XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
UTF-8
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Nodes;
using XFEEliteDangerous.Client;
using XFEEliteDangerous.Core;
using XFEEliteDangerous.ManagementClient;

try { return await RunAsync(AppText.ConfigureArguments(args)); }
catch (ArgumentException error) { Console.Error.WriteLine(error.Message); return 1; }

static async Task<int> RunAsync(string[] args)
{
    if (args.Length == 0 || args[0] is "--help" or "help")
    {
        Console.WriteLine(AppText.Get("Program.Text053"));
        return 0;
    }
    try
    {
        var command = args[0]; var options = Parse(args[1..]);
        if(command is "server-status" or "server-probe")
        {
            using var api=new ManagementApi(options.GetValueOrDefault("address")??"http://127.0.0.1:48080/api/");
            if(command=="server-status"){Print(await api.CallAsync("status"));return 0;}
            var access=JsonNode.Parse(await File.ReadAllTextAsync(Path.Combine(options.GetValueOrDefault("data-root")??Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),"XFEEliteDangerous","Server"),"admin-access.json")))!;
            var owner=await api.CallAsync("auth/local-owner",token:access["key"]!.GetValue<string>());var token=owner["token"]!.GetValue<string>();
            try
            {
                var accounts=await api.CallAsync("accounts",token:token);if(accounts is not JsonArray)throw new InvalidDataException("Accounts response is not an array.");
                var catalog=await api.CallAsync("catalog",new(){["search"]=""},token);if(catalog is not JsonArray)throw new InvalidDataException("Catalogue response is not an array.");
                var profile=await api.CallAsync("profile",token:token);if(profile["role"]?.GetValue<string>()!="administrator")throw new InvalidDataException("Local owner is not an administrator.");
                var probeId=options.GetValueOrDefault("account")??owner["account"]!["id"]!.GetValue<string>();
                _=await api.CallAsync("fleet",new(){["accountId"]=probeId},token);
                var rejected=false;try{_=await api.CallAsync("profile",token:"invalid-token");}catch(LocalSessionException){rejected=true;}
                if(!rejected)throw new InvalidDataException("Invalid token was accepted.");
                Console.WriteLine("PASS typed C# management client: object/array responses, local-owner login, fleet, catalogue and HTTP401 mapping.");
            }
            finally{await api.CallAsync("auth/logout",token:token);}
            return 0;
        }
        if (command == "inspect")
        {
            var inspection = await new GameInstallationInspector().InspectAsync(Required(options, "game"));
            Console.WriteLine(JsonSerializer.Serialize(inspection, ClientJson.Options)); return 0;
        }
        var directory = options.GetValueOrDefault("data") ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "XFEEliteDangerous", "Offline");
        await using var workspace = new OfflineWorkspace(directory);
        if (command == "status") { Print(await workspace.StatusAsync()); return 0; }
        if (command is not ("create-account" or "inventory" or "credits" or "set-quantity" or "import-journal" or "export")) throw new ArgumentException(AppText.Get("Program.Text054"));
        if (!options.ContainsKey("password-stdin") || !Console.IsInputRedirected) throw new ArgumentException(AppText.Get("Program.Text055"));
        var password = await Console.In.ReadLineAsync() ?? throw new ArgumentException(AppText.Get("Program.Text056"));
        var email = Required(options, "email");
        if (command == "create-account")
        {
            Print(await workspace.RegisterAsync(email, Required(options, "name"), password)); return 0;
        }
        var login = await workspace.LoginAsync(email, password);
        password = "";
        var session = login["token"]!.GetValue<string>();
        var id = options.GetValueOrDefault("account") ?? login["account"]!["id"]!.GetValue<string>();
        try
        {
            switch (command)
            {
                case "inventory": Print(await workspace.CommanderAsync(session, id)); break;
                case "credits":
                    Print(await workspace.EditAsync(session, id, InventoryEdit.Credits, new JsonObject { ["delta"] = long.Parse(Required(options, "delta"), CultureInfo.InvariantCulture) }, Required(options, "version"))); break;
                case "set-quantity":
                    var category = Required(options, "category");
                    if (category is not ("cargo" or "materials")) throw new ArgumentException(AppText.Get("Program.Text057"));
                    Print(await workspace.EditAsync(session, id, category == "cargo" ? InventoryEdit.Cargo : InventoryEdit.Materials,
                        new JsonObject { ["itemId"] = Required(options, "item"), ["category"] = Required(options, "item-category"), ["quantity"] = long.Parse(Required(options, "quantity"), CultureInfo.InvariantCulture) }, Required(options, "version"))); break;
                case "import-journal":
                    var snapshot = await new JournalSnapshotReader().ReadAsync(Required(options, "journal"));
                    var node = JsonSerializer.SerializeToNode(snapshot, ClientJson.Options)!.AsObject();
                    foreach (var row in node["cargo"]!.AsArray()) row!["category"] = "cargo";
                    Print(await workspace.ImportJournalAsync(session, id, node, Required(options, "version"))); break;
                case "export":
                    var output = LocalPaths.FilePath(Required(options, "output"));
                    var commander = await workspace.CommanderAsync(session, id);
                    Directory.CreateDirectory(Path.GetDirectoryName(output)!);
                    await using (var stream = new FileStream(output, FileMode.CreateNew, FileAccess.Write, FileShare.None))
                        await JsonSerializer.SerializeAsync(stream, commander, ClientJson.Options);
                    Console.WriteLine(AppText.Get("Program.Text058") + output); break;
            }
            return 0;
        }
        finally { workspace.Logout(session); }
    }
    catch (Exception error) when (error is IOException or InvalidOperationException or UnauthorizedAccessException or ArgumentException or JsonException or OverflowException or FormatException)
    {
        Console.Error.WriteLine(error is JsonException ? AppText.Get("Program.Text059") : error.Message); return 1;
    }
}
static Dictionary<string, string?> Parse(string[] args)
{
    var result = new Dictionary<string, string?>(StringComparer.Ordinal);
    var known = new HashSet<string>(["data", "email", "name", "password-stdin", "account", "game", "delta", "version", "category", "item", "item-category", "quantity", "journal", "output","address","data-root"], StringComparer.Ordinal);
    for (var index = 0; index < args.Length; index++)
    {
        if (!args[index].StartsWith("--", StringComparison.Ordinal)) throw new ArgumentException(AppText.Get("Program.Text060"));
        var key = args[index][2..];
        if (!known.Contains(key)) throw new ArgumentException(AppText.Get("Program.Text061") + key);
        var value = key == "password-stdin" ? null : ++index < args.Length ? args[index] : throw new ArgumentException(AppText.Get("Program.Text062") + key);
        if (!result.TryAdd(key, value)) throw new ArgumentException(AppText.Get("Program.Text063") + key);
    }
    return result;
}
static string Required(Dictionary<string, string?> options, string key) => options.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value) ? value : throw new ArgumentException(AppText.Get("Program.Text064") + key);
static void Print(JsonNode value) => Console.WriteLine(value.ToJsonString(ClientJson.Options));