more of J's code organization.

This commit is contained in:
stan44 2026-02-23 21:34:49 -06:00
parent 8171744438
commit c01548b764
14 changed files with 61 additions and 114 deletions

View File

@ -37,4 +37,3 @@ desktop.ini
# macOS
.DS_Store
journal-master\journal\tls_registry_backup_before_fix.txt

View File

@ -7,23 +7,7 @@ using Journal.Core.Services;
namespace Journal.Core;
public class Entry
{
private readonly IFragmentService _fragments;
private readonly IEntrySearchService _entrySearch;
private readonly IVaultStorageService _vaultStorage;
private readonly IJournalDatabaseService _database;
private readonly IJournalConfigService _config;
private readonly IAiService _ai;
private readonly ISpeechBridgeService _speech;
private readonly IEntryFileService _entryFiles;
private readonly CommandLogger _logger;
private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNameCaseInsensitive = true
};
public Entry(
public class Entry(
IFragmentService fragments,
IEntrySearchService entrySearch,
IVaultStorageService vaultStorage,
@ -33,17 +17,20 @@ public class Entry
ISpeechBridgeService speech,
IEntryFileService entryFiles,
CommandLogger logger)
{
private readonly IFragmentService _fragments = fragments;
private readonly IEntrySearchService _entrySearch = entrySearch;
private readonly IVaultStorageService _vaultStorage = vaultStorage;
private readonly IJournalDatabaseService _database = database;
private readonly IJournalConfigService _config = config;
private readonly IAiService _ai = ai;
private readonly ISpeechBridgeService _speech = speech;
private readonly IEntryFileService _entryFiles = entryFiles;
private readonly CommandLogger _logger = logger;
private static readonly JsonSerializerOptions JsonOptions = new()
{
_fragments = fragments;
_entrySearch = entrySearch;
_vaultStorage = vaultStorage;
_database = database;
_config = config;
_ai = ai;
_speech = speech;
_entryFiles = entryFiles;
_logger = logger;
}
PropertyNameCaseInsensitive = true
};
public async Task RunAsync()
{
@ -77,7 +64,7 @@ public class Entry
var correlationId = string.IsNullOrWhiteSpace(cmd.CorrelationId)
? Guid.NewGuid().ToString("N")
: cmd.CorrelationId.Trim();
_logger.LogStart(action, correlationId, cmd.Payload);
CommandLogger.LogStart(action, correlationId, cmd.Payload);
object? result;
try
@ -260,47 +247,47 @@ public class Entry
result = _database.HydrateWorkspace(dbHydratePayload.Password, dbHydratePayload.DataDirectory);
break;
default:
_logger.LogFailure(action, correlationId, "unknown_action");
CommandLogger.LogFailure(action, correlationId, "unknown_action");
return Error($"Unknown action: {action}");
}
}
catch (JsonException)
{
_logger.LogFailure(action, correlationId, "invalid_payload_json");
CommandLogger.LogFailure(action, correlationId, "invalid_payload_json");
return Error("Missing or invalid payload");
}
catch (ValidationException ex)
{
_logger.LogFailure(action, correlationId, "validation", ex.Message);
CommandLogger.LogFailure(action, correlationId, "validation", ex.Message);
return Error(ex.Message);
}
catch (ArgumentException ex)
{
_logger.LogFailure(action, correlationId, "argument", ex.Message);
CommandLogger.LogFailure(action, correlationId, "argument", ex.Message);
return Error(ex.Message);
}
catch (TimeoutException ex)
{
_logger.LogFailure(action, correlationId, "timeout", ex.Message);
CommandLogger.LogFailure(action, correlationId, "timeout", ex.Message);
return Error(ex.Message);
}
catch (InvalidOperationException ex)
{
_logger.LogFailure(action, correlationId, "invalid_operation", ex.Message);
CommandLogger.LogFailure(action, correlationId, "invalid_operation", ex.Message);
return Error(ex.Message);
}
catch (FileNotFoundException ex)
{
_logger.LogFailure(action, correlationId, "not_found", ex.Message);
CommandLogger.LogFailure(action, correlationId, "not_found", ex.Message);
return Error(ex.Message);
}
catch
{
_logger.LogFailure(action, correlationId, "internal_error");
CommandLogger.LogFailure(action, correlationId, "internal_error");
return Error("Internal error");
}
_logger.LogSuccess(action, correlationId);
CommandLogger.LogSuccess(action, correlationId);
return JsonSerializer.Serialize(new { ok = true, data = result });
}

View File

