mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Storage - Keep up to 5 backups of the database
Layouts - Prevent LEDs from going outside the layout bounds
This commit is contained in:
parent
033e94bc58
commit
bab566a2b9
@ -4,6 +4,7 @@ using System.Threading;
|
|||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Ninject;
|
using Artemis.Core.Ninject;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.Storage;
|
||||||
using Ninject;
|
using Ninject;
|
||||||
|
|
||||||
namespace Artemis.UI.Console
|
namespace Artemis.UI.Console
|
||||||
@ -28,6 +29,8 @@ namespace Artemis.UI.Console
|
|||||||
|
|
||||||
private static void Main(string[] args)
|
private static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
StorageManager.CreateBackup(Constants.DataFolder);
|
||||||
|
|
||||||
Utilities.PrepareFirstLaunch();
|
Utilities.PrepareFirstLaunch();
|
||||||
Utilities.ShutdownRequested += UtilitiesOnShutdownRequested;
|
Utilities.ShutdownRequested += UtilitiesOnShutdownRequested;
|
||||||
StandardKernel kernel = new() {Settings = {InjectNonPublic = true}};
|
StandardKernel kernel = new() {Settings = {InjectNonPublic = true}};
|
||||||
|
|||||||
@ -29,11 +29,6 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly string DataFolder = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\Artemis\\";
|
public static readonly string DataFolder = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\Artemis\\";
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The connection string used to connect to the database
|
|
||||||
/// </summary>
|
|
||||||
public static readonly string ConnectionString = $"FileName={DataFolder}\\database.db";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The plugin info used by core components of Artemis
|
/// The plugin info used by core components of Artemis
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -102,6 +102,26 @@ namespace Artemis.Core
|
|||||||
foreach (LedId led in ledsToRemove)
|
foreach (LedId led in ledsToRemove)
|
||||||
device.RemoveLed(led);
|
device.RemoveLed(led);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Led> deviceLeds = device.ToList();
|
||||||
|
foreach (Led led in deviceLeds)
|
||||||
|
{
|
||||||
|
float x = led.Location.X;
|
||||||
|
float y = led.Location.Y;
|
||||||
|
|
||||||
|
// Try to move the LED if it falls outside the boundaries of the layout
|
||||||
|
if (led.Location.X + led.Size.Width > device.Size.Width)
|
||||||
|
x -= led.Location.X + led.Size.Width - device.Size.Width;
|
||||||
|
|
||||||
|
if (led.Location.Y + led.Size.Height > device.Size.Height)
|
||||||
|
y -= led.Location.Y + led.Size.Height - device.Size.Height;
|
||||||
|
|
||||||
|
// If not possible because it's too large we'll have to drop it to avoid rendering issues
|
||||||
|
if (x < 0 || y < 0)
|
||||||
|
device.RemoveLed(led.Id);
|
||||||
|
else
|
||||||
|
led.Location = new Point(x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ApplyDevice(ArtemisDevice artemisDevice)
|
internal void ApplyDevice(ArtemisDevice artemisDevice)
|
||||||
|
|||||||
@ -50,24 +50,7 @@ namespace Artemis.Core.Ninject
|
|||||||
.Configure(c => c.When(HasAccessToProtectedService).InSingletonScope());
|
.Configure(c => c.When(HasAccessToProtectedService).InSingletonScope());
|
||||||
});
|
});
|
||||||
|
|
||||||
Kernel.Bind<LiteRepository>().ToMethod(t =>
|
Kernel.Bind<LiteRepository>().ToMethod(_ => StorageManager.CreateRepository(Constants.DataFolder)).InSingletonScope();
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return new LiteRepository(Constants.ConnectionString);
|
|
||||||
}
|
|
||||||
catch (LiteException e)
|
|
||||||
{
|
|
||||||
// I don't like this way of error reporting, now I need to use reflection if I want a meaningful error code
|
|
||||||
if (e.ErrorCode != LiteException.INVALID_DATABASE)
|
|
||||||
throw new ArtemisCoreException($"LiteDB threw error code {e.ErrorCode}. See inner exception for more details", e);
|
|
||||||
|
|
||||||
// If the DB is invalid it's probably LiteDB v4 (TODO: we'll have to do something better later)
|
|
||||||
File.Delete($"{Constants.DataFolder}\\database.db");
|
|
||||||
return new LiteRepository(Constants.ConnectionString);
|
|
||||||
}
|
|
||||||
}).InSingletonScope();
|
|
||||||
|
|
||||||
Kernel.Bind<StorageMigrationService>().ToSelf().InSingletonScope();
|
Kernel.Bind<StorageMigrationService>().ToSelf().InSingletonScope();
|
||||||
|
|
||||||
// Bind all migrations as singletons
|
// Bind all migrations as singletons
|
||||||
|
|||||||
63
src/Artemis.Storage/StorageManager.cs
Normal file
63
src/Artemis.Storage/StorageManager.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage
|
||||||
|
{
|
||||||
|
public static class StorageManager
|
||||||
|
{
|
||||||
|
private static bool _inUse;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a backup of the database if the last backup is older than 10 minutes
|
||||||
|
/// Removes the oldest backup if there are more than 5 backups present
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dataFolder">The Artemis data folder</param>
|
||||||
|
public static void CreateBackup(string dataFolder)
|
||||||
|
{
|
||||||
|
if (_inUse)
|
||||||
|
throw new Exception("Storage is already in use, can't backup now.");
|
||||||
|
|
||||||
|
string database = $"{dataFolder}\\database.db";
|
||||||
|
if (!File.Exists(database))
|
||||||
|
return;
|
||||||
|
|
||||||
|
string backupFolder = $"{dataFolder}\\database backups";
|
||||||
|
Directory.CreateDirectory(backupFolder);
|
||||||
|
FileSystemInfo[] files = new DirectoryInfo(backupFolder).GetFileSystemInfos();
|
||||||
|
if (files.Length >= 5)
|
||||||
|
{
|
||||||
|
FileSystemInfo newest = files.OrderByDescending(fi => fi.CreationTime).First();
|
||||||
|
FileSystemInfo oldest = files.OrderBy(fi => fi.CreationTime).First();
|
||||||
|
if (DateTime.Now - newest.CreationTime < TimeSpan.FromMinutes(10))
|
||||||
|
return;
|
||||||
|
|
||||||
|
oldest.Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
File.Copy(database, $"{backupFolder}\\database-{DateTime.Now:yyyy-dd-M--HH-mm-ss}.db");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the LiteRepository that will be managed by dependency injection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dataFolder">The Artemis data folder</param>
|
||||||
|
public static LiteRepository CreateRepository(string dataFolder)
|
||||||
|
{
|
||||||
|
if (_inUse)
|
||||||
|
throw new Exception("Storage is already in use, use dependency injection to get the repository.");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_inUse = true;
|
||||||
|
return new LiteRepository($"FileName={dataFolder}\\database.db");
|
||||||
|
}
|
||||||
|
catch (LiteException e)
|
||||||
|
{
|
||||||
|
// I don't like this way of error reporting, now I need to use reflection if I want a meaningful error message
|
||||||
|
throw new Exception($"LiteDB threw error code {e.ErrorCode}. See inner exception for more details", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,8 +6,10 @@ using System.Threading.Tasks;
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Markup;
|
using System.Windows.Markup;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
|
using Artemis.Core;
|
||||||
using Artemis.Core.Ninject;
|
using Artemis.Core.Ninject;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.Storage;
|
||||||
using Artemis.UI.Ninject;
|
using Artemis.UI.Ninject;
|
||||||
using Artemis.UI.Screens;
|
using Artemis.UI.Screens;
|
||||||
using Artemis.UI.Services;
|
using Artemis.UI.Services;
|
||||||
@ -25,6 +27,13 @@ namespace Artemis.UI
|
|||||||
{
|
{
|
||||||
private ApplicationStateManager _applicationStateManager;
|
private ApplicationStateManager _applicationStateManager;
|
||||||
private ICoreService _core;
|
private ICoreService _core;
|
||||||
|
|
||||||
|
public Bootstrapper()
|
||||||
|
{
|
||||||
|
// This is done at this kind of odd place to ensure it happens before the database is in use
|
||||||
|
StorageManager.CreateBackup(Constants.DataFolder);
|
||||||
|
}
|
||||||
|
|
||||||
public static List<string> StartupArguments { get; private set; }
|
public static List<string> StartupArguments { get; private set; }
|
||||||
|
|
||||||
protected override void OnExit(ExitEventArgs e)
|
protected override void OnExit(ExitEventArgs e)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user