Innovenergy_trunk/csharp/App/Backend/Database/Db.cs

235 lines
7.7 KiB
C#

using System.Reactive.Concurrency;
using System.Reactive.Linq;
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;
//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>();
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>();
//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);
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 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>();
});
UpdateKeys().SupressAwaitWarning();
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 UpdateKeys()
{
while (true)
{
try
{
await UpdateS3Urls();
}
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 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);
}
}