namespace AIStudio.Assistants.ModelComparison;
public sealed partial class ModelComparisonStore
{
///
/// The folder of the presets, one file per preset.
///
private const string PRESETS_DIRECTORY_NAME = "presets";
///
/// Gets the folder of the presets.
///
private string PresetsDirectory => Path.Combine(this.RootDirectory, PRESETS_DIRECTORY_NAME);
///
/// Gets the file of a preset.
///
/// The ID of the preset.
private string PresetPath(Guid presetId) => Path.Combine(this.PresetsDirectory, $"{presetId:D}.json");
///
/// Lists the presets, sorted by name.
///
///
/// A preset this version cannot read is left out, but stays on the disk, see ModelComparisonJson.
///
/// The cancellation token.
/// The presets.
public async Task> ListPresetsAsync(CancellationToken token = default)
{
await this.InitializeAsync(token);
if (!Directory.Exists(this.PresetsDirectory))
return [];
List presets = [];
foreach (var path in Directory.EnumerateFiles(this.PresetsDirectory, "*.json"))
{
token.ThrowIfCancellationRequested();
if (!Guid.TryParseExact(Path.GetFileNameWithoutExtension(path), "D", out var presetId))
continue;
// The ID inside the file must not lead to another file than the one it was read from:
if (await this.ReadJsonAsync(path, token) is { } preset)
presets.Add(preset with { Id = presetId });
}
return [.. presets.OrderBy(preset => preset.Name, StringComparer.CurrentCultureIgnoreCase)];
}
///
/// Stores a preset, as a new one or in place of the one with the same ID.
///
/// The preset.
/// The cancellation token.
/// The preset has no ID or no name.
public async Task SavePresetAsync(ModelComparisonPreset preset, CancellationToken token = default)
{
if (preset.Id == Guid.Empty)
throw new ArgumentException("A preset needs an ID.", nameof(preset));
if (string.IsNullOrWhiteSpace(preset.Name))
throw new ArgumentException("A preset needs a name.", nameof(preset));
await this.InitializeAsync(token);
var gate = this.GetLock(preset.Id);
await gate.WaitAsync(token);
try
{
await WriteJsonAtomicAsync(this.PresetPath(preset.Id), preset with { Name = preset.Name.Trim() }, token);
}
finally
{
gate.Release();
}
}
///
/// Deletes a preset.
///
/// The ID of the preset.
/// The cancellation token.
public async Task DeletePresetAsync(Guid presetId, CancellationToken token = default)
{
await this.InitializeAsync(token);
var gate = this.GetLock(presetId);
await gate.WaitAsync(token);
try
{
var path = this.PresetPath(presetId);
if (File.Exists(path))
File.Delete(path);
}
finally
{
gate.Release();
this.ForgetLock(presetId);
}
}
}