stan44 e0f298ba36 Add LyricFlow .NET backend API and Python bridge integration
- introduce `LyricFlow.Core.Backend` with shared DTOs, rhyme/spellcheck engines, and REST endpoints
- wire Python GUI/core to run and call the backend via new bridge/client modules
- add backend parity/integration tests and update packaging/ignore settings
2026-03-15 01:44:56 -05:00

142 lines
3.4 KiB
C#

using System.Text.Json;
using LyricFlow.Core.Dtos;
using LyricFlow.Core.Serialization;
namespace LyricFlow.Core.Services;
public class SessionStoreService
{
public const string GlobalWorkspaceKey = "__global__";
private readonly string _storagePath;
// MARK: - Lifecycle
#region Lifecycle
public SessionStoreService(string? storagePath = null)
{
_storagePath = storagePath ?? Path.Combine(AppPaths.AppDataDirectory(), "session_snapshots.json");
var directory = Path.GetDirectoryName(_storagePath);
if (!string.IsNullOrWhiteSpace(directory))
{
Directory.CreateDirectory(directory);
}
}
#endregion
// MARK: - Public Operations
#region Public Operations
public List<SessionTabSnapshotDto> Load(string? workspaceRoot)
{
var payload = ReadPayload();
return payload.Workspaces.TryGetValue(WorkspaceKey(workspaceRoot), out var snapshots) ? snapshots : [];
}
public void Save(string? workspaceRoot, List<SessionTabSnapshotDto> snapshots)
{
var payload = ReadPayload();
var key = WorkspaceKey(workspaceRoot);
if (snapshots.Count == 0)
{
payload.Workspaces.Remove(key);
}
else
{
payload.Workspaces[key] = snapshots;
}
WritePayload(payload);
}
public void Clear(string? workspaceRoot = null)
{
if (workspaceRoot is null)
{
if (File.Exists(_storagePath))
{
File.Delete(_storagePath);
}
return;
}
var payload = ReadPayload();
payload.Workspaces.Remove(WorkspaceKey(workspaceRoot));
if (payload.Workspaces.Count == 0)
{
if (File.Exists(_storagePath))
{
File.Delete(_storagePath);
}
return;
}
WritePayload(payload);
}
#endregion
// MARK: - Payload Persistence
#region Payload Persistence
private SessionPayload ReadPayload()
{
if (!File.Exists(_storagePath))
{
return new SessionPayload();
}
try
{
var payload = JsonSerializer.Deserialize(File.ReadAllText(_storagePath), LyricFlowCoreJsonContext.Default.SessionPayload);
return payload ?? new SessionPayload();
}
catch (IOException)
{
return new SessionPayload();
}
catch (JsonException)
{
return new SessionPayload();
}
}
private void WritePayload(SessionPayload payload)
{
payload.Version = 1;
File.WriteAllText(_storagePath, JsonSerializer.Serialize(payload, LyricFlowCoreJsonContext.Default.SessionPayload));
}
#endregion
// MARK: - Workspace Keys
#region Workspace Keys
private static string WorkspaceKey(string? workspaceRoot)
{
if (string.IsNullOrWhiteSpace(workspaceRoot))
{
return GlobalWorkspaceKey;
}
var fullPath = Path.GetFullPath(workspaceRoot);
return OperatingSystem.IsWindows() ? fullPath.ToLowerInvariant() : fullPath;
}
#endregion
// MARK: - Payload Model
#region Payload Model
#endregion
}
internal sealed class SessionPayload
{
public int Version { get; set; } = 1;
public Dictionary<string, List<SessionTabSnapshotDto>> Workspaces { get; set; } = new(StringComparer.OrdinalIgnoreCase);
}