using System.Text.Json; namespace XFEEDToolBox.Core.Galaxy; public sealed record GalaxyNativeCommodityOption(uint Uid,string Name,string Category,int Kind,bool? PublisherEligible); public sealed record GalaxyCommodityOptionsSnapshot(bool Available,IReadOnlyList Options,int UnresolvedCount) { public bool Complete=>false; } public sealed partial class NativeGalaxyAccountCatalog { public async Task ReadCommodityOptionsAsync(CancellationToken token=default) { var page=await pipe.CallAsync(new{op="galaxy.commodities",limit=16},token); if(!page.GetProperty("available").GetBoolean())return new(false,[],0); var generation=page.GetProperty("generation").GetUInt64();var total=page.GetProperty("total").GetInt32();var entity=page.GetProperty("entityId").GetString();var unresolved=page.GetProperty("unresolvedCount").GetInt32(); if(generation==0||total is <0 or >4096||unresolved is <0 or >4096||string.IsNullOrEmpty(entity)||page.GetProperty("complete").GetBoolean())throw new InvalidDataException("原商品定义快照标识无效。"); var result=new List();var ids=new HashSet();var offset=0; while(true) { token.ThrowIfCancellationRequested(); if(!page.GetProperty("available").GetBoolean()||page.GetProperty("generation").GetUInt64()!=generation||page.GetProperty("entityId").GetString()!=entity||page.GetProperty("total").GetInt32()!=total||page.GetProperty("unresolvedCount").GetInt32()!=unresolved||page.GetProperty("complete").GetBoolean())throw new InvalidDataException("原商品定义读取期间来源发生变化。"); var items=page.GetProperty("items");if(items.ValueKind!=JsonValueKind.Array||items.GetArrayLength()>16)throw new InvalidDataException("原商品定义分页无效。"); foreach(var item in items.EnumerateArray()) { var uid=item.GetProperty("uid").GetUInt32();var name=item.GetProperty("name").GetString();var category=item.GetProperty("category").GetString();var kind=item.GetProperty("kind").GetInt32(); var eligibility=item.GetProperty("publisherEligible");bool? eligible=eligibility.ValueKind==JsonValueKind.Null?null:eligibility.GetBoolean(); if(uid==uint.MaxValue||!ids.Add(uid)||string.IsNullOrWhiteSpace(name)||name.Length>256||name.Any(char.IsControl)||category is null||category.Length>256||category.Any(char.IsControl)||kind is not(1 or 2)||kind==1&&eligible!=true)throw new InvalidDataException("原商品定义条目无效。"); result.Add(new(uid,name,category,kind,eligible)); } offset+=items.GetArrayLength();var next=page.GetProperty("nextOffset"); if(next.ValueKind==JsonValueKind.Null){if(offset!=total)throw new InvalidDataException("原商品定义缺失分页。");break;} if(items.GetArrayLength()==0||next.GetInt32()!=offset||offset>=total)throw new InvalidDataException("原商品定义分页顺序无效。"); page=await pipe.CallAsync(new{op="galaxy.commodities",limit=16,offset,generation},token); } return new(true,result,unresolved); } }