using System.Text.Json.Nodes; using Fleet.Core; using Fleet.Enrollment.Client; // fleet-enroll --server https://panel --join jt_xxx --name jp-1 --identity-dir /etc/moshiro [--meta '{"probe_tcp_port":7443,...}'] [--version 1.0] // 一次性运行:生成身份、注册、写入身份目录,然后退出。 string? Arg(string name) => args.SkipWhile(a => a != name).Skip(1).FirstOrDefault(); string? server = Arg("--server"); string? join = Arg("--join"); string? name = Arg("--name"); string? directory = Arg("--identity-dir"); if (server is null || join is null || name is null || directory is null) { Console.Error.WriteLine("usage: fleet-enroll --server --join --name --identity-dir [--meta ] [--version ] [--genesis --controllers ]"); return 2; } JsonNode? meta = null; if (Arg("--meta") is { } metaText) { try { meta = JsonNode.Parse(metaText); } catch (System.Text.Json.JsonException ex) { Console.Error.WriteLine("--meta is not valid JSON: " + ex.Message); return 2; } } string? genesis = Arg("--genesis"); string[] controllers = (Arg("--controllers") ?? "").Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); if (genesis is not null && controllers.Length == 0) { Console.Error.WriteLine("--genesis needs --controllers: every node has an owner (the passkey credential ids from the panel's command)"); return 2; } using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) }; Result result = await EnrollmentClient.EnrollAsync( http, new Uri(server), join, name, directory, Arg("--version") ?? "0.0.0", meta, TimeProvider.System, CancellationToken.None, genesis, controllers); if (!result.TryGet(out EnrollmentResult? enrolled, out FleetError? error)) { Console.Error.WriteLine($"enrollment failed ({error.Code}): {error.Message}"); return 1; } Console.WriteLine($"enrolled as {enrolled.NodeId} ({enrolled.Status}); identity written to {enrolled.IdentityDirectory}" + (enrolled.Pinned ? "; operator trust pinned" : "; operator trust NOT pinned (no --genesis)")); return 0;