using System.Linq; using SQLite; namespace ParadoxSaveParser.WebAPI.Database; public class DatabaseConnector { private readonly int _uploadsLifetimeDays; private readonly SQLiteAsyncConnection _db; private readonly ContextLogger _logger; public DatabaseConnector(string databasePath, int uploadsLifetimeDays, ILogger logger) { _uploadsLifetimeDays = uploadsLifetimeDays; _db = new SQLiteAsyncConnection(databasePath); _logger = new ContextLogger("Database", logger); } public async Task InitializeAsync() { await _db.CreateTableAsync(); } public async Task GetMetadata(string id) { return (await _db.QueryAsync( "select * from SaveFileMetadata where id = ?", id)) .FirstOrDefault(); } public async Task CreateMetadata(Game game) { var meta = new SaveFileMetadata { id = Guid.NewGuid().ToString(), game = game, status = SaveFileProcessingStatus.Initialized, uploadDateTime = DateTime.Now }; await _db.InsertAsync(meta); return meta; } public async Task UpdateMetadataStatus(SaveFileMetadata meta, SaveFileProcessingStatus status) { meta.status = status; await _db.UpdateAsync(meta); } public async Task SetMetadataError(SaveFileMetadata meta, string errorMessage) { meta.errorMessage = errorMessage; await UpdateMetadataStatus(meta, SaveFileProcessingStatus.Error); DeleteAssociatedFiles(meta); } public async Task DeleteMetadata(SaveFileMetadata meta) { _logger.LogDebug($"Deleting save file (id: {meta.id} status: {meta.status} " + $"uploadDate: {meta.uploadDateTime:yyyy/MM/dd})"); await _db.DeleteAsync(meta); DeleteAssociatedFiles(meta); } /// /// WARNING: Call this method only when no parsing operations are running. /// public async Task DeleteInvalidData() { _logger.LogInfo("Deleting invalid data..."); var expirationDate = DateTime.Now.AddDays(-_uploadsLifetimeDays); var metadataTable = _db.Table(); int rowCount = await metadataTable.CountAsync(); int i = 0; int deleteCount = 0; while(i < rowCount) { var meta = await metadataTable.ElementAtAsync(i)!; if(meta.status != SaveFileProcessingStatus.Done || meta.uploadDateTime < expirationDate || !meta.AssociatedFilesExist()) { deleteCount++; await DeleteMetadata(meta); } i++; } _logger.LogInfo($"Deleted {deleteCount} invalid records"); } private void TryDeleteFile(IOPath file) { if (!File.Exists(file)) return; _logger.LogDebug($"Deleting file '{file}'"); File.Delete(file); } private void DeleteAssociatedFiles(SaveFileMetadata meta) { TryDeleteFile(meta.GetSaveFilePath()); TryDeleteFile(meta.GetParsedDataPath()); } }