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

310 lines
9.9 KiB
C#
Raw Normal View History

2023-03-15 13:38:06 +00:00
using InnovEnergy.App.Backend.DataTypes;
2023-03-16 09:34:47 +00:00
using InnovEnergy.App.Backend.DataTypes.Methods;
2023-03-15 13:38:06 +00:00
using InnovEnergy.App.Backend.Relations;
2023-10-16 09:27:19 +00:00
using InnovEnergy.Lib.S3Utils;
using InnovEnergy.Lib.S3Utils.DataTypes;
2023-10-26 12:09:38 +00:00
using InnovEnergy.Lib.Utils;
2023-02-16 12:57:06 +00:00
using SQLite;
using SQLiteConnection = SQLite.SQLiteConnection;
2023-02-16 12:57:06 +00:00
2023-03-08 12:20:33 +00:00
namespace InnovEnergy.App.Backend.Database;
2023-02-16 12:57:06 +00:00
2024-12-16 14:03:27 +00:00
//The methods of the Db class are located in multiple files (Create.cs, Read,cs, Delete.cs, Update.cs)
//That's why the class definition is partial
2023-11-20 16:29:45 +00:00
public static partial class Db
2023-02-16 12:57:06 +00:00
{
private static SQLiteConnection Connection { get; } = InitConnection();
2023-11-20 16:29:45 +00:00
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>();
2024-06-11 12:31:08 +00:00
public static TableQuery<UserAction> UserActions => Connection.Table<UserAction>();
2023-11-20 16:29:45 +00:00
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
//When a class is loaded, the fields are initialized before the constructor's code is executed.
//The TableQuery fields are lazy meaning that they will be initialized when they get accessed
2024-12-16 14:03:27 +00:00
//The connection searches for the latest backup and binds all the tables to it.
2023-03-23 12:28:55 +00:00
}
//This is the constructor of the class
2023-02-16 12:57:06 +00:00
static Db()
{
2023-03-15 13:38:06 +00:00
Connection.RunInTransaction(() =>
2023-02-16 12:57:06 +00:00
{
2023-03-15 13:38:06 +00:00
Connection.CreateTable<User>();
Connection.CreateTable<Installation>();
Connection.CreateTable<Folder>();
Connection.CreateTable<FolderAccess>();
Connection.CreateTable<InstallationAccess>();
2023-03-15 13:38:06 +00:00
Connection.CreateTable<Session>();
Connection.CreateTable<OrderNumber2Installation>();
Connection.CreateTable<Error>();
2023-11-20 16:29:45 +00:00
Connection.CreateTable<Warning>();
2024-06-11 12:31:08 +00:00
Connection.CreateTable<UserAction>();
2023-02-16 12:57:06 +00:00
});
2023-11-20 16:29:45 +00:00
//UpdateKeys();
2023-11-20 16:29:45 +00:00
CleanupSessions().SupressAwaitWarning();
DeleteSnapshots().SupressAwaitWarning();
}
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);
2023-11-20 16:29:45 +00:00
}
public static void BackupDatabase()
{
var filename = "db-" + DateTimeOffset.UtcNow.ToUnixTimeSeconds() + ".sqlite";
Connection.Backup("DbBackups/" + filename);
}
2024-12-16 14:03:27 +00:00
//Delete all except 10 snapshots every 24 hours.
private static async Task DeleteSnapshots()
{
while (true)
{
try
{
var files = new DirectoryInfo("DbBackups")
.GetFiles()
.OrderByDescending(f => f.LastWriteTime);
var filesToDelete = files.Skip(10);
foreach (var file in filesToDelete)
{
Console.WriteLine("File to delete is " + file.Name);
file.Delete();
}
}
catch(Exception e)
{
Console.WriteLine("An error has occured when cleaning database snapshots, exception is:\n"+e);
}
await Task.Delay(TimeSpan.FromHours(24));
}
}
//Delete all expired sessions every half an hour. An expired session is a session remained for more than 1 day.
2023-11-20 16:29:45 +00:00
private static async Task CleanupSessions()
{
while (true)
{
try
{
var deadline = DateTime.Now.AddDays(-Session.MaxAge.Days);
foreach (var session in Sessions)
{
if (session.LastSeen < deadline)
{
Console.WriteLine("Need to remove session of user id " + session.User.Name + "last time is "+session.LastSeen);
}
}
Sessions.Delete(s => s.LastSeen < deadline);
2023-11-20 16:29:45 +00:00
}
catch(Exception e)
{
Console.WriteLine("An error has occured when cleaning stale sessions, exception is:\n"+e);
}
2023-03-09 15:32:11 +00:00
2023-11-20 16:29:45 +00:00
await Task.Delay(TimeSpan.FromHours(0.5));
}
2023-02-16 12:57:06 +00:00
}
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));
}
}
2023-03-09 15:32:11 +00:00
2023-11-20 16:29:45 +00:00
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();
2023-11-20 16:29:45 +00:00
await Task.Delay(TimeSpan.FromHours(24));
}
}
2023-03-15 13:38:06 +00:00
private static Boolean RunTransaction(Func<Boolean> func)
2023-02-16 12:57:06 +00:00
{
2023-03-15 13:38:06 +00:00
var savepoint = Connection.SaveTransactionPoint();
var success = false;
2023-11-20 16:29:45 +00:00
2023-02-16 12:57:06 +00:00
try
{
2023-03-15 13:38:06 +00:00
success = func();
2023-02-16 12:57:06 +00:00
}
2023-03-15 13:38:06 +00:00
finally
2023-02-16 12:57:06 +00:00
{
2023-03-15 13:38:06 +00:00
if (success)
Connection.Release(savepoint);
else
Connection.RollbackTo(savepoint);
2023-02-16 12:57:06 +00:00
}
2023-03-09 15:32:11 +00:00
2023-03-15 13:38:06 +00:00
return success;
2023-02-16 12:57:06 +00:00
}
2023-11-20 16:29:45 +00:00
2023-03-09 11:50:21 +00:00
2023-07-06 08:57:57 +00:00
private static async Task UpdateS3Urls()
{
2023-10-16 09:27:19 +00:00
var regions = Installations
2023-11-20 16:29:45 +00:00
.Select(i => i.S3Region)
.Distinct()
.ToList();
2023-10-16 09:27:19 +00:00
const String provider = "exo.io";
2023-12-06 15:35:35 +00:00
Console.WriteLine("-----------------------UPDATED READ KEYS-------------------------------------------------------------------");
2023-11-20 16:29:45 +00:00
2023-10-16 09:27:19 +00:00
foreach (var region in regions)
2023-07-06 08:57:57 +00:00
{
2023-11-20 16:29:45 +00:00
var s3Region = new S3Region($"https://{region}.{provider}", ExoCmd.S3Credentials!);
2023-10-26 12:09:38 +00:00
var bucketList = await s3Region.ListAllBuckets();
2023-11-20 16:29:45 +00:00
var installations = from bucket in bucketList.Buckets
from installation in Installations
where installation.BucketName() == bucket.BucketName
select installation;
2023-10-26 12:09:38 +00:00
foreach (var installation in installations)
2023-10-16 09:27:19 +00:00
{
2023-10-26 12:09:38 +00:00
await installation.RenewS3Credentials();
2023-10-16 09:27:19 +00:00
}
2023-07-06 08:57:57 +00:00
}
}
2023-09-15 12:23:22 +00:00
2023-10-26 12:09:38 +00:00
public static async Task<Boolean> SendPasswordResetEmail(User user, String sessionToken)
2023-09-15 12:23:22 +00:00
{
2023-10-26 12:09:38 +00:00
try
{
await user.SendPasswordResetEmail(sessionToken);
return true;
}
2023-11-20 16:29:45 +00:00
catch
2023-10-26 12:09:38 +00:00
{
return false;
}
2023-09-15 12:23:22 +00:00
}
2023-11-20 16:29:45 +00:00
2023-10-26 12:09:38 +00:00
public static async Task<Boolean> SendNewUserEmail(User user)
2023-10-23 14:19:03 +00:00
{
2023-10-26 12:09:38 +00:00
try
{
await user.SendNewUserWelcomeMessage();
return true;
}
2023-11-20 16:29:45 +00:00
catch
2023-10-26 12:09:38 +00:00
{
return false;
}
2023-10-23 14:19:03 +00:00
}
2023-09-15 12:23:22 +00:00
public static Boolean DeleteUserPassword(User user)
{
user.Password = "";
user.MustResetPassword = true;
return Update(user);
}
2023-03-09 15:32:11 +00:00
}