diff --git a/StabilityMatrix.Core/Database/LiteDbContext.cs b/StabilityMatrix.Core/Database/LiteDbContext.cs index 0e187e84..5c50bfff 100644 --- a/StabilityMatrix.Core/Database/LiteDbContext.cs +++ b/StabilityMatrix.Core/Database/LiteDbContext.cs @@ -1,4 +1,6 @@ -using LiteDB.Async; +using LiteDB; +using LiteDB.Async; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Models.Api; @@ -10,27 +12,12 @@ namespace StabilityMatrix.Core.Database; public class LiteDbContext : ILiteDbContext { + private readonly ILogger logger; private readonly ISettingsManager settingsManager; private readonly DebugOptions debugOptions; private LiteDatabaseAsync? database; - public LiteDatabaseAsync Database - { - get - { - if (database != null) return database; - - var connectionString = debugOptions.TempDatabase ? ":temp:" - : $"Filename={Path.Combine(settingsManager.LibraryDir, "StabilityMatrix.db")};Mode=Shared"; - database = new LiteDatabaseAsync(connectionString); - - // Register reference fields - LiteDBExtensions.Register(m => m.ModelVersions, "CivitModelVersions"); - LiteDBExtensions.Register(e => e.Items, "CivitModels"); - - return database; - } - } + public LiteDatabaseAsync Database => database ??= CreateDatabase(); // Notification events public event EventHandler? CivitModelsChanged; @@ -41,11 +28,49 @@ public class LiteDbContext : ILiteDbContext public ILiteCollectionAsync CivitModelQueryCache => Database.GetCollection("CivitModelQueryCache"); public ILiteCollectionAsync GithubCache => Database.GetCollection("GithubCache"); - public LiteDbContext(ISettingsManager settingsManager, IOptions debugOptions) + public LiteDbContext( + ILogger logger, + ISettingsManager settingsManager, + IOptions debugOptions) { + this.logger = logger; this.settingsManager = settingsManager; this.debugOptions = debugOptions.Value; } + + private LiteDatabaseAsync CreateDatabase() + { + LiteDatabaseAsync? db = null; + + if (debugOptions.TempDatabase) + { + db = new LiteDatabaseAsync(":temp:"); + } + + // Attempt to create connection, might be in use + try + { + var dbPath = Path.Combine(settingsManager.LibraryDir, "StabilityMatrix.db"); + db = new LiteDatabaseAsync(new ConnectionString() + { + Filename = dbPath, + Connection = ConnectionType.Shared, + }); + } + catch (IOException e) + { + logger.LogWarning("Database in use or not accessible ({Message}), using temporary database", e.Message); + } + + // Fallback to temporary database + db ??= new LiteDatabaseAsync(":temp:"); + + // Register reference fields + LiteDBExtensions.Register(m => m.ModelVersions, "CivitModelVersions"); + LiteDBExtensions.Register(e => e.Items, "CivitModels"); + + return db; + } public async Task<(CivitModel?, CivitModelVersion?)> FindCivitModelFromFileHashAsync(string hashBlake3) { @@ -54,22 +79,26 @@ public class LiteDbContext : ILiteDbContext .Select(f => f.Hashes) .Select(hashes => hashes.BLAKE3) .Any(hash => hash == hashBlake3)) - .FirstOrDefaultAsync(); + .FirstOrDefaultAsync() + .ConfigureAwait(false); + if (version is null) return (null, null); + var model = await CivitModels.Query() .Include(m => m.ModelVersions) .Where(m => m.ModelVersions! .Select(v => v.Id) .Any(id => id == version.Id)) - .FirstOrDefaultAsync(); + .FirstOrDefaultAsync().ConfigureAwait(false); + return (model, version); } public async Task UpsertCivitModelAsync(CivitModel civitModel) { // Insert model versions first then model - var versionsUpdated = await CivitModelVersions.UpsertAsync(civitModel.ModelVersions); - var updated = await CivitModels.UpsertAsync(civitModel); + var versionsUpdated = await CivitModelVersions.UpsertAsync(civitModel.ModelVersions).ConfigureAwait(false); + var updated = await CivitModels.UpsertAsync(civitModel).ConfigureAwait(false); // Notify listeners on any change var anyUpdated = versionsUpdated > 0 || updated; if (anyUpdated) @@ -84,8 +113,8 @@ public class LiteDbContext : ILiteDbContext var civitModelsArray = civitModels.ToArray(); // Get all model versions then insert models var versions = civitModelsArray.SelectMany(model => model.ModelVersions ?? new()); - var versionsUpdated = await CivitModelVersions.UpsertAsync(versions); - var updated = await CivitModels.UpsertAsync(civitModelsArray); + var versionsUpdated = await CivitModelVersions.UpsertAsync(versions).ConfigureAwait(false); + var updated = await CivitModels.UpsertAsync(civitModelsArray).ConfigureAwait(false); // Notify listeners on any change var anyUpdated = versionsUpdated > 0 || updated > 0; if (updated > 0 || versionsUpdated > 0) @@ -98,7 +127,7 @@ public class LiteDbContext : ILiteDbContext // Add to cache public async Task UpsertCivitModelQueryCacheEntryAsync(CivitModelQueryCacheEntry entry) { - var changed = await CivitModelQueryCache.UpsertAsync(entry); + var changed = await CivitModelQueryCache.UpsertAsync(entry).ConfigureAwait(false); if (changed) { CivitModelsChanged?.Invoke(this, EventArgs.Empty); @@ -107,8 +136,14 @@ public class LiteDbContext : ILiteDbContext return changed; } - public Task GetGithubCacheEntry(string cacheKey) => - GithubCache.FindByIdAsync(cacheKey); + public async Task GetGithubCacheEntry(string cacheKey) + { + if (await GithubCache.FindByIdAsync(cacheKey).ConfigureAwait(false) is { } result) + { + return result; + } + return null; + } public Task UpsertGithubCacheEntry(GithubCacheEntry cacheEntry) => GithubCache.UpsertAsync(cacheEntry);