feat: add IDataProvider interface and LocalJsonProvider with JSON file CRUD

One JSON file per machine named by GUID, stored in a configurable directory.
Supports save, load, list (as summaries), and delete with IO-error retry.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-27 20:19:56 -04:00
parent 98453243fc
commit a6e813bc85
3 changed files with 261 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
namespace OpenNest.Data;
public interface IDataProvider
{
IReadOnlyList<MachineSummary> GetMachines();
MachineConfig? GetMachine(Guid id);
void SaveMachine(MachineConfig machine);
void DeleteMachine(Guid id);
}

View File

@@ -0,0 +1,89 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace OpenNest.Data;
public class LocalJsonProvider : IDataProvider
{
private readonly string _directory;
private static readonly JsonSerializerOptions JsonOptions = new()
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }
};
public LocalJsonProvider(string directory)
{
_directory = directory;
Directory.CreateDirectory(_directory);
}
public IReadOnlyList<MachineSummary> GetMachines()
{
var summaries = new List<MachineSummary>();
foreach (var file in Directory.GetFiles(_directory, "*.json"))
{
var machine = ReadFile(file);
if (machine is not null)
summaries.Add(new MachineSummary(machine.Id, machine.Name));
}
return summaries;
}
public MachineConfig? GetMachine(Guid id)
{
var path = GetPath(id);
return File.Exists(path) ? ReadFile(path) : null;
}
public void SaveMachine(MachineConfig machine)
{
var json = JsonSerializer.Serialize(machine, JsonOptions);
var path = GetPath(machine.Id);
WriteWithRetry(path, json);
}
public void DeleteMachine(Guid id)
{
var path = GetPath(id);
if (File.Exists(path))
File.Delete(path);
}
private string GetPath(Guid id) => Path.Combine(_directory, $"{id}.json");
private static MachineConfig? ReadFile(string path)
{
try
{
var json = File.ReadAllText(path);
return JsonSerializer.Deserialize<MachineConfig>(json, JsonOptions);
}
catch (JsonException)
{
return null;
}
catch (IOException)
{
return null;
}
}
private static void WriteWithRetry(string path, string json, int maxRetries = 3)
{
for (var attempt = 0; attempt < maxRetries; attempt++)
{
try
{
File.WriteAllText(path, json);
return;
}
catch (IOException) when (attempt < maxRetries - 1)
{
Thread.Sleep(100);
}
}
}
}