mirror of
https://github.com/gnh1201/welsonjs.git
synced 2026-04-18 18:18:42 +00:00
commit
93ec862f81
|
|
@ -0,0 +1,85 @@
|
|||
using log4net;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WelsonJS.Launcher.ApiEndpoints
|
||||
{
|
||||
public class JsonRpc2 : IApiEndpoint
|
||||
{
|
||||
private readonly ResourceServer Server;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ILog _logger;
|
||||
private const string Prefix = "jsonrpc2";
|
||||
|
||||
public JsonRpc2(ResourceServer server, HttpClient httpClient, ILog logger)
|
||||
{
|
||||
Server = server;
|
||||
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public bool CanHandle(HttpListenerContext context, string path)
|
||||
{
|
||||
if (context == null)
|
||||
return false;
|
||||
|
||||
if (!string.Equals(context.Request.HttpMethod, "POST", StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
|
||||
if (path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase) == false)
|
||||
return false;
|
||||
|
||||
string contentType = context.Request.ContentType?.ToLowerInvariant() ?? string.Empty;
|
||||
if (!(contentType.StartsWith("application/json")
|
||||
|| contentType.StartsWith("application/json-rpc")
|
||||
|| contentType.StartsWith("application/jsonrpc")
|
||||
|| contentType.StartsWith("text/json")))
|
||||
return false;
|
||||
|
||||
if (!context.Request.HasEntityBody)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task HandleAsync(HttpListenerContext context, string path)
|
||||
{
|
||||
string body;
|
||||
try
|
||||
{
|
||||
using (var input = context.Request.InputStream)
|
||||
using (var reader = new System.IO.StreamReader(input, System.Text.Encoding.UTF8))
|
||||
{
|
||||
body = await reader.ReadToEndAsync();
|
||||
}
|
||||
|
||||
_logger.Debug($"[JsonRpc2] Request body received ({body.Length} bytes)");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error("[JsonRpc2] Failed to read request body", ex);
|
||||
|
||||
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||
context.Response.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
var dispatcher = new JsonRpc2Dispatcher(_logger);
|
||||
|
||||
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(300)))
|
||||
{
|
||||
await dispatcher.HandleAsync(
|
||||
body,
|
||||
async (method, ser, id, ct) =>
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
},
|
||||
cts.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,9 @@
|
|||
using System;
|
||||
// JsNative.cs
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2025 Catswords OSS and WelsonJS Contributors
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ namespace WelsonJS.Launcher
|
|||
// Create slot and parse
|
||||
// Using Object.create(null) for a clean dictionary without prototype.
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("(function(){var S=globalThis.__WJ_STORE;");
|
||||
sb.Append("(function(){var S=globalThis.__WJS__;");
|
||||
sb.Append("S[").Append(id.ToString(CultureInfo.InvariantCulture)).Append("]=JSON.parse(").Append(Q(json)).Append(");");
|
||||
sb.Append("return '1';})()");
|
||||
string r = _core.EvaluateToString(sb.ToString());
|
||||
|
|
@ -59,7 +59,7 @@ namespace WelsonJS.Launcher
|
|||
public void Unload(int id)
|
||||
{
|
||||
EnsureStore();
|
||||
string script = "(function(){var S=globalThis.__WJ_STORE; delete S[" + id.ToString(CultureInfo.InvariantCulture) + "]; return '1';})()";
|
||||
string script = "(function(){var S=globalThis.__WJS__; delete S[" + id.ToString(CultureInfo.InvariantCulture) + "]; return '1';})()";
|
||||
_core.EvaluateToString(script);
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ namespace WelsonJS.Launcher
|
|||
{
|
||||
if (json == null) throw new ArgumentNullException("json");
|
||||
EnsureStore();
|
||||
string script = "(function(){var S=globalThis.__WJ_STORE; S[" + id.ToString(CultureInfo.InvariantCulture) + "]=JSON.parse(" + Q(json) + "); return '1';})()";
|
||||
string script = "(function(){var S=globalThis.__WJS__; S[" + id.ToString(CultureInfo.InvariantCulture) + "]=JSON.parse(" + Q(json) + "); return '1';})()";
|
||||
_core.EvaluateToString(script);
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ namespace WelsonJS.Launcher
|
|||
{
|
||||
EnsureStore();
|
||||
space = Clamp(space, 0, 10);
|
||||
string script = "(function(){var v=globalThis.__WJ_STORE[" + id.ToString(CultureInfo.InvariantCulture) + "]; return JSON.stringify(v,null," + space.ToString(CultureInfo.InvariantCulture) + ");})()";
|
||||
string script = "(function(){var v=globalThis.__WJS__[" + id.ToString(CultureInfo.InvariantCulture) + "]; return JSON.stringify(v,null," + space.ToString(CultureInfo.InvariantCulture) + ");})()";
|
||||
return _core.EvaluateToString(script);
|
||||
}
|
||||
|
||||
|
|
@ -96,13 +96,13 @@ namespace WelsonJS.Launcher
|
|||
string jsPath = BuildJsPath(path);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("(function(){var v=globalThis.__WJ_STORE[")
|
||||
sb.Append("(function(){var v=globalThis.__WJS__[")
|
||||
.Append(id.ToString(CultureInfo.InvariantCulture))
|
||||
.Append("];var p=").Append(jsPath).Append(";");
|
||||
sb.Append("for(var i=0;i<p.length;i++){var k=p[i];");
|
||||
sb.Append("if(Array.isArray(v) && typeof k==='number'){ v=v[k]; }");
|
||||
sb.Append("else { v=(v==null?null:v[k]); }}");
|
||||
sb.Append("return JSON.stringify(v);})()");
|
||||
sb.Append("return (typeof v==='object'?JSON.stringify(v):String(v));})()");
|
||||
return _core.EvaluateToString(sb.ToString());
|
||||
}
|
||||
|
||||
|
|
@ -110,11 +110,11 @@ namespace WelsonJS.Launcher
|
|||
private void EnsureStore()
|
||||
{
|
||||
if (_storeReady) return;
|
||||
// Create a single global dictionary: globalThis.__WJ_STORE
|
||||
// Create a single global dictionary: globalThis.__WJS__
|
||||
// Object.create(null) prevents prototype pollution and accidental hits on built-ins.
|
||||
string script =
|
||||
"(function(){var g=globalThis||this;" +
|
||||
"if(!g.__WJ_STORE){Object.defineProperty(g,'__WJ_STORE',{value:Object.create(null),writable:false,enumerable:false,configurable:false});}" +
|
||||
"if(!g.__WJS__){Object.defineProperty(g,'__WJS__',{value:Object.create(null),writable:false,enumerable:false,configurable:false});}" +
|
||||
"return '1';})()";
|
||||
string r = _core.EvaluateToString(script);
|
||||
_storeReady = (r == "1");
|
||||
|
|
|
|||
85
WelsonJS.Augmented/WelsonJS.Launcher/JsonRpc2Dispatcher.cs
Normal file
85
WelsonJS.Augmented/WelsonJS.Launcher/JsonRpc2Dispatcher.cs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
// JsonRpc2Dispatcher.cs
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2025 Catswords OSS and WelsonJS Contributors
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
using log4net;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
public sealed class JsonRpc2Request
|
||||
{
|
||||
public string Version;
|
||||
public string Method;
|
||||
}
|
||||
|
||||
public sealed class JsonRpc2Exception : Exception
|
||||
{
|
||||
public JsonRpc2Exception(string message) : base(message) { }
|
||||
public JsonRpc2Exception(string message, Exception inner) : base(message, inner) { }
|
||||
}
|
||||
|
||||
public sealed class JsonRpc2Dispatcher
|
||||
{
|
||||
private readonly ILog _logger;
|
||||
|
||||
public JsonRpc2Dispatcher(ILog logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<string> HandleAsync(
|
||||
string requestBody,
|
||||
Func<string, JsSerializer, int, CancellationToken, Task<string>> dispatchMethodAsync,
|
||||
CancellationToken ct)
|
||||
{
|
||||
if (string.IsNullOrEmpty(requestBody))
|
||||
throw new JsonRpc2Exception("Empty request body");
|
||||
|
||||
if (dispatchMethodAsync == null)
|
||||
throw new ArgumentNullException("dispatchMethodAsync");
|
||||
|
||||
using (var ser = new JsSerializer())
|
||||
{
|
||||
int id = ser.Load(requestBody);
|
||||
|
||||
try
|
||||
{
|
||||
string version = ser.ExtractFrom(id, "jsonrpc");
|
||||
if (!string.Equals(version, "2.0", StringComparison.Ordinal))
|
||||
throw new JsonRpc2Exception("Unsupported JSON-RPC version: " + version);
|
||||
|
||||
string method = ser.ExtractFrom(id, "method");
|
||||
if (string.IsNullOrEmpty(method))
|
||||
throw new JsonRpc2Exception("Missing method");
|
||||
|
||||
var req = new JsonRpc2Request
|
||||
{
|
||||
Version = version,
|
||||
Method = method
|
||||
};
|
||||
|
||||
return await dispatchMethodAsync(req.Method, ser, id, ct);
|
||||
}
|
||||
catch (JsonRpc2Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (_logger != null)
|
||||
_logger.Error("[JsonRpc2] Parse error", ex);
|
||||
|
||||
throw new JsonRpc2Exception("Parse error", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ser.Unload(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,8 +11,12 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
|
|
@ -49,7 +53,8 @@ namespace WelsonJS.Launcher
|
|||
string targetFilePath = GetTargetFilePath(args);
|
||||
if (!string.IsNullOrEmpty(targetFilePath))
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
HandleTargetFilePath(targetFilePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
@ -59,6 +64,14 @@ namespace WelsonJS.Launcher
|
|||
return;
|
||||
}
|
||||
|
||||
// if use the stdio-jsonrpc2 forwarder
|
||||
if (HasArg(args, "--stdio-jsonrpc2"))
|
||||
{
|
||||
_logger.Info("Starting in the stdio-jsonrpc2 forwarder...");
|
||||
ProcessStdioJsonRpc2().GetAwaiter().GetResult();
|
||||
return;
|
||||
}
|
||||
|
||||
// create the mutex
|
||||
_mutex = new Mutex(true, "WelsonJS.Launcher", out bool createdNew);
|
||||
if (!createdNew)
|
||||
|
|
@ -81,6 +94,135 @@ namespace WelsonJS.Launcher
|
|||
_mutex.Dispose();
|
||||
}
|
||||
|
||||
private static bool HasArg(string[] args, string key)
|
||||
{
|
||||
if (args == null)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
if (string.Equals(args[i], key, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async static Task ProcessStdioJsonRpc2()
|
||||
{
|
||||
string serverPrefix = GetAppConfig("ResourceServerPrefix");
|
||||
string endpoint = $"{serverPrefix}jsonrpc2";
|
||||
int timeout = int.TryParse(GetAppConfig("HttpClientTimeout"), out timeout) ? timeout : 300;
|
||||
|
||||
var http = new HttpClient
|
||||
{
|
||||
Timeout = TimeSpan.FromSeconds(timeout)
|
||||
};
|
||||
|
||||
using (var stdin = Console.OpenStandardInput())
|
||||
using (var stdout = Console.OpenStandardOutput())
|
||||
{
|
||||
var buffer = new byte[8192];
|
||||
|
||||
while (true)
|
||||
{
|
||||
int read;
|
||||
try
|
||||
{
|
||||
read = await stdin.ReadAsync(buffer, 0, buffer.Length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error("[stdio] stdin read failed", ex);
|
||||
break;
|
||||
}
|
||||
|
||||
if (read <= 0)
|
||||
{
|
||||
_logger.Info("[stdio] EOF received, exiting loop");
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] payload = new byte[read];
|
||||
Buffer.BlockCopy(buffer, 0, payload, 0, read);
|
||||
|
||||
_logger.Debug($"[stdio] recv {payload.Length} bytes");
|
||||
_logger.Debug($"[stdio] payload preview: {SafePreviewUtf8(payload, 512)}");
|
||||
|
||||
try
|
||||
{
|
||||
using (var content = new ByteArrayContent(payload))
|
||||
{
|
||||
// Content-Type: application/json
|
||||
content.Headers.ContentType =
|
||||
new MediaTypeHeaderValue("application/json")
|
||||
{
|
||||
CharSet = "utf-8"
|
||||
};
|
||||
|
||||
_logger.Debug($"[http] POST {endpoint}");
|
||||
|
||||
using (var response = await http.PostAsync(endpoint, content))
|
||||
{
|
||||
_logger.Info(
|
||||
$"[http] status={(int)response.StatusCode} {response.ReasonPhrase}");
|
||||
|
||||
foreach (var h in response.Headers)
|
||||
_logger.Debug($"[http] H {h.Key}: {string.Join(", ", h.Value)}");
|
||||
|
||||
foreach (var h in response.Content.Headers)
|
||||
_logger.Debug($"[http] HC {h.Key}: {string.Join(", ", h.Value)}");
|
||||
|
||||
byte[] responseBytes =
|
||||
await response.Content.ReadAsByteArrayAsync();
|
||||
|
||||
_logger.Debug($"[http] body {responseBytes.Length} bytes");
|
||||
|
||||
_logger.Debug(
|
||||
$"[http] body preview: {SafePreviewUtf8(responseBytes, 2048)}");
|
||||
|
||||
await stdout.WriteAsync(responseBytes, 0, responseBytes.Length);
|
||||
await stdout.FlushAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (TaskCanceledException ex)
|
||||
{
|
||||
_logger.Error("[http] request timed out or canceled", ex);
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
_logger.Error("[http] request failed", ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error("[http] unexpected error", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string SafePreviewUtf8(byte[] bytes, int maxBytes)
|
||||
{
|
||||
if (bytes == null || bytes.Length == 0)
|
||||
return "(empty)";
|
||||
|
||||
try
|
||||
{
|
||||
int len = Math.Min(bytes.Length, maxBytes);
|
||||
string s = Encoding.UTF8.GetString(bytes, 0, len);
|
||||
|
||||
s = s.Replace("\r", "\\r").Replace("\n", "\\n");
|
||||
|
||||
if (bytes.Length > maxBytes)
|
||||
s += $"...(truncated, total {bytes.Length} bytes)";
|
||||
|
||||
return s;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "(binary / non-utf8 response)";
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitializeAssemblyLoader()
|
||||
{
|
||||
byte[] gzBytes = Properties.Resources.Phantomizer;
|
||||
|
|
@ -182,7 +324,8 @@ namespace WelsonJS.Launcher
|
|||
|
||||
private static string GetTargetFilePath(string[] args)
|
||||
{
|
||||
if (args == null || args.Length == 0) return null;
|
||||
if (args == null || args.Length == 0)
|
||||
return null;
|
||||
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
|
|
@ -498,7 +641,7 @@ namespace WelsonJS.Launcher
|
|||
|
||||
public static void InitializeResourceServer()
|
||||
{
|
||||
lock(typeof(Program))
|
||||
lock (typeof(Program))
|
||||
{
|
||||
if (_resourceServer == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace WelsonJS.Launcher.Properties {
|
|||
// 클래스에서 자동으로 생성되었습니다.
|
||||
// 멤버를 추가하거나 제거하려면 .ResX 파일을 편집한 다음 /str 옵션을 사용하여 ResGen을
|
||||
// 다시 실행하거나 VS 프로젝트를 다시 빌드하십시오.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
|
@ -81,27 +81,27 @@ namespace WelsonJS.Launcher.Properties {
|
|||
/// <summary>
|
||||
/// 과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string AzureAiServiceApiKey {
|
||||
internal static string AzureCognitiveApiKey {
|
||||
get {
|
||||
return ResourceManager.GetString("AzureAiServiceApiKey", resourceCulture);
|
||||
return ResourceManager.GetString("AzureCognitiveApiKey", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 2024-05-01-preview과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string AzureAiServiceApiVersion {
|
||||
internal static string AzureCognitiveApiVersion {
|
||||
get {
|
||||
return ResourceManager.GetString("AzureAiServiceApiVersion", resourceCulture);
|
||||
return ResourceManager.GetString("AzureCognitiveApiVersion", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://ai-catswords656881030318.services.ai.azure.com/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// https://catswords-ai-resource.services.ai.azure.com/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string AzureAiServicePrefix {
|
||||
internal static string AzureCognitivePrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("AzureAiServicePrefix", resourceCulture);
|
||||
return ResourceManager.GetString("AzureCognitivePrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +197,7 @@ namespace WelsonJS.Launcher.Properties {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 90과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// 300과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string HttpClientTimeout {
|
||||
get {
|
||||
|
|
@ -407,7 +407,7 @@ namespace WelsonJS.Launcher.Properties {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 141.101.82.1과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// 49.8.14.101과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string WhoisClientAddress {
|
||||
get {
|
||||
|
|
@ -416,7 +416,7 @@ namespace WelsonJS.Launcher.Properties {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// https://whois.kr/kor/whois/whois.jsp과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string WhoisReferrerUrl {
|
||||
get {
|
||||
|
|
@ -425,7 +425,7 @@ namespace WelsonJS.Launcher.Properties {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// https://whois.kr/kor/whois.jsc과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string WhoisServerUrl {
|
||||
get {
|
||||
|
|
|
|||
|
|
@ -160,35 +160,35 @@
|
|||
<data name="ChromiumDevToolsPrefix" xml:space="preserve">
|
||||
<value>http://localhost:9222/</value>
|
||||
</data>
|
||||
<data name="AzureAiServiceApiKey" xml:space="preserve">
|
||||
<data name="AzureCognitiveApiKey" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="AzureAiServicePrefix" xml:space="preserve">
|
||||
<value>https://ai-catswords656881030318.services.ai.azure.com/</value>
|
||||
<data name="AzureCognitivePrefix" xml:space="preserve">
|
||||
<value>https://catswords-ai-resource.services.ai.azure.com/</value>
|
||||
</data>
|
||||
<data name="DnsServerAddress" xml:space="preserve">
|
||||
<value>1.1.1.1</value>
|
||||
</data>
|
||||
<data name="WhoisClientAddress" xml:space="preserve">
|
||||
<value>141.101.82.1</value>
|
||||
<value>49.8.14.101</value>
|
||||
</data>
|
||||
<data name="WhoisReferrerUrl" xml:space="preserve">
|
||||
<value>https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp</value>
|
||||
<value>https://whois.kr/kor/whois/whois.jsp</value>
|
||||
</data>
|
||||
<data name="WhoisServerUrl" xml:space="preserve">
|
||||
<value>https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc</value>
|
||||
<value>https://whois.kr/kor/whois.jsc</value>
|
||||
</data>
|
||||
<data name="BlobStoragePrefix" xml:space="preserve">
|
||||
<value>https://catswords.blob.core.windows.net/welsonjs/</value>
|
||||
</data>
|
||||
<data name="AzureAiServiceApiVersion" xml:space="preserve">
|
||||
<data name="AzureCognitiveApiVersion" xml:space="preserve">
|
||||
<value>2024-05-01-preview</value>
|
||||
</data>
|
||||
<data name="BlobConfigUrl" xml:space="preserve">
|
||||
<value>https://catswords.blob.core.windows.net/welsonjs/blob.config.xml</value>
|
||||
</data>
|
||||
<data name="HttpClientTimeout" xml:space="preserve">
|
||||
<value>90</value>
|
||||
<value>300</value>
|
||||
</data>
|
||||
<data name="IpQueryApiKey" xml:space="preserve">
|
||||
<value />
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@
|
|||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
using log4net;
|
||||
using log4net.Core;
|
||||
using Microsoft.Isam.Esent.Interop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
|
@ -75,6 +73,7 @@ namespace WelsonJS.Launcher
|
|||
_apis.Add(new ApiEndpoints.TwoFactorAuth(this, _httpClient, _logger));
|
||||
_apis.Add(new ApiEndpoints.Whois(this, _httpClient, _logger));
|
||||
_apis.Add(new ApiEndpoints.ImageColorPicker(this, _httpClient, _logger));
|
||||
_apis.Add(new ApiEndpoints.JsonRpc2(this, _httpClient, _logger));
|
||||
|
||||
// Register the prefix
|
||||
_listener.Prefixes.Add(prefix);
|
||||
|
|
@ -164,8 +163,8 @@ namespace WelsonJS.Launcher
|
|||
// Serve from the blob server
|
||||
if (await ServeBlob(context, path)) return;
|
||||
|
||||
// Fallback to serve from a resource name
|
||||
await ServeResource(context, GetResource(_resourceName), "text/html");
|
||||
// Fallback to 404 (Not Found)
|
||||
await ServeResource(context);
|
||||
}
|
||||
|
||||
private async Task<bool> ServeBlob(HttpListenerContext context, string path, string prefix = null)
|
||||
|
|
@ -398,7 +397,7 @@ namespace WelsonJS.Launcher
|
|||
await ServeResource(context, Encoding.UTF8.GetBytes(data), mimeType, statusCode);
|
||||
}
|
||||
|
||||
private byte[] GetResource(string resourceName)
|
||||
public static byte[] GetResource(string resourceName)
|
||||
{
|
||||
// Try to fetch embedded resource.
|
||||
byte[] data = GetEmbeddedResource(typeof(Program).Namespace + "." + resourceName);
|
||||
|
|
@ -408,7 +407,7 @@ namespace WelsonJS.Launcher
|
|||
return GetResourceFromManager(resourceName);
|
||||
}
|
||||
|
||||
private byte[] GetEmbeddedResource(string fullResourceName)
|
||||
private static byte[] GetEmbeddedResource(string fullResourceName)
|
||||
{
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
using (Stream stream = assembly.GetManifestResourceStream(fullResourceName))
|
||||
|
|
@ -425,7 +424,7 @@ namespace WelsonJS.Launcher
|
|||
return null;
|
||||
}
|
||||
|
||||
private byte[] GetResourceFromManager(string resourceName)
|
||||
private static byte[] GetResourceFromManager(string resourceName)
|
||||
{
|
||||
object resourceObject = Properties.Resources.ResourceManager.GetObject(resourceName);
|
||||
switch (resourceObject)
|
||||
|
|
@ -439,7 +438,7 @@ namespace WelsonJS.Launcher
|
|||
}
|
||||
}
|
||||
|
||||
private byte[] ConvertIconToBytes(System.Drawing.Icon icon)
|
||||
private static byte[] ConvertIconToBytes(System.Drawing.Icon icon)
|
||||
{
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -91,9 +91,11 @@
|
|||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ApiEndpoints\JsonRpc2.cs" />
|
||||
<Compile Include="IApiEndpoint.cs" />
|
||||
<Compile Include="JsCore.cs" />
|
||||
<Compile Include="JsNative.cs" />
|
||||
<Compile Include="JsonRpc2Dispatcher.cs" />
|
||||
<Compile Include="JsSerializer.cs" />
|
||||
<Compile Include="ApiEndpoints\ImageColorPicker.cs" />
|
||||
<Compile Include="ApiEndpoints\IpQuery.cs" />
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@
|
|||
<add key="ChromiumDevToolsTimeout" value="5"/>
|
||||
<add key="ChromiumExecutablePath" value="msedge.exe"/>
|
||||
<add key="ChromiumAppMode" value="true"/>
|
||||
<add key="AzureAiServicePrefix" value="https://ai-catswords656881030318.services.ai.azure.com/"/>
|
||||
<add key="AzureAiServiceApiKey" value=""/>
|
||||
<add key="AzureAiServiceApiVersion" value="2024-05-01-preview"/>
|
||||
<add key="WhoisServerUrl" value="https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc"/>
|
||||
<add key="WhoisReferrerUrl" value="https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp"/>
|
||||
<add key="WhoisClientAddress" value="141.101.82.1"/>
|
||||
<add key="AzureCognitivePrefix" value="https://ai-catswords656881030318.services.ai.azure.com/"/>
|
||||
<add key="AzureCognitiveApiKey" value=""/>
|
||||
<add key="AzureCognitiveApiVersion" value="2024-05-01-preview"/>
|
||||
<add key="WhoisServerUrl" value="https://whois.kr/kor/whois.jsc"/>
|
||||
<add key="WhoisReferrerUrl" value="https://whois.kr/kor/whois/whois.jsp"/>
|
||||
<add key="WhoisClientAddress" value="49.8.14.101"/>
|
||||
<add key="DnsServerAddress" value="1.1.1.1"/>
|
||||
<add key="BlobStoragePrefix" value="https://catswords.blob.core.windows.net/welsonjs/"/>
|
||||
<add key="BlobConfigUrl" value="https://catswords.blob.core.windows.net/welsonjs/blob.config.xml"/>
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@
|
|||
flex: 3;
|
||||
}
|
||||
|
||||
#mapView {
|
||||
flex: 3;
|
||||
}
|
||||
|
||||
#promptEditor {
|
||||
flex: 1;
|
||||
}
|
||||
|
|
@ -60,6 +64,7 @@
|
|||
}
|
||||
};
|
||||
</script>
|
||||
<script src="http://localhost:3000/ajax/libs/leaflet/1.9.4/leaflet.min.js" integrity="sha384-NElt3Op+9NBMCYaef5HxeJmU4Xeard/Lku8ek6hoPTvYkQPh3zLIrJP7KiRocsxO" crossorigin="anonymous"></script>
|
||||
<script src="http://localhost:3000/ajax/libs/lodash/4.17.21/lodash.min.js" integrity="sha384-H6KKS1H1WwuERMSm+54dYLzjg0fKqRK5ZRyASdbrI/lwrCc6bXEmtGYr5SwvP1pZ" crossorigin="anonymous"></script>
|
||||
<script src="http://localhost:3000/ajax/libs/jsoneditor/10.1.3/jsoneditor.min.js" integrity="sha384-NdVVc20Tze856ZAWEoJNCk0mL4zJrGztRwULc5Hz25HUXQQgYtmjFtgVAxR4p5dD" crossorigin="anonymous"></script>
|
||||
<script src="http://localhost:3000/ajax/libs/react/18.3.1/umd/react.production.min.js" integrity="sha384-DGyLxAyjq0f9SPpVevD6IgztCFlnMF6oW/XQGmfe+IsZ8TqEiDrcHkMLKI6fiB/Z" crossorigin="anonymous"></script>
|
||||
|
|
@ -103,7 +108,8 @@
|
|||
loadResource("http://localhost:3000/ajax/libs/metroui/dev/lib/metro.css", "text/css", "sha384-4XgOiXH2ZMaWt5s5B35yKi7EAOabhZvx7wO8Jr71q2vZ+uONdRza/6CsK2kpyocd"),
|
||||
loadResource("http://localhost:3000/ajax/libs/metroui/dev/lib/icons.css", "text/css", "sha384-FuLND994etg+RtnpPSPMyNBvL+fEz+xGhbN61WUWuDEeZ+wJzcQ8SGqAMuI5hWrt"),
|
||||
loadResource("http://localhost:3000/ajax/libs/monaco-editor/0.52.2/min/vs/editor/editor.main.css", "text/css", "sha384-06yHXpYRlHEPaR4AS0fB/W+lMN09Zh5e1XMtfkNQdHV38OlhfkOEW5M+pCj3QskC"),
|
||||
loadResource("http://localhost:3000/ajax/libs/jsoneditor/10.1.3/jsoneditor.min.css", "text/css", "sha384-cj1rYBc4/dVYAknZMTkVCDRL6Knzugf32igVqsuFW0iRWFHKH8Ci8+ekC8gNsFZ+")
|
||||
loadResource("http://localhost:3000/ajax/libs/jsoneditor/10.1.3/jsoneditor.min.css", "text/css", "sha384-cj1rYBc4/dVYAknZMTkVCDRL6Knzugf32igVqsuFW0iRWFHKH8Ci8+ekC8gNsFZ+"),
|
||||
loadResource("http://localhost:3000/ajax/libs/leaflet/1.9.4/leaflet.min.css", "text/css", "sha384-c6Rcwz4e4CITMbu/NBmnNS8yN2sC3cUElMEMfP3vqqKFp7GOYaaBBCqmaWBjmkjb")
|
||||
]).then(() => {
|
||||
const _e = React.createElement;
|
||||
|
||||
|
|
@ -128,9 +134,9 @@
|
|||
}
|
||||
|
||||
function RibbonMenu({
|
||||
onOpenFileClick, onSaveFileClick, onCopliotClick, onAzureAiClick,
|
||||
onOpenFileClick, onSaveFileClick, onCopliotClick, onAzureCognitiveClick,
|
||||
onSavePromptClick, onLoadPromptClick, onQueryWhoisClick, onQueryDnsClick,
|
||||
onQueryIpClick
|
||||
onQueryIpClick, onMapClick
|
||||
}) {
|
||||
const fileButtons = [
|
||||
{
|
||||
|
|
@ -147,9 +153,9 @@
|
|||
}
|
||||
];
|
||||
|
||||
const aiButtons = [
|
||||
const cognitiveToolsButtons = [
|
||||
{ id: 'btnCopilot', icon: 'mif-rocket', caption: 'Copilot', onClick: onCopliotClick },
|
||||
{ id: 'btnAzureAi', icon: 'mif-rocket', caption: 'Azure AI', onClick: onAzureAiClick },
|
||||
{ id: 'btnAzureCognitive', icon: 'mif-rocket', caption: 'Azure', onClick: onAzureCognitiveClick },
|
||||
{ id: 'btnSavePrompt', icon: 'mif-floppy-disks', caption: 'Save', onClick: onSavePromptClick },
|
||||
{ id: 'btnLoadPrompt', icon: 'mif-file-upload', caption: 'Load', onClick: onLoadPromptClick }
|
||||
];
|
||||
|
|
@ -157,7 +163,8 @@
|
|||
const networkToolsButtons = [
|
||||
{ id: 'btnWhois', icon: 'mif-earth', caption: 'Whois', onClick: onQueryWhoisClick },
|
||||
{ id: 'btnQueryDns', icon: 'mif-earth', caption: 'DNS', onClick: onQueryDnsClick },
|
||||
{ id: 'btnQueryIp', icon: 'mif-user-secret', caption: 'IP', onClick: onQueryIpClick }
|
||||
{ id: 'btnQueryIp', icon: 'mif-user-secret', caption: 'IP', onClick: onQueryIpClick },
|
||||
{ id: 'btnMap', icon: 'mif-rocket', caption: 'Map', onClick: onMapClick }
|
||||
];
|
||||
|
||||
return _e(
|
||||
|
|
@ -170,14 +177,14 @@
|
|||
_e('div', { className: 'content-holder' },
|
||||
_e('div', { className: 'section active', id: 'editor-tab' },
|
||||
_e(Group, { title: 'File', buttons: fileButtons }),
|
||||
_e(Group, { title: 'Generative AI', buttons: aiButtons }),
|
||||
_e(Group, { title: 'Network tools', buttons: networkToolsButtons })
|
||||
_e(Group, { title: 'Cognitive Tools (AI)', buttons: cognitiveToolsButtons }),
|
||||
_e(Group, { title: 'Network Tools', buttons: networkToolsButtons })
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function Editor({ editorRef }) {
|
||||
function Editor({ editorRef, visible }) {
|
||||
const containerRef = React.useRef(null);
|
||||
|
||||
const getSuggestions = (word, range) => axios.get(`/completion/${encodeURIComponent(word)}`)
|
||||
|
|
@ -233,6 +240,11 @@
|
|||
});
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
// toggle the display style attribute
|
||||
containerRef.current.style.display = (visible ? "" : "none");
|
||||
}, [visible]);
|
||||
|
||||
return _e('div', { id: 'editor', ref: containerRef });
|
||||
}
|
||||
|
||||
|
|
@ -282,12 +294,103 @@
|
|||
return _e('div', { id: 'promptEditor', ref: containerRef });
|
||||
}
|
||||
|
||||
function useLocationMarker(mapViewRef) {
|
||||
const markerRef = React.useRef(null);
|
||||
|
||||
const mark = React.useCallback((lat, lng, description) => {
|
||||
const map = mapViewRef.current;
|
||||
if (!map) return;
|
||||
|
||||
const latlng = L.latLng(lat, lng);
|
||||
|
||||
if (!markerRef.current) {
|
||||
markerRef.current = L.marker(latlng).addTo(map)
|
||||
.bindPopup(description || "(no description)")
|
||||
.openPopup();
|
||||
} else {
|
||||
markerRef.current.setLatLng(latlng);
|
||||
}
|
||||
}, [mapViewRef]);
|
||||
|
||||
return { mark, markerRef };
|
||||
}
|
||||
|
||||
function MapView({ mapViewRef, visible }) {
|
||||
const containerRef = React.useRef(null);
|
||||
|
||||
const { mark } = useLocationMarker(mapViewRef);
|
||||
|
||||
// init once
|
||||
React.useEffect(() => {
|
||||
if (!containerRef.current)
|
||||
return;
|
||||
|
||||
if (typeof L === "undefined" || !L || !L.map) {
|
||||
console.error("[MapView] Leaflet (L) is not loaded.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mapViewRef && mapViewRef.current && mapViewRef.current._leaflet_id)
|
||||
return;
|
||||
|
||||
const map = L.map(containerRef.current, {
|
||||
zoomControl: true,
|
||||
attributionControl: true
|
||||
}).setView([37.5665, 126.9780], 12);
|
||||
|
||||
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||
maxZoom: 19,
|
||||
attribution: '© OpenStreetMap contributors'
|
||||
}).addTo(map);
|
||||
|
||||
if (mapViewRef)
|
||||
mapViewRef.current = map;
|
||||
|
||||
return function () {
|
||||
try {
|
||||
if (mapViewRef && mapViewRef.current === map)
|
||||
mapViewRef.current = null;
|
||||
|
||||
map.remove();
|
||||
} catch (e) {}
|
||||
};
|
||||
}, []);
|
||||
|
||||
// handle show/hide toggles
|
||||
React.useEffect(() => {
|
||||
// when becoming visible, leaflet needs a resize recalculation
|
||||
const map = mapViewRef ? mapViewRef.current : null;
|
||||
if (!map || !map.invalidateSize)
|
||||
return;
|
||||
|
||||
// toggle the display style attribute
|
||||
containerRef.current.style.display = (visible ? "block" : "none");
|
||||
|
||||
// defer until after layout/display change
|
||||
if (visible) {
|
||||
setTimeout(function () {
|
||||
try {
|
||||
map.invalidateSize();
|
||||
|
||||
navigator.geolocation.getCurrentPosition(pos => {
|
||||
mark(pos.coords.latitude, pos.coords.longitude, `My Location: (${pos.coords.latitude}, ${pos.coords.longitude})`);
|
||||
});
|
||||
} catch (e) {}
|
||||
}, 0);
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
return _e('div', { id: 'mapView', ref: containerRef });
|
||||
}
|
||||
|
||||
function App() {
|
||||
const editorRef = React.useRef(null);
|
||||
const promptEditorRef = React.useRef(null);
|
||||
const settingsRef = React.useRef({});
|
||||
const fileNameRef = React.useRef('sayhello.js');
|
||||
const promptMessagesRef = React.useRef([]);
|
||||
const mapViewRef = React.useRef(null);
|
||||
const [showMap, setShowMap] = React.useState(false);
|
||||
|
||||
const fetchSettings = () => axios.get(`/settings`)
|
||||
.then(response => {
|
||||
|
|
@ -472,23 +575,23 @@
|
|||
}
|
||||
};
|
||||
|
||||
const sendMessageToAzureAi = () => {
|
||||
const sendMessageToAzureCognitive = () => {
|
||||
const promptMessage = prompt("Enter a prompt message:", '');
|
||||
if (!promptMessage || promptMessage.trim() == '') {
|
||||
alert("A prompt message is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
appendTextToEditor(`\n// ${promptMessage}... Generating text with Azure AI...`);
|
||||
appendTextToEditor(`\n// ${promptMessage}... Generating text with Azure Cognitive...`);
|
||||
pushPromptMessage("user", promptMessage);
|
||||
|
||||
const apiKey = settingsRef.current.AzureAiServiceApiKey;
|
||||
const apiKey = settingsRef.current.AzureCognitiveApiKey;
|
||||
if (!apiKey || apiKey.trim() == '') {
|
||||
alert("Azure AI API key is not set.");
|
||||
alert("Azure Cognitive API key is not set.");
|
||||
return;
|
||||
}
|
||||
|
||||
const url = `${settingsRef.current.AzureAiServicePrefix}models/chat/completions?api-version=${settingsRef.current.AzureAiServiceApiVersion}`;
|
||||
const url = `${settingsRef.current.AzureCognitivePrefix}models/chat/completions?api-version=${settingsRef.current.AzureCognitiveApiVersion}`;
|
||||
|
||||
const data = {
|
||||
messages: promptMessagesRef.current,
|
||||
|
|
@ -648,6 +751,10 @@
|
|||
});
|
||||
};
|
||||
|
||||
function toggleMap() {
|
||||
setShowMap(v => !v);
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
window.addEventListener('resize', () => {
|
||||
resizeEditor();
|
||||
|
|
@ -662,15 +769,17 @@
|
|||
onOpenFileClick: openFile,
|
||||
onSaveFileClick: saveFile,
|
||||
onCopliotClick: sendMessageToCopilot,
|
||||
onAzureAiClick: sendMessageToAzureAi,
|
||||
onAzureCognitiveClick: sendMessageToAzureCognitive,
|
||||
onSavePromptClick: savePromptMessages,
|
||||
onLoadPromptClick: loadPromptMessages,
|
||||
onQueryWhoisClick: queryWhois,
|
||||
onQueryDnsClick: queryDns,
|
||||
onQueryIpClick: queryIp
|
||||
onQueryIpClick: queryIp,
|
||||
onMapClick: toggleMap
|
||||
}),
|
||||
_e('div', { id: 'container' },
|
||||
_e(Editor, { editorRef }),
|
||||
_e(Editor, { editorRef: editorRef, visible: !showMap }),
|
||||
_e(MapView, { mapViewRef: mapViewRef, visible: showMap }),
|
||||
_e(PromptEditor, { promptEditorRef, promptMessagesRef })
|
||||
),
|
||||
_e('div', { className: 'banner' }, _e('a', { href: 'https://github.com/gnh1201/welsonjs' }, '❤️ Contribute this project')),
|
||||
|
|
|
|||
75
app.js
75
app.js
|
|
@ -36,12 +36,25 @@ var console = {
|
|||
}
|
||||
return res;
|
||||
},
|
||||
_echoDefault: function(message) {
|
||||
_muted: (function() {
|
||||
try {
|
||||
if (typeof WScript !== "undefined")
|
||||
return WScript.Arguments.Named.Exists("quiet");
|
||||
} catch (e) { /* ignore */ }
|
||||
|
||||
return false;
|
||||
})(),
|
||||
_echoCallback: function(params, type) {
|
||||
if (this._muted) return;
|
||||
|
||||
if (typeof WScript !== "undefined") {
|
||||
WScript.Echo("[*] " + message)
|
||||
if (this._muted) {
|
||||
WScript.StdErr.WriteLine("[*] " + params.message);
|
||||
return;
|
||||
}
|
||||
WScript.StdOut.WriteLine("[*] " + params.message);
|
||||
}
|
||||
},
|
||||
_echoCallback: null,
|
||||
_echo: function(args, type) {
|
||||
var messages = [];
|
||||
var params = {
|
||||
|
|
@ -80,19 +93,15 @@ var console = {
|
|||
}
|
||||
}
|
||||
|
||||
var message = messages.join(' ');
|
||||
params.message = messages.join(' ');
|
||||
if (typeof type !== "undefined") {
|
||||
message = type + ": " + message;
|
||||
params.message = type + ": " + params.message;
|
||||
}
|
||||
this._echoDefault(message);
|
||||
this._messages.push(message);
|
||||
this._echoCallback(params);
|
||||
this._messages.push(params.message);
|
||||
|
||||
if (params.scope.length > 0 && this._echoCallback != null) {
|
||||
try {
|
||||
this._echoCallback(params, type);
|
||||
} catch (e) {
|
||||
this._echoDefault("Exception:" + e.message);
|
||||
}
|
||||
if (params.scope.length > 0) {
|
||||
this._echoCallback(params, type);
|
||||
}
|
||||
},
|
||||
assert: function(assertion) {
|
||||
|
|
@ -238,7 +247,7 @@ function TraceError(severity, message, callee) {
|
|||
})([
|
||||
function (s) { fn.call(console, s); }, // 1) severity-specific console
|
||||
function (s) { console.log(s); }, // 2) generic console.log
|
||||
function (s) { WScript.Echo(s); } // 3) WSH fallback
|
||||
function (s) { WScript.StdOut.WriteLine(s); } // 3) WSH fallback
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -404,7 +413,7 @@ function require(pathname) {
|
|||
if (pos > -1) {
|
||||
var scheme = FN.substring(0, pos);
|
||||
|
||||
// load script from a remote server
|
||||
// request a script from a remote server
|
||||
if (["http", "https"].indexOf(scheme) > -1) {
|
||||
require._addScriptProvider(function(url) {
|
||||
try {
|
||||
|
|
@ -415,7 +424,7 @@ function require(pathname) {
|
|||
});
|
||||
}
|
||||
|
||||
// load script from LIE(Language Inference Engine) service
|
||||
// request a script from LLM based AI services
|
||||
if (["ai"].indexOf(scheme) > -1) {
|
||||
require._addScriptProvider(function(url) {
|
||||
try {
|
||||
|
|
@ -472,7 +481,7 @@ function require(pathname) {
|
|||
})({
|
||||
existsSync: function(filename) {
|
||||
return UseObject("Scripting.FileSystemObject", function(fso) {
|
||||
return fso.FileExists(filename);
|
||||
return fso.FileExists(require._getCurrentScriptDirectory() + "\\" + filename);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
|
|
@ -715,22 +724,20 @@ require._addScriptProvider = function(f) {
|
|||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Load script, and call app.main()
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function initializeConsole() {
|
||||
if (typeof WScript === "undefined") {
|
||||
console.error("This is not a console application");
|
||||
return;
|
||||
}
|
||||
|
||||
var argl = WScript.arguments.length;
|
||||
if (argl > 0) {
|
||||
var args = [];
|
||||
for (var i = 0; i < argl; i++) {
|
||||
args.push(WScript.arguments(i));
|
||||
}
|
||||
var args = (function(acc, length) {
|
||||
for (var i = 0; i < length; i++)
|
||||
acc.push(WScript.arguments(i));
|
||||
return acc;
|
||||
})([], WScript.arguments.length);
|
||||
|
||||
if (args.length > 0) {
|
||||
var name = args.shift();
|
||||
var app = require(name);
|
||||
if (app) {
|
||||
|
|
@ -779,14 +786,12 @@ function initializeWindow(name, args, w, h) {
|
|||
|
||||
function dispatchServiceEvent(name, eventType, w_args, argl) {
|
||||
var app = require(name);
|
||||
var args = [];
|
||||
var args = (function(acc, length) {
|
||||
for (var i = 0; i < argl; i++)
|
||||
acc.push(w_args(i));
|
||||
return acc;
|
||||
})([], argl);
|
||||
|
||||
// convert the arguments to Array
|
||||
for (var i = 0; i < argl; i++) {
|
||||
args.push(w_args(i));
|
||||
}
|
||||
|
||||
// load the service
|
||||
if (app) {
|
||||
var bind = function(eventType) {
|
||||
var event_callback_name = "on" + eventType;
|
||||
|
|
@ -846,8 +851,8 @@ if (typeof JSON === "undefined") {
|
|||
__evalFile__("app/assets/js/json2.js");
|
||||
}
|
||||
|
||||
// core-js (formerly, babel-polyfill)
|
||||
require("app/assets/js/core-js-3.38.0.minified");
|
||||
// core-js (polyfills)
|
||||
require("app/assets/js/core-js-3.49.0.wsh");
|
||||
|
||||
// Squel.js SQL query string builder for Javascript
|
||||
var squel = require("app/assets/js/squel-basic-5.13.0-afa1cb5.wsh");
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
29381
app/assets/js/core-js-3.49.0.wsh.js
Normal file
29381
app/assets/js/core-js-3.49.0.wsh.js
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -47,4 +47,4 @@ echo [*] Registering WelsonJS.Toolkit component...
|
|||
|
||||
:: Final step
|
||||
echo [*] Pre-configuration complete. Starting bootstrap script...
|
||||
cscript app.js bootstrap
|
||||
%SystemRoot%\SysWOW64\cscript.exe app.js bootstrap
|
||||
|
|
|
|||
7
bootstrap.js
vendored
7
bootstrap.js
vendored
|
|
@ -1,5 +1,5 @@
|
|||
// bootstrap.js
|
||||
// Copyright 2019-2025, Namhyeon Go <gnh1201@catswords.re.kr> and the WelsonJS contributors.
|
||||
// Copyright 2019-2026, Namhyeon Go <gnh1201@catswords.re.kr> and the WelsonJS contributors.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
|
|
@ -19,11 +19,6 @@ function main(args) {
|
|||
console.log("Starting unlock files...");
|
||||
PS.execCommand("dir | Unblock-File");
|
||||
|
||||
// Allow CROS to ADO
|
||||
//console.log("Adjusting CROS policy to ADO...");
|
||||
//REG.write(REG.HKCU, "SOFTWARE\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Lockdown_Zones\\4", "1406", "00000000", REG.DWORD);
|
||||
//REG.write(REG.HKLM, "SOFTWARE\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Lockdown_Zones\\4", "1406", "00000000", REG.DWORD);
|
||||
|
||||
// Register HTA file association
|
||||
console.log("Registering HTA file association...");
|
||||
REG.execFile("app\\assets\\reg\\Default_HTA.reg");
|
||||
|
|
|
|||
|
|
@ -1,33 +1,35 @@
|
|||
// coupang.js
|
||||
// Coupang SERP API Client
|
||||
// Copyright 2019-2025, Namhyeon Go <gnh1201@catswords.re.kr> and the WelsonJS contributors.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
// SECURITY NOTICE
|
||||
// Due to potential security issues, the Public API URL is not provided. If you need to request access, please refer to the project's contact information.
|
||||
// You can download the server-side script that implements this functionality from the link below:
|
||||
// https://github.com/gnh1201/caterpillar
|
||||
//
|
||||
var JsonRpc2 = require("lib/jsonrpc2");
|
||||
var HTTP = require("lib/http");
|
||||
|
||||
function search(s) {
|
||||
var rpc = JsonRpc2.create(JsonRpc2.DEFAULT_JSONRPC2_URL);
|
||||
var result = rpc.invoke("relay_invoke_method", {
|
||||
"callback": "load_script",
|
||||
"requires": [
|
||||
"https://scriptas.catswords.net/coupang.class.php"
|
||||
],
|
||||
"args": [
|
||||
"$search = new CoupangProductSearch(); return $search->searchProducts('" + s + "')"
|
||||
]
|
||||
}, "");
|
||||
function search(keyword, limit) {
|
||||
if (typeof keyword !== "string" || keyword.length === 0) {
|
||||
throw new TypeError("keyword must be a non-empty string");
|
||||
}
|
||||
|
||||
return result.data;
|
||||
limit = Math.min(100, Math.max(1,
|
||||
Math.floor((typeof limit === "number" && isFinite(limit)) ? limit : 10)
|
||||
));
|
||||
|
||||
return HTTP.create()
|
||||
.setParameters({
|
||||
"keyword": keyword,
|
||||
"limit": limit
|
||||
})
|
||||
.setDataType("json")
|
||||
.open("GET", "https://cold-math-31f3.gnh1201.workers.dev/api/v1/products/search")
|
||||
.send()
|
||||
.responseBody
|
||||
;
|
||||
}
|
||||
|
||||
exports.search = search;
|
||||
|
||||
exports.VERSIONINFO = "Coupang Product Search Client (coupang.js) version 0.1.1";
|
||||
exports.VERSIONINFO = "Coupang SERP API Client (coupang.js) version 1.0";
|
||||
exports.AUTHOR = "gnh1201@catswords.re.kr";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
|
|
|
|||
|
|
@ -106,9 +106,9 @@ var HTTPObject = function(engine) {
|
|||
"Msxml2.XMLHTTP",
|
||||
"Msxml2.XMLHTTP.7.0",
|
||||
"Msxml2.XMLHTTP.6.0",
|
||||
"Msxml2.XMLHTTP.5.O",
|
||||
"Msxml2.XMLHTTP.4.O",
|
||||
"Msxml2.XMLHTTP.3.O",
|
||||
"Msxml2.XMLHTTP.5.0",
|
||||
"Msxml2.XMLHTTP.4.0",
|
||||
"Msxml2.XMLHTTP.3.0",
|
||||
"Msxml2.XMLHTTP.2.6",
|
||||
"Msxml2.ServerXMLHTTP",
|
||||
"Msxml2.ServerXMLHTTP.6.0",
|
||||
|
|
@ -1229,7 +1229,7 @@ exports.parseURL = parseURL;
|
|||
exports.DEFAULT_USER_AGENT = DEFAULT_USER_AGENT;
|
||||
exports.defaultUserAgent = DEFAULT_USER_AGENT; // compatible
|
||||
|
||||
exports.VERSIONINFO = "WelsonJS framework HTTP client (http.js) version 0.7.48";
|
||||
exports.VERSIONINFO = "WelsonJS framework HTTP client (http.js) version 0.7.49";
|
||||
exports.AUTHOR = "gnh1201@catswords.re.kr";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,58 @@ function JsonRpc2(url) {
|
|||
}
|
||||
}
|
||||
|
||||
function extract(message, callback) {
|
||||
var data;
|
||||
|
||||
if (typeof callback !== "function") {
|
||||
throw new Error("Invalid callback");
|
||||
}
|
||||
|
||||
try {
|
||||
data = JSON.parse(message);
|
||||
} catch (e) {
|
||||
throw new Error("Invalid JSON: " + e.message);
|
||||
}
|
||||
|
||||
if (!data || typeof data !== "object") {
|
||||
throw new Error("Invalid request object");
|
||||
}
|
||||
|
||||
if (data.jsonrpc !== "2.0") {
|
||||
throw new Error("Invalid JSON-RPC version");
|
||||
}
|
||||
|
||||
if (!data.method || typeof data.method !== "string") {
|
||||
throw new Error("Missing or invalid method");
|
||||
}
|
||||
|
||||
var params = data.params !== undefined ? data.params : null;
|
||||
var id = data.id !== undefined ? data.id : null;
|
||||
|
||||
try {
|
||||
var result = callback(data.method, params, id);
|
||||
|
||||
if (result !== false) {
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
result: result === undefined ? null : result,
|
||||
id: id
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (e) {
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
error: {
|
||||
code: -32603,
|
||||
message: e && e.message ? e.message : "Internal error"
|
||||
},
|
||||
id: id
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function wrap(method, params, id) {
|
||||
return {
|
||||
"jsonrpc": "2.0",
|
||||
|
|
@ -51,14 +103,15 @@ function create(url) {
|
|||
return new JsonRpc2(url);
|
||||
}
|
||||
|
||||
var DEFAULT_JSONRPC2_URL = "https://azure-ashlan-40.tiiny.io/";
|
||||
var DEFAULT_JSONRPC2_URL = "http://localhost:5555";
|
||||
|
||||
exports.extract = extract;
|
||||
exports.wrap = wrap;
|
||||
exports.create = create;
|
||||
|
||||
exports.DEFAULT_JSONRPC2_URL = DEFAULT_JSONRPC2_URL;
|
||||
|
||||
exports.VERSIONINFO = "JSON-RPC 2.0 wrapper (jsonrpc2.js) version 0.1.5";
|
||||
exports.VERSIONINFO = "JSON-RPC 2.0 wrapper (jsonrpc2.js) version 0.1.7";
|
||||
exports.AUTHOR = "gnh1201@catswords.re.kr";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
|
|
|
|||
68
lib/stdio-server.js
Normal file
68
lib/stdio-server.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// stdio-server.js
|
||||
// Copyright 2019-2026, Namhyeon Go <gnh1201@catswords.re.kr> and the WelsonJS contributors.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
var STD = require("lib/std");
|
||||
|
||||
function StdioServer() {
|
||||
// Set event-attachable object
|
||||
STD.EventTarget.apply(this, arguments);
|
||||
|
||||
this.messages = [];
|
||||
|
||||
this.receive = function () {
|
||||
return this.messages.shift();
|
||||
};
|
||||
|
||||
this.send = function (message) {
|
||||
if (!message) return;
|
||||
|
||||
if (typeof message === "object") {
|
||||
try {
|
||||
var _serialized = JSON.stringify(message);
|
||||
message = _serialized;
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
|
||||
WScript.StdOut.WriteLine(message);
|
||||
WScript.StdErr.WriteLine(message);
|
||||
};
|
||||
|
||||
this.listen = function () {
|
||||
while (!WScript.StdIn.AtEndOfStream) {
|
||||
this.messages.push(WScript.StdIn.ReadLine());
|
||||
this.dispatchEvent(new STD.Event("message"));
|
||||
}
|
||||
};
|
||||
}
|
||||
StdioServer.prototype = new STD.EventTarget();
|
||||
StdioServer.prototype.constructor = StdioServer;
|
||||
|
||||
/*
|
||||
|
||||
// For example
|
||||
var server = new StdioServer();
|
||||
|
||||
server.addEventListener("message", function(e) {
|
||||
// receive message
|
||||
var message = e.target.receive();
|
||||
|
||||
console.log(message);
|
||||
|
||||
// send message
|
||||
e.target.send("Hello world");
|
||||
});
|
||||
|
||||
server.listen();
|
||||
|
||||
*/
|
||||
|
||||
exports.create = function () {
|
||||
return new StdioServer();
|
||||
};
|
||||
|
||||
exports.VERSIONINFO = "Stdio Server (stdio-server.js) version 0.1";
|
||||
exports.AUTHOR = "gnh1201@catswords.re.kr";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
126
mcploader.js
Normal file
126
mcploader.js
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
// mcploader.js
|
||||
// Copyright 2019-2026, Namhyeon Go <gnh1201@catswords.re.kr> and the WelsonJS contributors.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
var StdioServer = require("lib/stdio-server");
|
||||
var JsonRpc2 = require("lib/jsonrpc2");
|
||||
|
||||
function main(args) {
|
||||
var server = StdioServer.create();
|
||||
|
||||
server.addEventListener("message", function(e) {
|
||||
var message = e.target.receive();
|
||||
|
||||
e.target.send(
|
||||
JsonRpc2.extract(message, function (method, params, id) {
|
||||
var isError = false;
|
||||
|
||||
if (method == "initialize") {
|
||||
return {
|
||||
"protocolVersion": "2025-11-25",
|
||||
"capabilities": {
|
||||
"extensions": {
|
||||
"io.modelcontextprotocol/ui": {
|
||||
"mimeTypes": ["text/html;profile=mcp-app"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serverInfo": {
|
||||
"name": "WelsonJS MCP",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"isError": isError
|
||||
};
|
||||
}
|
||||
|
||||
if (method === "notifications/initialized") {
|
||||
// DO NOT return anything
|
||||
return false;
|
||||
}
|
||||
|
||||
if (method == "tools/list") {
|
||||
return {
|
||||
"tools": [
|
||||
{
|
||||
"name": "add_both_numbers",
|
||||
"title": "add both_numbers (add A and B)",
|
||||
"description": "add two numbers (add A and B)",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"a": {
|
||||
"type": "number"
|
||||
},
|
||||
"b": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": ["a", "b"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "evaluate_js_es3",
|
||||
"title": "Evaluate JavaScript ES3",
|
||||
"description": "Evaluate JavaScript with ES3 syntax (use ES3 syntax strictly)",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"script": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["script"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"isError": isError
|
||||
};
|
||||
}
|
||||
|
||||
if (method == "tools/call") {
|
||||
var function_calling_name = params.name;
|
||||
|
||||
if (function_calling_name == "add_both_numbers") {
|
||||
return {
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "Result is " + (parseFloat(params.arguments.a) + parseFloat(params.arguments.b))
|
||||
}
|
||||
],
|
||||
"isError": isError
|
||||
};
|
||||
}
|
||||
|
||||
if (function_calling_name == "evaluate_js_es3") {
|
||||
return {
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": (function(script) {
|
||||
try {
|
||||
return String(eval(script));
|
||||
} catch (e) {
|
||||
return "Error";
|
||||
isError = true;
|
||||
}
|
||||
})(params.arguments.script)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isError = true;
|
||||
return {
|
||||
"isError": isError
|
||||
};
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
server.listen();
|
||||
}
|
||||
|
||||
exports.main = main;
|
||||
Loading…
Reference in New Issue
Block a user