more of J's code organization.
This commit is contained in:
parent
8171744438
commit
c01548b764
1
journal-master/journal/.gitignore
vendored
1
journal-master/journal/.gitignore
vendored
@ -37,4 +37,3 @@ desktop.ini
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
journal-master\journal\tls_registry_backup_before_fix.txt
|
||||
@ -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 });
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
? ""
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user