mirror of
https://github.com/gnh1201/welsonjs.git
synced 2026-02-20 17:48:27 +00:00
Refactor logger interface and add JsNative interop layer
Updated ICompatibleLogger to accept params object[] for flexible logging. Refactored TraceLogger to support the new interface and improved formatting. Added JsNative.cs to encapsulate ChakraCore P/Invoke interop, and updated JsCore to use JsNative for all native calls. Modified all resource tools to accept and use ICompatibleLogger for consistent logging. Updated project file to include new and updated sources.
This commit is contained in:
parent
83a037dfa2
commit
87020d35ac
|
|
@ -10,8 +10,8 @@ namespace WelsonJS.Launcher
|
|||
{
|
||||
public interface ICompatibleLogger
|
||||
{
|
||||
void Info(string message);
|
||||
void Warn(string message);
|
||||
void Error(string message);
|
||||
void Info(params object[] args);
|
||||
void Warn(params object[] args);
|
||||
void Error(params object[] args);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,53 +4,47 @@
|
|||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
public sealed class JsCore : IDisposable
|
||||
{
|
||||
private IntPtr _runtime = IntPtr.Zero;
|
||||
private IntPtr _context = IntPtr.Zero;
|
||||
private JsNative.JsRuntime _rt;
|
||||
private JsNative.JsContext _ctx;
|
||||
private bool _disposed;
|
||||
|
||||
public JsCore()
|
||||
{
|
||||
Check(JsCreateRuntime(0, IntPtr.Zero, out _runtime), nameof(JsCreateRuntime));
|
||||
Check(JsCreateContext(_runtime, out _context), nameof(JsCreateContext));
|
||||
Check(JsSetCurrentContext(_context), nameof(JsSetCurrentContext));
|
||||
Check(JsNative.JsCreateRuntime(JsNative.JsRuntimeAttributes.None, null, out _rt), "JsCreateRuntime");
|
||||
Check(JsNative.JsCreateContext(_rt, out _ctx), "JsCreateContext");
|
||||
Check(JsNative.JsSetCurrentContext(_ctx), "JsSetCurrentContext");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates JavaScript and returns the result converted to string (via JsConvertValueToString).
|
||||
/// </summary>
|
||||
public string EvaluateToString(string script, string sourceUrl = "repl")
|
||||
{
|
||||
if (_disposed) throw new ObjectDisposedException(nameof(JsCore));
|
||||
if (script is null) throw new ArgumentNullException(nameof(script));
|
||||
if (script == null) throw new ArgumentNullException(nameof(script));
|
||||
|
||||
Check(JsRunScript(script, IntPtr.Zero, sourceUrl, out var result), nameof(JsRunScript));
|
||||
JsNative.JsValue result;
|
||||
Check(JsNative.JsRunScript(script, UIntPtr.Zero, sourceUrl, out result), "JsRunScript");
|
||||
|
||||
// Convert result -> JsString
|
||||
Check(JsConvertValueToString(result, out var jsString), nameof(JsConvertValueToString));
|
||||
JsNative.JsValue jsStr;
|
||||
Check(JsNative.JsConvertValueToString(result, out jsStr), "JsConvertValueToString");
|
||||
|
||||
// Extract pointer/length (UTF-16) and marshal to managed string
|
||||
Check(JsStringToPointer(jsString, out var p, out var len), nameof(JsStringToPointer));
|
||||
return Marshal.PtrToStringUni(p, checked((int)len));
|
||||
IntPtr p;
|
||||
UIntPtr len;
|
||||
Check(JsNative.JsStringToPointer(jsStr, out p, out len), "JsStringToPointer");
|
||||
|
||||
int chars = checked((int)len);
|
||||
return Marshal.PtrToStringUni(p, chars);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates JavaScript for side effects; discards the result.
|
||||
/// </summary>
|
||||
public void Execute(string script, string sourceUrl = "repl")
|
||||
private static void Check(JsNative.JsErrorCode code, string op)
|
||||
{
|
||||
_ = EvaluateToString(script, sourceUrl);
|
||||
}
|
||||
|
||||
private static void Check(JsErrorCode code, string op)
|
||||
{
|
||||
if (code != JsErrorCode.JsNoError)
|
||||
throw new InvalidOperationException($"{op} failed with {code} (0x{(int)code:X}).");
|
||||
if (code != JsNative.JsErrorCode.JsNoError)
|
||||
throw new InvalidOperationException(op + " failed: " + code + " (0x" + ((int)code).ToString("X", CultureInfo.InvariantCulture) + ")");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -60,112 +54,18 @@ namespace WelsonJS.Launcher
|
|||
|
||||
try
|
||||
{
|
||||
// Unset the current context from the SAME physical thread that set it.
|
||||
JsSetCurrentContext(IntPtr.Zero);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Swallow to ensure runtime is disposed.
|
||||
// Unset current context
|
||||
JsNative.JsSetCurrentContext(new JsNative.JsContext { Handle = IntPtr.Zero });
|
||||
}
|
||||
catch { /* ignore */ }
|
||||
finally
|
||||
{
|
||||
if (_runtime != IntPtr.Zero)
|
||||
{
|
||||
JsDisposeRuntime(_runtime);
|
||||
_runtime = IntPtr.Zero;
|
||||
}
|
||||
_context = IntPtr.Zero;
|
||||
if (_rt.Handle != IntPtr.Zero)
|
||||
JsNative.JsDisposeRuntime(_rt);
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~JsCore() => Dispose();
|
||||
|
||||
// =========================
|
||||
// P/Invoke surface (as given)
|
||||
// =========================
|
||||
|
||||
// Essential (expanded) JsErrorCode set matching ChakraCore’s headers layout.
|
||||
// Values are grouped by category bases (0x10000, 0x20000, ...).
|
||||
public enum JsErrorCode
|
||||
{
|
||||
// Success
|
||||
JsNoError = 0,
|
||||
|
||||
// Category bases (useful when inspecting ranges)
|
||||
JsErrorCategoryUsage = 0x10000,
|
||||
JsErrorCategoryEngine = 0x20000,
|
||||
JsErrorCategoryScript = 0x30000,
|
||||
JsErrorCategoryFatal = 0x40000,
|
||||
|
||||
// Usage errors (0x10001+)
|
||||
JsErrorInvalidArgument = 0x10001,
|
||||
JsErrorNullArgument = 0x10002,
|
||||
JsErrorNoCurrentContext = 0x10003,
|
||||
JsErrorInExceptionState = 0x10004,
|
||||
JsErrorNotImplemented = 0x10005,
|
||||
JsErrorWrongThread = 0x10006,
|
||||
JsErrorRuntimeInUse = 0x10007,
|
||||
JsErrorBadSerializedScript = 0x10008,
|
||||
JsErrorInDisabledState = 0x10009,
|
||||
JsErrorCannotDisableExecution = 0x1000A,
|
||||
JsErrorHeapEnumInProgress = 0x1000B,
|
||||
JsErrorArgumentNotObject = 0x1000C,
|
||||
JsErrorInProfileCallback = 0x1000D,
|
||||
JsErrorInThreadServiceCallback = 0x1000E,
|
||||
JsErrorCannotSerializeDebugScript = 0x1000F,
|
||||
JsErrorAlreadyDebuggingContext = 0x10010,
|
||||
JsErrorAlreadyProfilingContext = 0x10011,
|
||||
JsErrorIdleNotEnabled = 0x10012,
|
||||
|
||||
// Engine errors (0x20001+)
|
||||
JsErrorOutOfMemory = 0x20001,
|
||||
JsErrorBadFPUState = 0x20002,
|
||||
|
||||
// Script errors (0x30001+)
|
||||
JsErrorScriptException = 0x30001,
|
||||
JsErrorScriptCompile = 0x30002,
|
||||
JsErrorScriptTerminated = 0x30003,
|
||||
JsErrorScriptEvalDisabled = 0x30004,
|
||||
|
||||
// Fatal (0x40001)
|
||||
JsErrorFatal = 0x40001,
|
||||
|
||||
// Misc/diagnostic (0x50000+)
|
||||
JsErrorWrongRuntime = 0x50000,
|
||||
JsErrorDiagAlreadyInDebugMode = 0x50001,
|
||||
JsErrorDiagNotInDebugMode = 0x50002,
|
||||
JsErrorDiagNotAtBreak = 0x50003,
|
||||
JsErrorDiagInvalidHandle = 0x50004,
|
||||
JsErrorDiagObjectNotFound = 0x50005,
|
||||
JsErrorDiagUnableToPerformAction = 0x50006,
|
||||
}
|
||||
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern JsErrorCode JsCreateRuntime(uint attributes, IntPtr callback, out IntPtr runtime);
|
||||
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern JsErrorCode JsCreateContext(IntPtr runtime, out IntPtr context);
|
||||
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern JsErrorCode JsSetCurrentContext(IntPtr context);
|
||||
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
||||
public static extern JsErrorCode JsRunScript(string script, IntPtr sourceContext, string sourceUrl, out IntPtr result);
|
||||
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern JsErrorCode JsConvertValueToString(IntPtr value, out IntPtr stringValue);
|
||||
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern JsErrorCode JsStringToPointer(IntPtr value, out IntPtr buffer, out UIntPtr length);
|
||||
|
||||
// Note: Unsetting is typically done via JsSetCurrentContext(IntPtr.Zero)
|
||||
// Kept here only if your build exposes this symbol.
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "JsSetCurrentContext")]
|
||||
public static extern JsErrorCode JsUnSetCurrentContext(IntPtr zero);
|
||||
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern JsErrorCode JsDisposeRuntime(IntPtr runtime);
|
||||
~JsCore() { Dispose(); }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
93
WelsonJS.Toolkit/WelsonJS.Launcher/JsNative.cs
Normal file
93
WelsonJS.Toolkit/WelsonJS.Launcher/JsNative.cs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
public static class JsNative
|
||||
{
|
||||
// === Enums / handles ===
|
||||
[Flags]
|
||||
public enum JsRuntimeAttributes : uint
|
||||
{
|
||||
None = 0x00000000,
|
||||
DisableBackgroundWork = 0x00000001,
|
||||
AllowScriptInterrupt = 0x00000002,
|
||||
EnableIdleProcessing = 0x00000004,
|
||||
DisableNativeCodeGeneration = 0x00000008,
|
||||
EnableExperimentalFeatures = 0x00000010,
|
||||
}
|
||||
|
||||
// ChakraCore typedefs are opaque pointers; represent as IntPtr
|
||||
public struct JsRuntime { public IntPtr Handle; }
|
||||
public struct JsContext { public IntPtr Handle; }
|
||||
public struct JsValue { public IntPtr Handle; }
|
||||
|
||||
// JsErrorCode (essential subset; expand as needed)
|
||||
public enum JsErrorCode
|
||||
{
|
||||
JsNoError = 0,
|
||||
|
||||
// Usage
|
||||
JsErrorInvalidArgument = 0x10001,
|
||||
JsErrorNullArgument = 0x10002,
|
||||
JsErrorNoCurrentContext = 0x10003,
|
||||
JsErrorInExceptionState = 0x10004,
|
||||
JsErrorNotImplemented = 0x10005,
|
||||
JsErrorWrongThread = 0x10006,
|
||||
JsErrorRuntimeInUse = 0x10007,
|
||||
|
||||
// Script
|
||||
JsErrorScriptException = 0x30001,
|
||||
JsErrorScriptCompile = 0x30002,
|
||||
JsErrorScriptTerminated = 0x30003,
|
||||
|
||||
// Engine
|
||||
JsErrorOutOfMemory = 0x20001,
|
||||
|
||||
// Fatal
|
||||
JsErrorFatal = 0x40001,
|
||||
}
|
||||
|
||||
// Thread service callback: __stdcall
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
public delegate JsErrorCode JsThreadServiceCallback(IntPtr callback, IntPtr callbackState);
|
||||
|
||||
// ======= FIXED SIGNATURES (StdCall + Unicode) =======
|
||||
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern JsErrorCode JsCreateRuntime(
|
||||
JsRuntimeAttributes attributes,
|
||||
JsThreadServiceCallback threadService, // pass null if unused
|
||||
out JsRuntime runtime);
|
||||
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern JsErrorCode JsCreateContext(
|
||||
JsRuntime runtime,
|
||||
out JsContext newContext);
|
||||
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern JsErrorCode JsSetCurrentContext(JsContext context);
|
||||
|
||||
// JsSourceContext is size_t → UIntPtr; strings are wide-char
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
|
||||
public static extern JsErrorCode JsRunScript(
|
||||
string script,
|
||||
UIntPtr sourceContext,
|
||||
string sourceUrl,
|
||||
out JsValue result);
|
||||
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern JsErrorCode JsConvertValueToString(JsValue value, out JsValue stringValue);
|
||||
|
||||
// Returns pointer to UTF-16 buffer + length (size_t) for a JsString value
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern JsErrorCode JsStringToPointer(
|
||||
JsValue value,
|
||||
out IntPtr buffer,
|
||||
out UIntPtr length);
|
||||
|
||||
// Unset by passing "invalid" context (JS_INVALID_REFERENCE is typically null)
|
||||
[DllImport("ChakraCore.dll", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern JsErrorCode JsDisposeRuntime(JsRuntime runtime);
|
||||
}
|
||||
}
|
||||
|
|
@ -60,13 +60,13 @@ namespace WelsonJS.Launcher
|
|||
}, TaskScheduler.Default);
|
||||
|
||||
// Add resource tools
|
||||
_tools.Add(new ResourceTools.Completion(this, _httpClient));
|
||||
_tools.Add(new ResourceTools.Settings(this, _httpClient));
|
||||
_tools.Add(new ResourceTools.ChromiumDevTools(this, _httpClient));
|
||||
_tools.Add(new ResourceTools.DnsQuery(this, _httpClient));
|
||||
_tools.Add(new ResourceTools.IpQuery(this, _httpClient));
|
||||
_tools.Add(new ResourceTools.TwoFactorAuth(this, _httpClient));
|
||||
_tools.Add(new ResourceTools.Whois(this, _httpClient));
|
||||
_tools.Add(new ResourceTools.Completion(this, _httpClient, _logger));
|
||||
_tools.Add(new ResourceTools.Settings(this, _httpClient, _logger));
|
||||
_tools.Add(new ResourceTools.ChromiumDevTools(this, _httpClient, _logger));
|
||||
_tools.Add(new ResourceTools.DnsQuery(this, _httpClient, _logger));
|
||||
_tools.Add(new ResourceTools.IpQuery(this, _httpClient, _logger));
|
||||
_tools.Add(new ResourceTools.TwoFactorAuth(this, _httpClient, _logger));
|
||||
_tools.Add(new ResourceTools.Whois(this, _httpClient, _logger));
|
||||
|
||||
// Register the prefix
|
||||
_listener.Prefixes.Add(prefix);
|
||||
|
|
|
|||
|
|
@ -19,13 +19,16 @@ namespace WelsonJS.Launcher.ResourceTools
|
|||
{
|
||||
private readonly ResourceServer Server;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ICompatibleLogger _logger;
|
||||
private readonly WebSocketManager _wsManager = new WebSocketManager();
|
||||
private const string Prefix = "devtools/";
|
||||
|
||||
public ChromiumDevTools(ResourceServer server, HttpClient httpClient)
|
||||
public ChromiumDevTools(ResourceServer server, HttpClient httpClient, ICompatibleLogger logger)
|
||||
{
|
||||
Server = server;
|
||||
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public bool CanHandle(string path)
|
||||
|
|
|
|||
|
|
@ -22,13 +22,16 @@ namespace WelsonJS.Launcher.ResourceTools
|
|||
{
|
||||
private readonly ResourceServer Server;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ICompatibleLogger _logger;
|
||||
private const string Prefix = "completion/";
|
||||
private readonly ConcurrentBag<string> DiscoveredExecutables = new ConcurrentBag<string>();
|
||||
|
||||
public Completion(ResourceServer server, HttpClient httpClient)
|
||||
public Completion(ResourceServer server, HttpClient httpClient, ICompatibleLogger logger)
|
||||
{
|
||||
Server = server;
|
||||
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
|
||||
Task.Run(async () => await SafeDiscoverAsync(DiscoverFromInstalledSoftware));
|
||||
Task.Run(async () => await SafeDiscoverAsync(DiscoverFromPathVariable));
|
||||
|
|
@ -160,7 +163,7 @@ namespace WelsonJS.Launcher.ResourceTools
|
|||
{
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Trace.TraceInformation("Directory does not exist: {0}", path);
|
||||
_logger.Info("Directory does not exist: {0}", path);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +178,7 @@ namespace WelsonJS.Launcher.ResourceTools
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.TraceInformation("Error enumerating executables in '{0}': {1}", path, ex.Message);
|
||||
_logger.Info("Error enumerating executables in '{0}': {1}", path, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +198,7 @@ namespace WelsonJS.Launcher.ResourceTools
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.TraceError($"Discovery failed: {ex.Message}");
|
||||
_logger.Error($"Discovery failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,16 +18,19 @@ namespace WelsonJS.Launcher.ResourceTools
|
|||
{
|
||||
private readonly ResourceServer Server;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ICompatibleLogger _logger;
|
||||
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, HttpClient httpClient)
|
||||
public DnsQuery(ResourceServer server, HttpClient httpClient, ICompatibleLogger logger)
|
||||
{
|
||||
Server = server;
|
||||
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
|
||||
DnsServer = Program.GetAppConfig("DnsServerAddress");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,12 +14,15 @@ namespace WelsonJS.Launcher.ResourceTools
|
|||
{
|
||||
private readonly ResourceServer Server;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ICompatibleLogger _logger;
|
||||
private const string Prefix = "ip-query/";
|
||||
|
||||
public IpQuery(ResourceServer server, HttpClient httpClient)
|
||||
public IpQuery(ResourceServer server, HttpClient httpClient, ICompatibleLogger logger)
|
||||
{
|
||||
Server = server;
|
||||
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public bool CanHandle(string path)
|
||||
|
|
|
|||
|
|
@ -20,12 +20,15 @@ namespace WelsonJS.Launcher.ResourceTools
|
|||
{
|
||||
private readonly ResourceServer Server;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ICompatibleLogger _logger;
|
||||
private const string Prefix = "settings";
|
||||
|
||||
public Settings(ResourceServer server, HttpClient httpClient)
|
||||
public Settings(ResourceServer server, HttpClient httpClient, ICompatibleLogger logger)
|
||||
{
|
||||
Server = server;
|
||||
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public bool CanHandle(string path)
|
||||
|
|
|
|||
|
|
@ -19,14 +19,17 @@ namespace WelsonJS.Launcher.ResourceTools
|
|||
{
|
||||
private readonly ResourceServer Server;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ICompatibleLogger _logger;
|
||||
private const string Prefix = "tfa/";
|
||||
private const string Base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
private static readonly int[] ValidKeyCharLengths = new[] { 16, 32 };
|
||||
|
||||
public TwoFactorAuth(ResourceServer server, HttpClient httpClient)
|
||||
public TwoFactorAuth(ResourceServer server, HttpClient httpClient, ICompatibleLogger logger)
|
||||
{
|
||||
Server = server;
|
||||
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public bool CanHandle(string path)
|
||||
|
|
|
|||
|
|
@ -15,12 +15,15 @@ namespace WelsonJS.Launcher.ResourceTools
|
|||
{
|
||||
private readonly ResourceServer Server;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ICompatibleLogger _logger;
|
||||
private const string Prefix = "whois/";
|
||||
|
||||
public Whois(ResourceServer server, HttpClient httpClient)
|
||||
public Whois(ResourceServer server, HttpClient httpClient, ICompatibleLogger logger)
|
||||
{
|
||||
Server = server;
|
||||
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public bool CanHandle(string path)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
// We use the ICompatibleLogger interface to maintain a BCL-first style.
|
||||
// This allows for later replacement with logging libraries such as ILogger or Log4Net.
|
||||
//
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
|
|
@ -21,7 +23,7 @@ namespace WelsonJS.Launcher
|
|||
_logFileName = (typeof(TraceLogger).Namespace ?? "WelsonJS.Launcher") + ".log";
|
||||
Trace.Listeners.Add(new TextWriterTraceListener(_logFileName));
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Fallback when the process cannot write to the working directory
|
||||
Trace.Listeners.Add(new ConsoleTraceListener());
|
||||
|
|
@ -30,8 +32,27 @@ namespace WelsonJS.Launcher
|
|||
Trace.AutoFlush = true;
|
||||
}
|
||||
|
||||
public void Info(string message) => Trace.TraceInformation(message);
|
||||
public void Warn(string message) => Trace.TraceWarning(message);
|
||||
public void Error(string message) => Trace.TraceError(message);
|
||||
public void Info(params object[] args) => Trace.TraceInformation(Format(args));
|
||||
public void Warn(params object[] args) => Trace.TraceWarning(Format(args));
|
||||
public void Error(params object[] args) => Trace.TraceError(Format(args));
|
||||
|
||||
private static string Format(object[] args)
|
||||
{
|
||||
if (args == null || args.Length == 0) return string.Empty;
|
||||
|
||||
if (args.Length == 1)
|
||||
return args[0]?.ToString() ?? string.Empty;
|
||||
|
||||
string format = args[0]?.ToString() ?? string.Empty;
|
||||
try
|
||||
{
|
||||
return string.Format(format, args.Skip(1).ToArray());
|
||||
}
|
||||
catch
|
||||
{
|
||||
// In case of mismatched format placeholders
|
||||
return string.Join(" ", args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,8 +89,10 @@
|
|||
<Compile Include="ICompatibleLogger.cs" />
|
||||
<Compile Include="IResourceTool.cs" />
|
||||
<Compile Include="JsCore.cs" />
|
||||
<Compile Include="JsNative.cs" />
|
||||
<Compile Include="JsSerializer.cs" />
|
||||
<Compile Include="NativeBootstrap.cs" />
|
||||
<Compile Include="ResourceTools\ImageProxy.cs" />
|
||||
<Compile Include="ResourceTools\IpQuery.cs" />
|
||||
<Compile Include="ResourceTools\Settings.cs" />
|
||||
<Compile Include="ResourceTools\Completion.cs" />
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user