zcbot/windows-node/Zcbot.WindowsNode/Program.cs

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,
});
}
}