using System.Text.Json; using XFEEDToolBox.Core.Data; using XFEEDToolBox.Core.Models; using XFEEDToolBox.Core.Navigation; internal static class NativeRepairAcceptance { public static async Task RunAsync(int pid,string address,string action,string path) { if(action is not("repair" or "integrity")||File.Exists(path)||File.Exists(path+".submitted.json"))throw new ArgumentException("A new bounded repair acceptance is required."); var settings=ToolboxSettings.Load(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),"XFEstudio","XFEEDToolBox","settings.json")); await using var journal=new JournalMonitor(settings.JournalDirectory);await journal.StartAsync();var initial=journal.State; if(!initial.InGame||!initial.Docked||initial.MarketId is not {} market||initial.CurrentShipId!=7||!initial.StationServicesKnown||!initial.StationServices.Contains("repair"))throw new InvalidOperationException("Actual docked acceptance ship and repair service required."); using var stop=new CancellationTokenSource(TimeSpan.FromSeconds(100)); await using var protection=await FlightTestProtectionScope.ArmAsync(pid);var pipe=new NavigationPipeClient(pid); async Task Wait(JsonElement queued) { var generation=queued.GetProperty("generation").GetUInt64(); while(true){var value=await pipe.CallAsync(new{op="commerce.market.status",generation},stop.Token);if(value.GetProperty("state").GetInt32()>=3)return value;await Task.Delay(80,stop.Token);} } Task Prices()=>ReadPrices(); async Task ReadPrices()=>await Wait(await pipe.CallAsync(new{op="station.services.inspect",marketId=(uint)market,maintenanceAddress=address},stop.Token)); var key=Guid.NewGuid().ToString("N");var started=DateTimeOffset.UtcNow;string? failure=null; JsonElement? before=null,quote=null,receipt=null,after=null,serverAfter=null; try { before=await pipe.CallAsync(new{op="station.services.inventory"},stop.Token);quote=await Prices(); var repair=quote.Value.GetProperty("servicePrices").GetProperty("repair");var costs=action=="integrity"?repair.GetProperty("shipIntegrityCosts"):repair;var cost=costs.GetProperty("costToRepair").GetInt64(); if(cost is <=0 or >5000)throw new InvalidOperationException("Expected a nonzero bounded original repair quote."); if(journal.State.LoadGameAt!=initial.LoadGameAt||journal.State.CurrentShipId!=initial.CurrentShipId||!journal.State.Docked||journal.State.MarketId!=market)throw new InvalidOperationException("Docking or session changed."); await File.WriteAllTextAsync(path+".submitted.json",JsonSerializer.Serialize(new{key,market,pid,started,action,before,cost,instruction="Never resend an uncertain original service operation."},ToolboxSettings.JsonOptions)); receipt=await Wait(await pipe.CallAsync(new{op="station.services",marketId=(uint)market,maintenanceAddress=address,action,operationKey=key},stop.Token)); if(receipt.Value.GetProperty("state").GetInt32()!=3||!receipt.Value.GetProperty("serverConfirmed").GetBoolean()||!receipt.Value.GetProperty("clientApplied").GetBoolean())throw new InvalidOperationException("Original repair reply unconfirmed; reconcile before any further mutation."); after=await pipe.CallAsync(new{op="station.services.inventory"},stop.Token); if(after.Value.GetProperty("credits").GetInt64()!=before.Value.GetProperty("credits").GetInt64()-cost||after.Value.GetProperty("cargoCount").GetInt32()!=before.Value.GetProperty("cargoCount").GetInt32())throw new InvalidOperationException("Actual native wallet or cargo disagrees with repair receipt."); serverAfter=await Prices();var nextRepair=serverAfter.Value.GetProperty("servicePrices").GetProperty("repair");var next=action=="integrity"?nextRepair.GetProperty("shipIntegrityCosts"):nextRepair; if(next.GetProperty("costToRepair").GetInt64()!=0||action=="integrity"&&next.GetProperty("wear").GetInt32()!=0)throw new InvalidOperationException("A second original server quote did not confirm the repair."); } catch(Exception error){failure=error.ToString();} var passed=failure is null;await File.WriteAllTextAsync(path,JsonSerializer.Serialize(new{pid,market,started,finished=DateTimeOffset.UtcNow,key,action,passed,before,quote,receipt,after,serverAfter,failure,screenUse=false,osInputsSent=0,journalEventsSynthesized=0},ToolboxSettings.JsonOptions)); Console.WriteLine(JsonSerializer.Serialize(new{passed,market,action,failure}));if(!passed)throw new InvalidOperationException("Native repair acceptance did not pass."); } }