diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs
index 4d367f4..e40782d 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs
@@ -60,6 +60,15 @@ namespace WelsonJS.Launcher.Properties {
}
}
+ ///
+ /// https://ajax.aspnetcdn.com/과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string AspNetCdnPrefix {
+ get {
+ return ResourceManager.GetString("AspNetCdnPrefix", resourceCulture);
+ }
+ }
+
///
/// 과(와) 유사한 지역화된 문자열을 찾습니다.
///
@@ -132,6 +141,24 @@ namespace WelsonJS.Launcher.Properties {
}
}
+ ///
+ /// https://esm.run/과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string EsmRunPrefix {
+ get {
+ return ResourceManager.GetString("EsmRunPrefix", resourceCulture);
+ }
+ }
+
+ ///
+ /// https://esm.sh/과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string EsmShPrefix {
+ get {
+ return ResourceManager.GetString("EsmShPrefix", resourceCulture);
+ }
+ }
+
///
/// (아이콘)과(와) 유사한 System.Drawing.Icon 형식의 지역화된 리소스를 찾습니다.
///
@@ -142,6 +169,15 @@ namespace WelsonJS.Launcher.Properties {
}
}
+ ///
+ /// https://ajax.googleapis.com/과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string GoogleApisPrefix {
+ get {
+ return ResourceManager.GetString("GoogleApisPrefix", resourceCulture);
+ }
+ }
+
///
/// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
///
@@ -232,6 +268,42 @@ namespace WelsonJS.Launcher.Properties {
}
}
+ ///
+ /// https://code.jquery.com/과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string JqueryCdnPrefix {
+ get {
+ return ResourceManager.GetString("JqueryCdnPrefix", resourceCulture);
+ }
+ }
+
+ ///
+ /// https://cdn.jsdelivr.net/과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string JsDeliverPrefix {
+ get {
+ return ResourceManager.GetString("JsDeliverPrefix", resourceCulture);
+ }
+ }
+
+ ///
+ /// https://polyfill-fastly.io/과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string PolyfillPrefix {
+ get {
+ return ResourceManager.GetString("PolyfillPrefix", resourceCulture);
+ }
+ }
+
+ ///
+ /// https://raw.githubusercontent.com/과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string RawGitHubPrefix {
+ get {
+ return ResourceManager.GetString("RawGitHubPrefix", resourceCulture);
+ }
+ }
+
///
/// https://github.com/gnh1201/welsonjs과(와) 유사한 지역화된 문자열을 찾습니다.
///
@@ -250,6 +322,24 @@ namespace WelsonJS.Launcher.Properties {
}
}
+ ///
+ /// https://www.skypack.dev/과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string SkypackPrefix {
+ get {
+ return ResourceManager.GetString("SkypackPrefix", resourceCulture);
+ }
+ }
+
+ ///
+ /// https://unpkg.com/과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string UnpkgPrefix {
+ get {
+ return ResourceManager.GetString("UnpkgPrefix", resourceCulture);
+ }
+ }
+
///
/// 141.101.82.1과(와) 유사한 지역화된 문자열을 찾습니다.
///
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx
index bf5af31..5e041d3 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx
@@ -187,4 +187,34 @@
https://cdnjs.cloudflare.com/
+
+ https://esm.run/
+
+
+ https://esm.sh/
+
+
+ https://code.jquery.com/
+
+
+ https://cdn.jsdelivr.net/
+
+
+ https://www.skypack.dev/
+
+
+ https://unpkg.com/
+
+
+ https://ajax.aspnetcdn.com/
+
+
+ https://ajax.googleapis.com/
+
+
+ https://polyfill-fastly.io/
+
+
+ https://raw.githubusercontent.com/
+
\ No newline at end of file
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
index cd21f07..caf1f72 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
@@ -1,12 +1,19 @@
-using System;
+// ResourceServer.cs
+// A resource server of WelsonJS Editor (WelsonJS.Launcher)
+// Namhyeon Go
+// https://github.com/gnh1201/welsonjs
+//
+using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
+using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
@@ -23,7 +30,25 @@ namespace WelsonJS.Launcher
private string _resourceName;
private List _tools = new List();
private readonly HttpClient _httpClient = new HttpClient();
- private readonly string _defaultMimeType = "application/octet-stream";
+ private static readonly string _defaultMimeType = "application/octet-stream";
+ private static readonly Regex _nodePackageRegex = new Regex(@"^[^/@]+@[^/]+/", RegexOptions.Compiled);
+ private static readonly List CDN_PREFIXES = new List {
+ new[] { "ajax/libs/" },
+ new[] { "npm/", "gh/", "wp/" },
+ new[] { "jquery/" },
+ new[] { "polyfill/" },
+ new[] { "ajax/" }, // https://learn.microsoft.com/en-us/aspnet/ajax/cdn/overview
+ new[] { "raw/gh/"}
+ };
+ private enum CDN_TYPES: int
+ {
+ Cloudflare = 0,
+ JsDeliver = 1,
+ Jquery = 2,
+ Polyfill = 3,
+ Microsoft = 4,
+ GitHub = 5
+ };
public ResourceServer(string prefix, string resourceName)
{
@@ -182,17 +207,55 @@ namespace WelsonJS.Launcher
}
}
- // use the cdn-js
- if (path.StartsWith("ajax/libs/"))
+ // use CDN sources
+ if (await TryServeFromCdn(context, path))
{
- if (await ServeBlob(context, path, Program.GetAppConfig("CdnJsPrefix"))) {
- return true;
- }
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private async Task TryServeFromCdn(HttpListenerContext context, string path)
+ {
+ bool isNodePackageExpression = _nodePackageRegex.IsMatch(path);
+ bool isPrefixMatched(CDN_TYPES type)
+ {
+ if (CDN_PREFIXES[(int)type].Any(prefix => path.StartsWith(prefix)))
+ {
+ return true;
}
- // use the blob stroage
- if (await ServeBlob(context, path, Program.GetAppConfig("BlobStoragePrefix"))) {
- return true;
+ return false;
+ }
+
+ var sources = new (bool isMatch, string configKey, Func transform)[]
+ {
+ (isPrefixMatched(CDN_TYPES.Cloudflare), "CdnJsPrefix", p => p), // Libraries from Cloudflare
+ (isPrefixMatched(CDN_TYPES.Cloudflare), "GoogleApisPrefix", p => p), // Libraries from Google
+ (isNodePackageExpression, "UnpkgPrefix", p => p),
+ (isNodePackageExpression, "SkypackPrefix", p => p),
+ (isNodePackageExpression, "EsmShPrefix", p => p),
+ (isNodePackageExpression, "EsmRunPrefix", p => p),
+ (isPrefixMatched(CDN_TYPES.JsDeliver), "JsDeliverPrefix", p => p),
+ (isPrefixMatched(CDN_TYPES.Jquery), "JqueryCdnPrefix", p => p.Substring("jquery/".Length)),
+ (isPrefixMatched(CDN_TYPES.Polyfill), "CdnJsPrefix", p => p), // polyfill.js from Cloudflare
+ (isPrefixMatched(CDN_TYPES.Polyfill), "PolyfillPrefix", p => p.Substring("polyfill/".Length)), // polyfill.js from Fastly
+ (isPrefixMatched(CDN_TYPES.Microsoft), "AspNetCdnPrefix", p => p), // Libraries from Microsoft
+ (isPrefixMatched(CDN_TYPES.GitHub), "RawGitHubPrefix", p => p.Substring("raw/gh/".Length)),
+ (true, "BlobStoragePrefix", p => p) // fallback
+ };
+
+ foreach (var (isMatch, configKey, transform) in sources)
+ {
+ if (isMatch)
+ {
+ string prefix = Program.GetAppConfig(configKey);
+ if (await ServeBlob(context, transform(path), prefix))
+ {
+ return true;
+ }
}
}
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/app.config b/WelsonJS.Toolkit/WelsonJS.Launcher/app.config
index 729e7ad..4bd67b0 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/app.config
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/app.config
@@ -14,6 +14,15 @@
+
+
+
+
+
+
+
+
+