103 lines
3.2 KiB
C#
103 lines
3.2 KiB
C#
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
|
|
namespace Zcbot.WindowsNode;
|
|
|
|
internal static class Program
|
|
{
|
|
[STAThread]
|
|
private static int Main(string[] args)
|
|
{
|
|
if (args.Length > 0)
|
|
{
|
|
NativeConsole.AttachToParent();
|
|
return RunCommandAsync(args).GetAwaiter().GetResult();
|
|
}
|
|
|
|
ApplicationConfiguration.Initialize();
|
|
using var singleInstance = new Mutex(
|
|
initiallyOwned: true, "Local\\Zcbot.WindowsNode", out var isFirstInstance);
|
|
if (!isFirstInstance)
|
|
{
|
|
MessageBox.Show(
|
|
"zcbot Windows Node 已在运行。请查看系统托盘。",
|
|
"zcbot Windows Node", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
return 0;
|
|
}
|
|
|
|
var store = new NodeConfigStore(NodePaths.ForCurrentMachine());
|
|
Application.Run(new TrayApplicationContext(store));
|
|
return 0;
|
|
}
|
|
|
|
private static async Task<int> RunCommandAsync(string[] args)
|
|
{
|
|
try
|
|
{
|
|
var store = new NodeConfigStore(NodePaths.ForCurrentMachine());
|
|
if (string.Equals(args[0], "enroll", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var options = EnrollOptions.Parse(args[1..]);
|
|
await EnrollmentClient.EnrollAsync(options, store, CancellationToken.None);
|
|
Console.WriteLine("[OK] Node registration saved.");
|
|
return 0;
|
|
}
|
|
if (!string.Equals(args[0], "run", StringComparison.OrdinalIgnoreCase)
|
|
|| !args.Skip(1).Contains("--headless", StringComparer.OrdinalIgnoreCase))
|
|
{
|
|
throw new NodeConfigurationException(
|
|
"Usage: Zcbot.WindowsNode enroll ... | run --headless");
|
|
}
|
|
|
|
using var shutdown = new CancellationTokenSource();
|
|
Console.CancelKeyPress += (_, eventArgs) =>
|
|
{
|
|
eventArgs.Cancel = true;
|
|
shutdown.Cancel();
|
|
};
|
|
var config = store.Load();
|
|
await new NodeConnectionLoop(config).RunAsync(shutdown.Token);
|
|
return 0;
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
return 0;
|
|
}
|
|
catch (NodeConfigurationException exception)
|
|
{
|
|
Console.Error.WriteLine($"[ERR] {exception.Message}");
|
|
return 2;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
Console.Error.WriteLine($"[ERR] {exception.GetType().Name}: {exception.Message}");
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static class NativeConsole
|
|
{
|
|
private const uint AttachParentProcess = 0xFFFFFFFF;
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
private static extern bool AttachConsole(uint processId);
|
|
|
|
internal static void AttachToParent()
|
|
{
|
|
if (!AttachConsole(AttachParentProcess))
|
|
{
|
|
return;
|
|
}
|
|
Console.SetOut(new StreamWriter(Console.OpenStandardOutput(), new UTF8Encoding(false))
|
|
{
|
|
AutoFlush = true,
|
|
});
|
|
Console.SetError(new StreamWriter(Console.OpenStandardError(), new UTF8Encoding(false))
|
|
{
|
|
AutoFlush = true,
|
|
});
|
|
}
|
|
}
|