namespace XFEExtension.NetCore.AutoConfig;
///
/// 为同一种配置类型创建相互独立的实例和文件存储。适用于多租户、多账号或多工作区场景。
///
/// 配置类型
public sealed class ProfileStore where TProfile : XFEProfile, new()
{
private readonly object syncRoot = new();
private readonly Func profileFactory;
private readonly string profilePath;
private TProfile current;
///
/// 创建配置存储。
///
/// 包含扩展名的完整配置文件路径
/// 是否在创建时读取文件
/// 可选实例工厂;省略时调用公共无参构造函数
public ProfileStore(string profilePath, bool autoLoad = true, Func? profileFactory = null)
{
ArgumentException.ThrowIfNullOrWhiteSpace(profilePath);
this.profilePath = Path.GetFullPath(profilePath);
this.profileFactory = profileFactory ?? (static () => new TProfile());
current = CreateProfile();
if (autoLoad)
current = (TProfile)current.InstanceLoadProfile(CreateProfile);
}
/// 实际使用的完整配置文件路径。
public string ProfilePath => profilePath;
/// 当前实例。加载或导入只有在迁移和验证成功后才会替换它。
public TProfile Current
{
get
{
lock (syncRoot)
return current;
}
}
/// 重新从文件加载配置。
public void Load()
{
lock (syncRoot)
current = (TProfile)current.InstanceLoadProfile(CreateProfile);
}
/// 立即保存当前配置。
public void Save()
{
lock (syncRoot)
current.InstanceSaveProfile();
}
/// 异步保存当前配置。
public Task SaveAsync(CancellationToken cancellationToken = default)
{
TProfile snapshot;
lock (syncRoot)
snapshot = current;
return snapshot.InstanceSaveProfileAsync(cancellationToken);
}
/// 等待调用前已经请求的自动保存完成。
public Task FlushAsync(CancellationToken cancellationToken = default)
{
TProfile snapshot;
lock (syncRoot)
snapshot = current;
return snapshot.InstanceFlushProfileAsync(cancellationToken);
}
/// 删除此存储对应的配置文件。
public void Delete()
{
lock (syncRoot)
current.InstanceDeleteProfile();
}
/// 导出包含版本元数据的配置文本。
public string Export()
{
lock (syncRoot)
return current.InstanceExportProfile();
}
/// 以原始字节导出包含版本元数据的配置;MessagePack 模式不会产生 Base64 中间文本。
public byte[] ExportBytes()
{
lock (syncRoot)
return current.InstanceExportProfileBytes();
}
/// 导入配置文本;迁移或验证失败时保持当前实例不变。
public void Import(string profileContent)
{
ArgumentNullException.ThrowIfNull(profileContent);
lock (syncRoot)
current = (TProfile)current.InstanceImportProfile(profileContent, CreateProfile);
}
/// 从原始字节导入配置;迁移或验证失败时保持当前实例不变。
public void ImportBytes(ReadOnlyMemory profileContent)
{
lock (syncRoot)
current = (TProfile)current.InstanceImportProfileBytes(profileContent, CreateProfile);
}
///
/// 在实例锁内修改配置,并在修改成功后请求一次合并自动保存。
///
public void Update(Action update)
{
ArgumentNullException.ThrowIfNull(update);
lock (syncRoot)
lock (current.ProfileSyncRoot)
{
update(current);
current.InstanceRequestSaveProfile();
}
}
/// 在实例锁内读取配置。
public TResult Read(Func read)
{
ArgumentNullException.ThrowIfNull(read);
lock (syncRoot)
lock (current.ProfileSyncRoot)
return read(current);
}
private TProfile CreateProfile()
{
var profile = profileFactory() ?? throw new InvalidOperationException("配置实例工厂返回了 null");
profile.Initialize();
profile.CurrentProfilePath = profilePath;
return profile;
}
}