using InnovEnergy.App.Backend.DataTypes; using InnovEnergy.App.Backend.DataTypes.Methods; using InnovEnergy.App.Backend.Relations; using InnovEnergy.Lib.S3Utils; using InnovEnergy.Lib.S3Utils.DataTypes; using InnovEnergy.Lib.Utils; using SQLite; using SQLiteConnection = SQLite.SQLiteConnection; namespace InnovEnergy.App.Backend.Database; public static partial class Db { private static SQLiteConnection Connection { get; } = InitConnection(); private static SQLiteConnection InitConnection() { var latestDb = new DirectoryInfo("DbBackups") .GetFiles() .OrderBy(f => f.LastWriteTime) .Last().Name; Console.WriteLine("latestdb is "+latestDb); //This is the file connection from the DbBackups folder var fileConnection = new SQLiteConnection("DbBackups/" + latestDb); //Create a table if it does not exist fileConnection.CreateTable<User>(); fileConnection.CreateTable<Installation>(); fileConnection.CreateTable<Folder>(); fileConnection.CreateTable<FolderAccess>(); fileConnection.CreateTable<InstallationAccess>(); fileConnection.CreateTable<Session>(); fileConnection.CreateTable<OrderNumber2Installation>(); fileConnection.CreateTable<Error>(); fileConnection.CreateTable<Warning>(); fileConnection.CreateTable<UserAction>(); return fileConnection; //return CopyDbToMemory(fileConnection); } private static SQLiteConnection CopyDbToMemory(SQLiteConnection fileConnection) { var memoryConnection = new SQLiteConnection(":memory:"); //Create a table if it does not exist in main memory memoryConnection.CreateTable<User>(); memoryConnection.CreateTable<Installation>(); memoryConnection.CreateTable<Folder>(); memoryConnection.CreateTable<FolderAccess>(); memoryConnection.CreateTable<InstallationAccess>(); memoryConnection.CreateTable<Session>(); memoryConnection.CreateTable<OrderNumber2Installation>(); memoryConnection.CreateTable<Error>(); memoryConnection.CreateTable<Warning>(); fileConnection.CreateTable<UserAction>(); //Copy all the existing tables from the disk to main memory fileConnection.Table<Session>().ForEach(memoryConnection.Insert); fileConnection.Table<Folder>().ForEach(memoryConnection.Insert); fileConnection.Table<Installation>().ForEach(memoryConnection.Insert); fileConnection.Table<User>().ForEach(memoryConnection.Insert); fileConnection.Table<FolderAccess>().ForEach(memoryConnection.Insert); fileConnection.Table<InstallationAccess>().ForEach(memoryConnection.Insert); fileConnection.Table<OrderNumber2Installation>().ForEach(memoryConnection.Insert); fileConnection.Table<Error>().ForEach(memoryConnection.Insert); fileConnection.Table<Warning>().ForEach(memoryConnection.Insert); fileConnection.Table<UserAction>().ForEach(memoryConnection.Insert); return memoryConnection; } public static void BackupDatabase() { var filename = "db-" + DateTimeOffset.UtcNow.ToUnixTimeSeconds() + ".sqlite"; Connection.Backup("DbBackups/" + filename); } public static TableQuery<Session> Sessions => Connection.Table<Session>(); public static TableQuery<Folder> Folders => Connection.Table<Folder>(); public static TableQuery<Installation> Installations => Connection.Table<Installation>(); public static TableQuery<User> Users => Connection.Table<User>(); public static TableQuery<FolderAccess> FolderAccess => Connection.Table<FolderAccess>(); public static TableQuery<InstallationAccess> InstallationAccess => Connection.Table<InstallationAccess>(); public static TableQuery<OrderNumber2Installation> OrderNumber2Installation => Connection.Table<OrderNumber2Installation>(); public static TableQuery<Error> Errors => Connection.Table<Error>(); public static TableQuery<Warning> Warnings => Connection.Table<Warning>(); public static TableQuery<UserAction> UserActions => Connection.Table<UserAction>(); public static void Init() { // used to force static constructor //Since this class is static, we call Init method from the Program.cs to initialize all the fields of the class } //This is the constructor of the class static Db() { Connection.RunInTransaction(() => { Connection.CreateTable<User>(); Connection.CreateTable<Installation>(); Connection.CreateTable<Folder>(); Connection.CreateTable<FolderAccess>(); Connection.CreateTable<InstallationAccess>(); Connection.CreateTable<Session>(); Connection.CreateTable<OrderNumber2Installation>(); Connection.CreateTable<Error>(); Connection.CreateTable<Warning>(); Connection.CreateTable<UserAction>(); }); //UpdateKeys(); CleanupSessions().SupressAwaitWarning(); } private static async Task CleanupSessions() { while (true) { try { DeleteStaleSessions(); } catch(Exception e) { Console.WriteLine("An error has occured when cleaning stale sessions, exception is:\n"+e); } await Task.Delay(TimeSpan.FromHours(0.5)); } } private static async Task RemoveNonExistingKeys() { while (true) { try { var validReadKeys = Installations .Select(i => i.S3Key) .Distinct() .ToList(); var validWriteKeys = Installations .Select(i => i.S3WriteKey) .Distinct() .ToList(); Console.WriteLine("VALID READ KEYS"); for (int i = 0; i < validReadKeys.Count; i++) { Console.WriteLine(validReadKeys[i]); } Console.WriteLine("VALID WRITE KEYS"); for (int i = 0; i < validReadKeys.Count; i++) { Console.WriteLine(validWriteKeys[i]); } const String provider = "exo.io"; var S3keys = await ExoCmd.GetAccessKeys(); foreach (var keyMetadata in S3keys) { if (keyMetadata["key"].ToString()!="EXOa0b53cf10517307cec1bf00e" && !validReadKeys.Contains(keyMetadata["key"].ToString()) && !validWriteKeys.Contains(keyMetadata["key"].ToString())) { //await ExoCmd.RevokeReadKey(keyMetadata["key"].ToString()); Console.WriteLine("Deleted key "+keyMetadata["key"]); } } } catch(Exception e) { Console.WriteLine("An error has occured when updating S3 keys, exception is:\n"+e); } await Task.Delay(TimeSpan.FromHours(24)); } } private static async Task UpdateKeys() { while (true) { try { await UpdateS3Urls(); } catch(Exception e) { Console.WriteLine("An error has occured when updating S3 keys, exception is:\n"+e); } await RemoveNonExistingKeys(); await Task.Delay(TimeSpan.FromHours(24)); } } private static Boolean RunTransaction(Func<Boolean> func) { var savepoint = Connection.SaveTransactionPoint(); var success = false; try { success = func(); } finally { if (success) Connection.Release(savepoint); else Connection.RollbackTo(savepoint); } return success; } private static void DeleteStaleSessions() { var deadline = DateTime.Now.AddDays((-1) * Session.MaxAge.Days); Sessions.Delete(s => s.LastSeen < deadline); } private static async Task UpdateS3Urls() { var regions = Installations .Select(i => i.S3Region) .Distinct() .ToList(); const String provider = "exo.io"; Console.WriteLine("-----------------------UPDATED READ KEYS-------------------------------------------------------------------"); foreach (var region in regions) { var s3Region = new S3Region($"https://{region}.{provider}", ExoCmd.S3Credentials!); var bucketList = await s3Region.ListAllBuckets(); var installations = from bucket in bucketList.Buckets from installation in Installations where installation.BucketName() == bucket.BucketName select installation; foreach (var installation in installations) { await installation.RenewS3Credentials(); } } } public static async Task<Boolean> SendPasswordResetEmail(User user, String sessionToken) { try { await user.SendPasswordResetEmail(sessionToken); return true; } catch { return false; } } public static async Task<Boolean> SendNewUserEmail(User user) { try { await user.SendNewUserWelcomeMessage(); return true; } catch { return false; } } public static Boolean DeleteUserPassword(User user) { user.Password = ""; user.MustResetPassword = true; return Update(user); } }