97 lines
3.3 KiB
C#
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
|
|
};
|
|
}
|