diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs
index c9d723c..e7b3b1c 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs
@@ -70,11 +70,20 @@ namespace WelsonJS.Launcher.Properties {
}
///
- /// https://ai-catswords656881030318.services.ai.azure.com/models/chat/completions?api-version=2024-05-01-preview과(와) 유사한 지역화된 문자열을 찾습니다.
+ /// 2024-05-01-preview과(와) 유사한 지역화된 문자열을 찾습니다.
///
- internal static string AzureAiServiceUrl {
+ internal static string AzureAiServiceApiVersion {
get {
- return ResourceManager.GetString("AzureAiServiceUrl", resourceCulture);
+ return ResourceManager.GetString("AzureAiServiceApiVersion", resourceCulture);
+ }
+ }
+
+ ///
+ /// https://ai-catswords656881030318.services.ai.azure.com/과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string AzureAiServicePrefix {
+ get {
+ return ResourceManager.GetString("AzureAiServicePrefix", resourceCulture);
}
}
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx
index 311ac5c..5d55a0e 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx
@@ -163,8 +163,8 @@
-
- https://ai-catswords656881030318.services.ai.azure.com/models/chat/completions?api-version=2024-05-01-preview
+
+ https://ai-catswords656881030318.services.ai.azure.com/
1.1.1.1
@@ -181,4 +181,7 @@
https://catswords.blob.core.windows.net/welsonjs/
+
+ 2024-05-01-preview
+
\ No newline at end of file
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
index c218177..5568e3e 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
@@ -23,8 +23,8 @@ namespace WelsonJS.Launcher
private string _prefix;
private string _resourceName;
private List _tools = new List();
- private const int _blobTimeout = 5000;
- private readonly HttpClient _blobClient = new HttpClient();
+ private const int _httpClientTimeout = 5000;
+ private readonly HttpClient _httpClient = new HttpClient();
private readonly string _defaultMimeType = "application/octet-stream";
public ResourceServer(string prefix, string resourceName)
@@ -33,15 +33,15 @@ namespace WelsonJS.Launcher
_listener = new HttpListener();
_listener.Prefixes.Add(prefix);
_resourceName = resourceName;
- _blobClient.Timeout = TimeSpan.FromMilliseconds(_blobTimeout);
+ _httpClient.Timeout = TimeSpan.FromMilliseconds(_httpClientTimeout);
// Add resource tools
- _tools.Add(new ResourceTools.Completion(this));
- _tools.Add(new ResourceTools.Config(this));
- _tools.Add(new ResourceTools.DevTools(this));
- _tools.Add(new ResourceTools.DnsQuery(this));
- _tools.Add(new ResourceTools.Tfa(this));
- _tools.Add(new ResourceTools.Whois(this));
+ _tools.Add(new ResourceTools.Completion(this, _httpClient));
+ _tools.Add(new ResourceTools.Settings(this, _httpClient));
+ _tools.Add(new ResourceTools.DevTools(this, _httpClient));
+ _tools.Add(new ResourceTools.DnsQuery(this, _httpClient));
+ _tools.Add(new ResourceTools.Tfa(this, _httpClient));
+ _tools.Add(new ResourceTools.Whois(this, _httpClient));
}
public string GetPrefix()
@@ -158,7 +158,7 @@ namespace WelsonJS.Launcher
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.UserAgent.ParseAdd(context.Request.UserAgent);
- HttpResponseMessage response = await _blobClient.SendAsync(request);
+ HttpResponseMessage response = await _httpClient.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/AzureAi.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/AzureAi.cs
deleted file mode 100644
index 147e78a..0000000
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/AzureAi.cs
+++ /dev/null
@@ -1,139 +0,0 @@
-using System;
-using System.IO;
-using System.Net;
-using System.Net.Http;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace WelsonJS.Launcher.ResourceTools
-{
- public class AzureAi : IResourceTool
- {
- private ResourceServer Server;
- private const string Prefix = "azure-ai/";
- private const int ChunkSize = 4096;
- private readonly string AzureAiServiceUrl;
- private readonly string AzureAiServiceApiKey;
-
- public AzureAi(ResourceServer server)
- {
- Server = server;
-
- AzureAiServiceUrl = Program.GetAppConfig("AzureAiServiceUrl");
- AzureAiServiceApiKey = Program.GetAppConfig("AzureAiServiceApiKey");
- }
-
- public bool CanHandle(string path)
- {
- return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
- }
-
- public async Task HandleAsync(HttpListenerContext context, string path)
- {
- string apiKey = AzureAiServiceApiKey;
- if (string.IsNullOrEmpty(apiKey))
- {
- WriteError(context, "Missing the API key.", HttpStatusCode.BadRequest);
- return;
- }
-
- string requestBody = ReadRequestBody(context);
- bool isStreaming = ContainsSequentialKeywords(requestBody, new[] { "\"stream\"", "true" }, 30);
-
- try
- {
- using (var response = await SendAzureRequestAsync(apiKey, requestBody, isStreaming))
- {
- await ForwardResponseAsync(context, response, isStreaming);
- }
- }
- catch (HttpRequestException ex)
- {
- WriteError(context, "Request error: " + ex.Message, HttpStatusCode.BadGateway);
- }
- }
-
- private string ReadRequestBody(HttpListenerContext context)
- {
- using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
- {
- return reader.ReadToEnd();
- }
- }
-
- private async Task SendAzureRequestAsync(string apiKey, string requestBody, bool isStreaming)
- {
- using (var client = new HttpClient())
- {
- var requestMessage = new HttpRequestMessage(HttpMethod.Post, AzureAiServiceUrl);
- requestMessage.Headers.Add("api-key", apiKey);
- requestMessage.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
-
- var completionOption = isStreaming
- ? HttpCompletionOption.ResponseHeadersRead
- : HttpCompletionOption.ResponseContentRead;
-
- return await client.SendAsync(requestMessage, completionOption);
- }
- }
-
- private async Task ForwardResponseAsync(HttpListenerContext context, HttpResponseMessage response, bool isStreaming)
- {
- context.Response.StatusCode = (int)response.StatusCode;
- context.Response.ContentType = response.Content.Headers.ContentType?.ToString() ?? "application/json";
-
- using (var responseStream = await response.Content.ReadAsStreamAsync())
- {
- if (isStreaming)
- {
- context.Response.SendChunked = true;
- context.Response.Headers.Add("Transfer-Encoding", "chunked");
- context.Response.Headers.Add("Cache-Control", "no-cache");
-
- byte[] buffer = new byte[ChunkSize];
- int bytesRead;
- while ((bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
- {
- await context.Response.OutputStream.WriteAsync(buffer, 0, bytesRead);
- context.Response.OutputStream.Flush();
- }
- }
- else
- {
- await responseStream.CopyToAsync(context.Response.OutputStream);
- }
- }
- }
-
- private void WriteError(HttpListenerContext context, string message, HttpStatusCode statusCode)
- {
- context.Response.StatusCode = (int)statusCode;
- using (var writer = new StreamWriter(context.Response.OutputStream, Encoding.UTF8))
- {
- writer.Write(message);
- }
- }
-
- public static bool ContainsSequentialKeywords(string input, string[] keywords, int maxDistance)
- {
- if (input == null || keywords == null || keywords.Length < 2)
- return false;
-
- int position = 0;
-
- for (int i = 0; i < keywords.Length; i++)
- {
- int index = input.IndexOf(keywords[i], position, StringComparison.OrdinalIgnoreCase);
- if (index < 0)
- return false;
-
- if (i > 0 && (index - position) > maxDistance)
- return false;
-
- position = index + keywords[i].Length;
- }
-
- return true;
- }
- }
-}
\ No newline at end of file
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Completion.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Completion.cs
index d9d6d81..ad4488a 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Completion.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Completion.cs
@@ -8,18 +8,21 @@ using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;
+using System.Net.Http;
namespace WelsonJS.Launcher.ResourceTools
{
public class Completion : IResourceTool
{
- private ResourceServer Server;
+ private readonly ResourceServer Server;
+ private readonly HttpClient _httpClient;
private const string Prefix = "completion/";
private List Executables = new List();
- public Completion(ResourceServer server)
+ public Completion(ResourceServer server, HttpClient httpClient)
{
Server = server;
+ _httpClient = httpClient;
new Task(() =>
{
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Config.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Config.cs
deleted file mode 100644
index 6358766..0000000
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Config.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System;
-using System.Net;
-using System.Threading.Tasks;
-
-namespace WelsonJS.Launcher.ResourceTools
-{
- public class Config : IResourceTool
- {
- private ResourceServer Server;
- private const string Prefix = "config/";
-
- public Config(ResourceServer server)
- {
- Server = server;
- }
-
- public bool CanHandle(string path)
- {
- return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
- }
-
- public async Task HandleAsync(HttpListenerContext context, string path)
- {
- await Task.Delay(0);
-
- string configName = path.Substring(Prefix.Length);
-
- try
- {
- string configValue = Program.GetAppConfig(configName);
- Server.ServeResource(context, configValue, "text/plain");
- }
- catch (Exception ex)
- {
- Server.ServeResource(context, $"Failed to process Config request. {ex.Message}", "application/xml", 500);
- }
- }
- }
-}
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DevTools.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DevTools.cs
index 890e9fa..20d40c9 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DevTools.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DevTools.cs
@@ -8,12 +8,13 @@ namespace WelsonJS.Launcher.ResourceTools
public class DevTools : IResourceTool
{
private ResourceServer Server;
+ private readonly HttpClient _httpClient;
private const string Prefix = "devtools/";
- private const double Timeout = 5000;
- public DevTools(ResourceServer server)
+ public DevTools(ResourceServer server, HttpClient httpClient)
{
Server = server;
+ _httpClient = httpClient;
}
public bool CanHandle(string path)
@@ -27,15 +28,10 @@ namespace WelsonJS.Launcher.ResourceTools
try
{
- using (HttpClient client = new HttpClient())
- {
- client.Timeout = TimeSpan.FromMilliseconds(Timeout);
+ string url = Program.GetAppConfig("DevToolsPrefix") + endpoint;
+ string data = await _httpClient.GetStringAsync(url);
- string url = Program.GetAppConfig("DevToolsPrefix") + endpoint;
- string data = await client.GetStringAsync(url);
-
- Server.ServeResource(context, data, "application/json");
- }
+ Server.ServeResource(context, data, "application/json");
}
catch (Exception ex)
{
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DnsQuery.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DnsQuery.cs
index fa4ca2a..7403a63 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DnsQuery.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DnsQuery.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
+using System.Net.Http;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
@@ -10,16 +11,19 @@ namespace WelsonJS.Launcher.ResourceTools
{
public class DnsQuery : IResourceTool
{
- private ResourceServer Server;
+ private readonly ResourceServer Server;
+ private readonly HttpClient _httpClient;
private const string Prefix = "dns-query/";
private string DnsServer;
private const int DnsPort = 53;
private const int Timeout = 5000;
private static readonly Random _random = new Random();
- public DnsQuery(ResourceServer server)
+ public DnsQuery(ResourceServer server, HttpClient httpClient)
{
Server = server;
+ _httpClient = httpClient;
+
DnsServer = Program.GetAppConfig("DnsServerAddress");
}
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Settings.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Settings.cs
new file mode 100644
index 0000000..4886404
--- /dev/null
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Settings.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Reflection;
+using System.Resources;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+
+namespace WelsonJS.Launcher.ResourceTools
+{
+ public class Settings : IResourceTool
+ {
+ private readonly ResourceServer Server;
+ private readonly HttpClient _httpClient;
+ private const string Prefix = "settings";
+
+ public Settings(ResourceServer server, HttpClient httpClient)
+ {
+ Server = server;
+ _httpClient = httpClient;
+ }
+
+ public bool CanHandle(string path)
+ {
+ return path.Equals(Prefix, StringComparison.OrdinalIgnoreCase);
+ }
+
+ public async Task HandleAsync(HttpListenerContext context, string path)
+ {
+ await Task.Delay(0);
+
+ // Get current namespace (e.g., WelsonJS.Launcher)
+ string ns = typeof(Program).Namespace;
+
+ // Build resource base name (e.g., WelsonJS.Launcher.Properties.Resources)
+ string resourceBaseName = ns + ".Properties.Resources";
+
+ // Load resource strings using ResourceManager
+ var resourceManager = new ResourceManager(resourceBaseName, Assembly.GetExecutingAssembly());
+ var resourceSet = resourceManager.GetResourceSet(
+ System.Globalization.CultureInfo.CurrentCulture,
+ true,
+ true
+ );
+
+ var resourceStrings = new Dictionary();
+ foreach (System.Collections.DictionaryEntry entry in resourceSet)
+ {
+ string key = (string)entry.Key;
+ object value = entry.Value;
+
+ if (value is string strValue)
+ {
+ resourceStrings[key] = strValue;
+ }
+ }
+
+ // Load settings from app.config
+ var appConfig = ConfigurationManager.AppSettings.AllKeys
+ .ToDictionary(k => k, k => ConfigurationManager.AppSettings[k]);
+
+ // Merge keys from both sources (app.config has priority)
+ var allKeys = new HashSet(resourceStrings.Keys.Concat(appConfig.Keys));
+ var finalConfig = new Dictionary();
+
+ foreach (var key in allKeys)
+ {
+ if (appConfig.ContainsKey(key))
+ finalConfig[key] = appConfig[key];
+ else if (resourceStrings.ContainsKey(key))
+ finalConfig[key] = resourceStrings[key];
+ }
+
+ // Generate XML using XElement
+ XElement xml = new XElement("settings",
+ finalConfig.Select(kv => new XElement(kv.Key, kv.Value))
+ );
+
+ Server.ServeResource(context, xml.ToString(), "application/xml");
+ }
+ }
+}
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Tfa.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Tfa.cs
index 52de1d9..0685888 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Tfa.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Tfa.cs
@@ -4,18 +4,21 @@ using System.Security.Cryptography;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
+using System.Net.Http;
namespace WelsonJS.Launcher.ResourceTools
{
public class Tfa : IResourceTool
{
- private ResourceServer Server;
+ private readonly ResourceServer Server;
+ private readonly HttpClient _httpClient;
private const string Prefix = "tfa/";
private const string Base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
- public Tfa(ResourceServer server)
+ public Tfa(ResourceServer server, HttpClient httpClient)
{
Server = server;
+ _httpClient = httpClient;
}
public bool CanHandle(string path)
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Whois.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Whois.cs
index 7efe928..148da61 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Whois.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Whois.cs
@@ -8,13 +8,14 @@ namespace WelsonJS.Launcher.ResourceTools
{
public class Whois : IResourceTool
{
- private ResourceServer Server;
+ private readonly ResourceServer Server;
+ private readonly HttpClient _httpClient;
private const string Prefix = "whois/";
- private const int Timeout = 5000;
- public Whois(ResourceServer server)
+ public Whois(ResourceServer server, HttpClient httpClient)
{
Server = server;
+ _httpClient = httpClient;
}
public bool CanHandle(string path)
@@ -32,32 +33,27 @@ namespace WelsonJS.Launcher.ResourceTools
return;
}
- using (var client = new HttpClient())
+ string clientAddress = Program.GetAppConfig("WhoisClientAddress");
+
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, Program.GetAppConfig("WhoisServerUrl"))
{
- client.Timeout = TimeSpan.FromMilliseconds(Timeout);
+ Content = new StringContent($"query={Uri.EscapeDataString(query)}&ip={clientAddress}", Encoding.UTF8, "application/x-www-form-urlencoded")
+ };
- string clientAddress = Program.GetAppConfig("WhoisClientAddress");
+ request.Headers.Add("Accept", "*/*");
+ request.Headers.Add("User-Agent", context.Request.UserAgent);
+ _httpClient.DefaultRequestHeaders.Referrer = new Uri(Program.GetAppConfig("WhoisReferrerUrl"));
- HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, Program.GetAppConfig("WhoisServerUrl"))
- {
- Content = new StringContent($"query={Uri.EscapeDataString(query)}&ip={clientAddress}", Encoding.UTF8, "application/x-www-form-urlencoded")
- };
+ try
+ {
+ HttpResponseMessage response = await _httpClient.SendAsync(request);
+ string responseBody = await response.Content.ReadAsStringAsync();
- request.Headers.Add("Accept", "*/*");
- request.Headers.Add("User-Agent", context.Request.UserAgent);
- client.DefaultRequestHeaders.Referrer = new Uri(Program.GetAppConfig("WhoisReferrerUrl"));
-
- try
- {
- HttpResponseMessage response = await client.SendAsync(request);
- string responseBody = await response.Content.ReadAsStringAsync();
-
- Server.ServeResource(context, responseBody, "text/plain", (int)response.StatusCode);
- }
- catch (Exception ex)
- {
- Server.ServeResource(context, $"Failed to process WHOIS request. {ex.Message}", "application/xml", 500);
- }
+ Server.ServeResource(context, responseBody, "text/plain", (int)response.StatusCode);
+ }
+ catch (Exception ex)
+ {
+ Server.ServeResource(context, $"Failed to process WHOIS request. {ex.Message}", "application/xml", 500);
}
}
}
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/WelsonJS.Launcher.csproj b/WelsonJS.Toolkit/WelsonJS.Launcher/WelsonJS.Launcher.csproj
index 731acee..21be0a4 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/WelsonJS.Launcher.csproj
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/WelsonJS.Launcher.csproj
@@ -74,8 +74,7 @@
-
-
+
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/app.config b/WelsonJS.Toolkit/WelsonJS.Launcher/app.config
index 2e92fd9..063a683 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/app.config
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/app.config
@@ -5,8 +5,9 @@
-
+
+
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/editor.html b/WelsonJS.Toolkit/WelsonJS.Launcher/editor.html
index 3e49309..342d8c8 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/editor.html
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/editor.html
@@ -57,7 +57,19 @@
Copilot
- Generative
+
+
+
+ Generative AI