diff --git a/Services/DatabaseService.cs b/Services/DatabaseService.cs new file mode 100644 index 0000000..a5b595e --- /dev/null +++ b/Services/DatabaseService.cs @@ -0,0 +1,31 @@ +using HermesSocketServer.Store; + +namespace HermesSocketServer.Services +{ + public class DatabaseService : BackgroundService + { + private readonly VoiceStore _voices; + private readonly Serilog.ILogger _logger; + + public DatabaseService(VoiceStore voices, Serilog.ILogger logger) { + _voices = voices; + _logger = logger; + } + + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + _logger.Information("Loading TTS voices..."); + await _voices.Load(); + _logger.Information("Loaded TTS voices."); + + await Task.Run(async () => + { + while (true) + { + await Task.Delay(TimeSpan.FromMinutes(1)); + await _voices.Save(); + } + }); + } + } +} \ No newline at end of file diff --git a/Startup.cs b/Startup.cs index 8046e02..4542978 100644 --- a/Startup.cs +++ b/Startup.cs @@ -13,6 +13,9 @@ using Serilog.Events; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; using Microsoft.AspNetCore.Connections; +using HermesSocketServer.Validators; +using HermesSocketServer.Store; +using HermesSocketServer.Services; var yamlDeserializer = new DeserializerBuilder() @@ -29,7 +32,7 @@ var configuration = yamlDeserializer.Deserialize(configCont if (configuration.Environment.ToUpper() != "QA" && configuration.Environment.ToUpper() != "PROD") throw new Exception("Invalid environment set."); -var builder = WebApplication.CreateBuilder(args); +var builder = WebApplication.CreateBuilder(); builder.Logging.ClearProviders(); builder.Services.Configure(options => @@ -57,7 +60,7 @@ builder.Host.UseSerilog(logger); builder.Logging.AddSerilog(logger); var s = builder.Services; -s.AddSerilog(); +s.AddSerilog(logger); s.AddSingleton(configuration); s.AddSingleton(); @@ -72,6 +75,13 @@ s.AddSingleton(); s.AddSingleton(); s.AddSingleton(); +// Validators +s.AddSingleton(); +s.AddSingleton(); + +// Stores +s.AddSingleton(); + // Request handlers s.AddSingleton(); s.AddSingleton(); @@ -102,6 +112,9 @@ s.AddSingleton(new JsonSerializerOptions() }); s.AddSingleton(); + +s.AddHostedService(); + var app = builder.Build(); app.UseForwardedHeaders(); app.UseSerilogRequestLogging(); @@ -122,7 +135,7 @@ app.Use(async (HttpContext context, RequestDelegate next) => { if (context.Request.Path != "/") { - context.Response.StatusCode = StatusCodes.Status403Forbidden; + context.Response.StatusCode = StatusCodes.Status401Unauthorized; return; } @@ -135,6 +148,7 @@ app.Use(async (HttpContext context, RequestDelegate next) => { context.Response.StatusCode = StatusCodes.Status400BadRequest; } + await next(context); }); await app.RunAsync(); \ No newline at end of file diff --git a/Store/IStore.cs b/Store/IStore.cs index 6c5d906..e34b284 100644 --- a/Store/IStore.cs +++ b/Store/IStore.cs @@ -6,7 +6,7 @@ namespace HermesSocketServer.Store IEnumerable Get(); Task Load(); void Remove(K? key); - Task Save(); + Task Save(); bool Set(K? key, V? value); } } \ No newline at end of file diff --git a/Store/VoiceStore.cs b/Store/VoiceStore.cs index 5c15223..3dad776 100644 --- a/Store/VoiceStore.cs +++ b/Store/VoiceStore.cs @@ -20,7 +20,7 @@ namespace HermesSocketServer.Store public DateTime PreviousSave; - public VoiceStore(Database database, IValidator voiceIdValidator, IValidator voiceNameValidator, Serilog.ILogger logger) + public VoiceStore(Database database, VoiceIdValidator voiceIdValidator, VoiceNameValidator voiceNameValidator, Serilog.ILogger logger) { _database = database; _voiceIdValidator = voiceIdValidator; @@ -56,6 +56,7 @@ namespace HermesSocketServer.Store var name = reader.GetString(1); _voices.Add(id, name); }); + _logger.Information($"Loaded {_voices.Count} TTS voices from database."); } public void Remove(string? key) @@ -78,13 +79,15 @@ namespace HermesSocketServer.Store } } - public async Task Save() + public async Task Save() { + var changes = false; var sb = new StringBuilder(); var sql = ""; if (_added.Any()) { + int count = _added.Count; sb.Append("INSERT INTO \"TtsVoice\" (id, name) VALUES "); lock (_lock) { @@ -107,16 +110,19 @@ namespace HermesSocketServer.Store try { + _logger.Debug($"About to save {count} voices to database."); await _database.ExecuteScalar(sql); } catch (Exception ex) { _logger.Error(ex, "Failed to save TTS voices on database: " + sql); } + changes = true; } if (_modified.Any()) { + int count = _modified.Count; sb.Append("UPDATE \"TtsVoice\" as t SET name = c.name FROM (VALUES "); lock (_lock) { @@ -140,16 +146,19 @@ namespace HermesSocketServer.Store try { + _logger.Debug($"About to update {count} voices on the database."); await _database.ExecuteScalar(sql); } catch (Exception ex) { _logger.Error(ex, "Failed to modify TTS voices on database: " + sql); } + changes = true; } if (_deleted.Any()) { + int count = _deleted.Count; sb.Append("DELETE FROM \"TtsVoice\" WHERE id IN ("); lock (_lock) { @@ -170,13 +179,16 @@ namespace HermesSocketServer.Store try { + _logger.Debug($"About to delete {count} voices from the database."); await _database.ExecuteScalar(sql); } catch (Exception ex) { _logger.Error(ex, "Failed to modify TTS voices on database: " + sql); } + changes = true; } + return changes; } public bool Set(string? key, string? value)