XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Text.Json;

namespace XFEEDToolBox.Core.Execution;

public sealed record TradeJourneyCheckpoint(string Commander,long ShipId,DateTimeOffset StartedAt,
    ConfirmedTradeReceipt? Bought=null,ConfirmedTradeReceipt? Sold=null);

/// <summary>Durable journey state; reloading never changes a confirmed order's identity or session.</summary>
public static class TradeJourneyCheckpoints
{
    private static readonly JsonSerializerOptions Json=new(JsonSerializerDefaults.Web){WriteIndented=true};

    public static TradeJourneyCheckpoint Load(string path)
    {
        var value=JsonSerializer.Deserialize<TradeJourneyCheckpoint>(File.ReadAllText(path),Json)
            ??throw new InvalidDataException("跑商恢复记录为空。");
        Validate(value);return value;
    }

    public static void Save(string path,TradeJourneyCheckpoint value)
    {
        Validate(value);path=Path.GetFullPath(path);Directory.CreateDirectory(Path.GetDirectoryName(path)!);
        var temporary=path+"."+Guid.NewGuid().ToString("N")+".tmp";
        try
        {
            using(var file=new FileStream(temporary,FileMode.CreateNew,FileAccess.Write,FileShare.Read,4096,FileOptions.WriteThrough))
            {JsonSerializer.Serialize(file,value,Json);file.Flush(true);}
            File.Move(temporary,path,true);
        }
        finally{if(File.Exists(temporary))File.Delete(temporary);}
    }

    private static void Validate(TradeJourneyCheckpoint value)
    {
        if(string.IsNullOrWhiteSpace(value.Commander)||value.ShipId<0||value.StartedAt==default||value.Sold is not null&&value.Bought is null)
            throw new InvalidDataException("跑商恢复记录缺少原始指挥官、飞船或买入回执。");
        void Receipt(ConfirmedTradeReceipt receipt,bool buy)
        {
            if(!Guid.TryParseExact(receipt.OperationKey,"N",out _)||!receipt.ServerConfirmed||!receipt.ClientApplied
                ||receipt.CommanderId!=value.Commander||receipt.ShipId!=value.ShipId||receipt.MarketId<=0||string.IsNullOrWhiteSpace(receipt.Commodity)
                ||(buy?receipt.QuantityDelta<=0:receipt.QuantityDelta>=0)||receipt.UnitPrice<=0||receipt.CreditsBefore<0||receipt.CreditsAfter<0
                ||receipt.CargoBefore<0||receipt.CargoAfter<0||(long)receipt.CargoAfter-receipt.CargoBefore!=receipt.QuantityDelta
                ||(decimal)receipt.CreditsAfter-receipt.CreditsBefore!=-(decimal)receipt.UnitPrice*receipt.QuantityDelta
                ||receipt.SessionStartedAt==default||receipt.SessionStartedAt>receipt.ConfirmedAt||receipt.ConfirmedAt<value.StartedAt)
                throw new InvalidDataException("跑商恢复记录中的原始交易回执不一致。");
        }
        if(value.Bought is {} purchase)Receipt(purchase,true);
        if(value.Sold is {} sale)
        {
            Receipt(sale,false);var bought=value.Bought!;
            if(sale.OperationKey==bought.OperationKey||sale.Commodity!=bought.Commodity||(long)sale.QuantityDelta!=-((long)bought.QuantityDelta)||sale.ConfirmedAt<bought.ConfirmedAt)
                throw new InvalidDataException("跑商恢复记录中的买卖回执未对应同一批货物。");
        }
    }
}