Aetheria/Aetheria.State.Import/Program.cs
2026-06-13 05:53:18 +01:00

97 lines
3.3 KiB
C#

using System.Security.Cryptography;
using Aetheria.State;
using Aetheria.State.Documents;
using Aetheria.State.Migration;
var root = args.Length > 0 ? Path.GetFullPath(args[0]) : Directory.GetCurrentDirectory();
var statePath = args.Length > 1
? Path.GetFullPath(args[1])
: AetheriaStatePaths.ResolveDefaultStatePath(root);
var gameData = Path.Combine(root, "GameData");
var catalogPath = Path.Combine(gameData, "AetherDB.msgpack");
var nameFilesRoot = Path.Combine(gameData, "NameFile");
var capturedAtUtc = DateTimeOffset.UtcNow.ToString("O");
var catalog = CaptureFile(root, catalogPath);
var nameFiles = Directory.Exists(nameFilesRoot)
? Directory.EnumerateFiles(nameFilesRoot, "*.msgpack", SearchOption.TopDirectoryOnly)
.OrderBy(path => path, StringComparer.OrdinalIgnoreCase)
.Select(path => CaptureFile(root, path))
.ToArray()
: [];
await using var node = await AetheriaStateNode.OpenAsync(statePath, "aetheria-legacy-catalog-import");
await node.PutLegacyCatalogQuarantineAsync(new AetheriaLegacyCatalogQuarantine
{
RootPath = root,
CapturedAtUtc = capturedAtUtc,
CatalogFile = catalog.RelativePath,
CatalogFingerprint = catalog.Fingerprint,
CatalogBytes = catalog.Bytes,
NameFiles = nameFiles,
Notes =
[
"This document quarantines legacy catalog file facts only. It does not deserialize old DatabaseEntry payloads or grant old MessagePack files runtime state authority.",
"AetherDB.msgpack and NameFile/*.msgpack remain migration inputs until a bounded catalog mapper emits typed Aetheria item/faction/name documents."
]
});
await node.PutMigrationLedgerAsync(new AetheriaMigrationLedger
{
Source = LegacyMigrationBoundary.LegacyGameDataFile,
SourceFingerprint = catalog.Fingerprint,
LastMigrationAtUtc = capturedAtUtc,
Counts =
[
new AetheriaMigrationCount
{
DocumentType = "aetheria.legacy_catalog_quarantine.v1",
Count = 1
},
new AetheriaMigrationCount
{
DocumentType = "legacy.catalog_file",
Count = catalog.Bytes > 0 ? 1 : 0
},
new AetheriaMigrationCount
{
DocumentType = "legacy.name_file",
Count = nameFiles.Length
}
],
Notes =
[
"Legacy catalog quarantine captured file fingerprints into typed CultCache state without reading old DatabaseEntry payloads.",
$"State path: {statePath}"
]
});
await node.FlushAsync();
Console.WriteLine($"Aetheria legacy catalog quarantine captured: {statePath}");
Console.WriteLine($"Catalog: {catalog.RelativePath} {catalog.Bytes} bytes {catalog.Fingerprint}");
Console.WriteLine($"Name files: {nameFiles.Length}");
static AetheriaLegacyCatalogFile CaptureFile(string root, string path)
{
if (!File.Exists(path))
{
return new AetheriaLegacyCatalogFile
{
RelativePath = Path.GetRelativePath(root, path).Replace('\\', '/'),
Fingerprint = "missing",
Bytes = 0
};
}
using var stream = File.OpenRead(path);
var hash = SHA256.HashData(stream);
return new AetheriaLegacyCatalogFile
{
RelativePath = Path.GetRelativePath(root, path).Replace('\\', '/'),
Fingerprint = Convert.ToHexString(hash).ToLowerInvariant(),
Bytes = stream.Length
};
}