- 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
142 lines
3.4 KiB
C#
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);
|
|
}
|