@ -7,9 +7,7 @@ public sealed class DiskEntryFileRepository : IEntryFileRepository
if (!Directory.Exists(dataDirectory))
return [];
return Directory.GetFiles(dataDirectory, "*.md")
.OrderBy(Path.GetFileName, StringComparer.Ordinal)
.ToArray();
return [.. Directory.GetFiles(dataDirectory, "*.md").OrderBy(Path.GetFileName, StringComparer.Ordinal)];
}
public string ReadFile(string filePath) => File.ReadAllText(filePath);

View File

@ -183,7 +183,7 @@ public class FileFragmentRepository : IFragmentRepository
return [];
var docs = JsonSerializer.Deserialize<List<FragmentDocument>>(json, _jsonOptions) ?? [];
return docs.Select(d => new Fragment(d.Id, d.Type, d.Description, d.Time, d.Tags)).ToList();
return [.. docs.Select(d => new Fragment(d.Id, d.Type, d.Description, d.Time, d.Tags))];
}
private void SaveStoreLocked()

View File

@ -5,18 +5,18 @@ namespace Journal.Core.Services;
public sealed class CommandLogger
{
public void LogStart(string action, string correlationId, JsonElement? payload)
public static void LogStart(string action, string correlationId, JsonElement? payload)
{
var redactedPayload = LogRedactor.RedactPayload(payload);
EmitLog("information", action, correlationId, "start", redactedPayload);
}
public void LogSuccess(string action, string correlationId)
public static void LogSuccess(string action, string correlationId)
{
EmitLog("information", action, correlationId, "success");
}
public void LogFailure(string action, string correlationId, string errorType, string? message = null)
public static void LogFailure(string action, string correlationId, string errorType, string? message = null)
{
var details = string.IsNullOrWhiteSpace(message)
? ""

View File

@ -2,18 +2,11 @@ using Journal.Core.Dtos;
namespace Journal.Core.Services;
public sealed class DisabledAiService : IAiService
public sealed class DisabledAiService(string provider, string message = "AI provider disabled.", bool healthy = true) : IAiService
{
private readonly string _provider;
private readonly string _message;
private readonly bool _healthy;
public DisabledAiService(string provider, string message = "AI provider disabled.", bool healthy = true)
{
_provider = string.IsNullOrWhiteSpace(provider) ? "none" : provider.Trim();
_message = string.IsNullOrWhiteSpace(message) ? "AI provider disabled." : message.Trim();
_healthy = healthy;
}
private readonly string _provider = string.IsNullOrWhiteSpace(provider) ? "none" : provider.Trim();
private readonly string _message = string.IsNullOrWhiteSpace(message) ? "AI provider disabled." : message.Trim();
private readonly bool _healthy = healthy;
public Task<AiHealthDto> HealthAsync(CancellationToken cancellationToken = default) =>
Task.FromResult(new AiHealthDto(_provider, Enabled: false, Healthy: _healthy, Message: _message));

View File

@ -2,16 +2,10 @@ using Journal.Core.Dtos;
namespace Journal.Core.Services;
public sealed class DisabledSpeechBridgeService : ISpeechBridgeService
public sealed class DisabledSpeechBridgeService(string provider = "none", string message = "Speech bridge is disabled.") : ISpeechBridgeService
{
private readonly string _provider;
private readonly string _message;
public DisabledSpeechBridgeService(string provider = "none", string message = "Speech bridge is disabled.")
{
_provider = string.IsNullOrWhiteSpace(provider) ? "none" : provider.Trim();
_message = string.IsNullOrWhiteSpace(message) ? "Speech bridge is disabled." : message.Trim();
}
private readonly string _provider = string.IsNullOrWhiteSpace(provider) ? "none" : provider.Trim();
private readonly string _message = string.IsNullOrWhiteSpace(message) ? "Speech bridge is disabled." : message.Trim();
public Task<SpeechDevicesResultDto> ListDevicesAsync(CancellationToken cancellationToken = default)
{

View File

@ -3,20 +3,16 @@ using Journal.Core.Repositories;
namespace Journal.Core.Services;
public sealed class EntryFileService : IEntryFileService
public sealed class EntryFileService(IEntryFileRepository repo) : IEntryFileService
{
private readonly IEntryFileRepository _repo;
public EntryFileService(IEntryFileRepository repo) =>
_repo = repo ?? throw new ArgumentNullException(nameof(repo));
private readonly IEntryFileRepository _repo = repo ?? throw new ArgumentNullException(nameof(repo));
public IReadOnlyList<EntryListItem> ListEntries(string dataDirectory)
{
return _repo.ListMarkdownFiles(dataDirectory)
return [.. _repo.ListMarkdownFiles(dataDirectory)
.Select(path => new EntryListItem(
FileName: _repo.GetFileName(path),
FilePath: _repo.GetFullPath(path)))
.ToArray();
FilePath: _repo.GetFullPath(path)))];
}
public EntryLoadResult LoadEntry(string filePath)

View File

@ -5,11 +5,9 @@ using Journal.Core.Repositories;
namespace Journal.Core.Services;
public class FragmentService : IFragmentService
public class FragmentService(IFragmentRepository repo) : IFragmentService
{
private readonly IFragmentRepository _repo;
public FragmentService(IFragmentRepository repo) => _repo = repo ?? throw new ArgumentNullException(nameof(repo));
private readonly IFragmentRepository _repo = repo ?? throw new ArgumentNullException(nameof(repo));
private static FragmentDto Map(Fragment f) => new(
f.Id,

View File

@ -5,7 +5,7 @@ using Microsoft.Data.Sqlite;
namespace Journal.Core.Services;
public sealed class JournalDatabaseService : IJournalDatabaseService
public sealed class JournalDatabaseService(IJournalConfigService config) : IJournalDatabaseService
{
public const int KeySize = 32;
public const int Iterations = 600_000;
@ -15,12 +15,7 @@ public sealed class JournalDatabaseService : IJournalDatabaseService
private static readonly IReadOnlyList<string> RequiredSchemaTables =
["entries", "sections", "fragments", "tags", "fragment_tags"];
private readonly IJournalConfigService _config;
public JournalDatabaseService(IJournalConfigService config)
{
_config = config;
}
private readonly IJournalConfigService _config = config;
public string GetDatabasePath(string? dataDirectory = null)
{

View File

@ -4,19 +4,14 @@ using Journal.Core.Models;
namespace Journal.Core.Services;
public sealed class PythonSidecarClient
public sealed class PythonSidecarClient(JournalConfig config)
{
private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNameCaseInsensitive = true
};
private readonly JournalConfig _config;
public PythonSidecarClient(JournalConfig config)
{
_config = config;
}
private readonly JournalConfig _config = config;
public async Task<JsonElement?> SendAsync(string action, object payload, CancellationToken cancellationToken)
{

View File

@ -3,18 +3,11 @@ using Journal.Core.Dtos;
namespace Journal.Core.Services;
public sealed class SidecarCli
public sealed class SidecarCli(IVaultStorageService vaultStorage, IEntrySearchService entrySearch, IJournalConfigService config)
{
private readonly IVaultStorageService _vaultStorage;
private readonly IEntrySearchService _entrySearch;
private readonly IJournalConfigService _config;
public SidecarCli(IVaultStorageService vaultStorage, IEntrySearchService entrySearch, IJournalConfigService config)
{
_vaultStorage = vaultStorage;
_entrySearch = entrySearch;
_config = config;
}
private readonly IVaultStorageService _vaultStorage = vaultStorage;
private readonly IEntrySearchService _entrySearch = entrySearch;
private readonly IJournalConfigService _config = config;
public async Task<int> RunAsync(string[] args, Entry entry)
{
@ -34,9 +27,9 @@ public sealed class SidecarCli
}
if (string.Equals(args[0], "vault", StringComparison.OrdinalIgnoreCase))
return RunVaultCommand(args.Skip(1).ToArray());
return RunVaultCommand([.. args.Skip(1)]);
if (string.Equals(args[0], "search", StringComparison.OrdinalIgnoreCase))
return RunSearchCommand(args.Skip(1).ToArray());
return RunSearchCommand([.. args.Skip(1)]);
Console.Error.WriteLine($"Unknown command: {args[0]}");
PrintUsage();
@ -60,7 +53,7 @@ public sealed class SidecarCli
return 2;
}
if (!TryParseVaultOptions(args.Skip(1).ToArray(), out var options, out var parseError))
if (!TryParseVaultOptions([.. args.Skip(1)], out var options, out var parseError))
{
Console.Error.WriteLine(parseError);
PrintVaultUsage();

View File

@ -6,14 +6,12 @@ using System.Threading;
namespace Journal.Core.Services;
public class VaultStorageService : IVaultStorageService
public class VaultStorageService(IVaultCryptoService crypto) : IVaultStorageService
{
private readonly IVaultCryptoService _crypto;
private readonly IVaultCryptoService _crypto = crypto;
private readonly Dictionary<string, string> _monthFingerprintCache = new(StringComparer.Ordinal);
private readonly object _vaultIoLock = new();
public VaultStorageService(IVaultCryptoService crypto) => _crypto = crypto;
public string GetMonthlyVaultFileName(DateTime date) => date.ToString("yyyy-MM") + ".vault";
public bool LoadAllVaults(string password, string vaultDirectory, string dataDirectory)

View File

@ -2,4 +2,5 @@
<Project Path="Journal.Api/Journal.Api.csproj" />
<Project Path="Journal.Core/Journal.Core.csproj" />
<Project Path="Journal.Sidecar/Journal.Sidecar.csproj" />
<Project Path="Journal.SmokeTests/Journal.SmokeTests.csproj" />
</Solution>