namespace GFramework.Game.Config;
///
/// 提供面向宿主的 YAML 文本校验入口,使保存前校验可以复用运行时同一套 schema 规则。
///
public static class YamlConfigTextValidator
{
// Cache parsed schemas by table/path plus last write time so save-path validation can
// avoid repeated disk IO and JSON parsing while still observing schema edits.
private static readonly ConcurrentDictionary SchemaCache = new();
///
/// 使用指定 schema 文件同步校验 YAML 文本。
///
/// 所属配置表名称。
/// Schema 文件绝对路径。
/// YAML 文件路径,仅用于诊断信息。
/// 待校验的 YAML 文本。
/// 当 或 为空白时抛出。
/// 当 或 为 时抛出。
/// 当 schema 文件不可用,或 YAML 内容与 schema 不匹配时抛出。
///
/// 同步加载 schema 并立即校验,适合非异步上下文;内部委托 执行校验逻辑。
///
public static void Validate(
string tableName,
string schemaPath,
string yamlPath,
string yamlText)
{
var schema = GetOrLoadSchema(tableName, schemaPath);
YamlConfigSchemaValidator.Validate(tableName, schema, yamlPath, yamlText);
}
///
/// 使用指定 schema 文件异步校验 YAML 文本。
///
/// 所属配置表名称。
/// Schema 文件绝对路径。
/// YAML 文件路径,仅用于诊断信息。
/// 待校验的 YAML 文本。
/// 取消令牌。
/// 表示异步校验操作的任务。
/// 当 或 为空白时抛出。
/// 当 或 为 时抛出。
/// 当 schema 文件不可用,或 YAML 内容与 schema 不匹配时抛出。
/// 当 已被触发时抛出。
///
/// 异步加载 schema(调用 )后同步执行校验,适合 I/O 密集场景;
/// 校验本身不涉及异步操作。
///
public static async Task ValidateAsync(
string tableName,
string schemaPath,
string yamlPath,
string yamlText,
CancellationToken cancellationToken = default)
{
var schema = await GetOrLoadSchemaAsync(tableName, schemaPath, cancellationToken)
.ConfigureAwait(false);
YamlConfigSchemaValidator.Validate(tableName, schema, yamlPath, yamlText);
}
///
/// 获取可复用的 schema 模型,必要时从磁盘重新加载。
///
/// 所属配置表名称。
/// Schema 文件绝对路径。
/// 与当前 schema 文件内容匹配的已解析模型。
/// 当 或 为空白时抛出。
/// 当 schema 文件不可用或内容非法时抛出。
private static YamlConfigSchema GetOrLoadSchema(
string tableName,
string schemaPath)
{
var cacheKey = CreateCacheKey(tableName, schemaPath);
if (TryGetCachedSchema(cacheKey, out var cachedSchema))
{
return cachedSchema;
}
var schema = YamlConfigSchemaValidator.Load(tableName, schemaPath);
CacheSchema(cacheKey, schema);
return schema;
}
///
/// 异步获取可复用的 schema 模型,必要时从磁盘重新加载。
///
/// 所属配置表名称。
/// Schema 文件绝对路径。
/// 取消令牌。
/// 与当前 schema 文件内容匹配的已解析模型。
/// 当 或 为空白时抛出。
/// 当 schema 文件不可用或内容非法时抛出。
private static async Task GetOrLoadSchemaAsync(
string tableName,
string schemaPath,
CancellationToken cancellationToken)
{
var cacheKey = CreateCacheKey(tableName, schemaPath);
if (TryGetCachedSchema(cacheKey, out var cachedSchema))
{
return cachedSchema;
}
var schema = await YamlConfigSchemaValidator.LoadAsync(tableName, schemaPath, cancellationToken)
.ConfigureAwait(false);
CacheSchema(cacheKey, schema);
return schema;
}
///
/// 创建 schema 缓存键,并提前执行与公开入口一致的参数契约检查。
///
/// 所属配置表名称。
/// Schema 文件绝对路径。
/// 用于缓存查找的稳定键。
/// 当 或 为空白时抛出。
private static SchemaCacheKey CreateCacheKey(
string tableName,
string schemaPath)
{
if (string.IsNullOrWhiteSpace(tableName))
{
throw new ArgumentException("Table name cannot be null or whitespace.", nameof(tableName));
}
if (string.IsNullOrWhiteSpace(schemaPath))
{
throw new ArgumentException("Schema path cannot be null or whitespace.", nameof(schemaPath));
}
return new SchemaCacheKey(tableName, schemaPath);
}
///
/// 尝试命中当前 schema 文件版本对应的缓存项。
///
/// 缓存键。
/// 命中的 schema;未命中时为 。
/// 当缓存项仍与当前文件时间戳一致时返回 。
private static bool TryGetCachedSchema(
SchemaCacheKey cacheKey,
out YamlConfigSchema schema)
{
var lastWriteTimeUtc = File.GetLastWriteTimeUtc(cacheKey.SchemaPath);
if (SchemaCache.TryGetValue(cacheKey, out var cacheEntry) &&
cacheEntry.LastWriteTimeUtc == lastWriteTimeUtc)
{
schema = cacheEntry.Schema;
return true;
}
schema = null!;
return false;
}
///
/// 使用最新的文件时间戳刷新 schema 缓存。
///
/// 缓存键。
/// 最新加载的 schema。
private static void CacheSchema(
SchemaCacheKey cacheKey,
YamlConfigSchema schema)
{
var lastWriteTimeUtc = File.GetLastWriteTimeUtc(cacheKey.SchemaPath);
SchemaCache[cacheKey] = new SchemaCacheEntry(lastWriteTimeUtc, schema);
}
///
/// 表示一个 schema 缓存键。
///
/// 所属配置表名称。
/// Schema 文件绝对路径。
private readonly record struct SchemaCacheKey(
string TableName,
string SchemaPath);
///
/// 表示一个带文件时间戳的 schema 缓存条目。
///
/// 加载时观察到的 schema 文件修改时间。
/// 已解析的 schema 模型。
private readonly record struct SchemaCacheEntry(
DateTime LastWriteTimeUtc,
YamlConfigSchema Schema);
}