mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 03:48:56 +00:00
Devices - Reworking layout loading
This commit is contained in:
1 parent
9393bf2b68
commit
e8590abd61
57 files changed
+824
-349
No files matched your search
@@ -1,7 +1,9 @@
|
||||
using System.Reflection;
|
||||
using Artemis.Core.Providers;
|
||||
using Artemis.WebClient.Workshop.Extensions;
|
||||
using Artemis.WebClient.Workshop.Handlers.InstallationHandlers;
|
||||
using Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||
using Artemis.WebClient.Workshop.Providers;
|
||||
using Artemis.WebClient.Workshop.Repositories;
|
||||
using Artemis.WebClient.Workshop.Services;
|
||||
using Artemis.WebClient.Workshop.State;
|
||||
@@ -46,6 +48,7 @@ public static class ContainerExtensions
|
||||
container.Register<IAuthenticationRepository, AuthenticationRepository>(Reuse.Singleton);
|
||||
container.Register<IAuthenticationService, AuthenticationService>(Reuse.Singleton);
|
||||
container.Register<IWorkshopService, WorkshopService>(Reuse.Singleton);
|
||||
container.Register<ILayoutProvider, WorkshopLayoutProvider>(Reuse.Singleton);
|
||||
|
||||
container.Register<EntryUploadHandlerFactory>(Reuse.Transient);
|
||||
container.RegisterMany(workshopAssembly, type => type.IsAssignableTo<IEntryUploadHandler>(), Reuse.Transient);
|
||||
|
||||
+46
-10
@@ -1,4 +1,9 @@
|
||||
using Artemis.UI.Shared.Extensions;
|
||||
using System.Data;
|
||||
using System.IO.Compression;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared.Extensions;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Artemis.UI.Shared.Utilities;
|
||||
using Artemis.WebClient.Workshop.Services;
|
||||
|
||||
@@ -8,17 +13,17 @@ public class LayoutEntryInstallationHandler : IEntryInstallationHandler
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IWorkshopService _workshopService;
|
||||
private readonly IDeviceService _deviceService;
|
||||
|
||||
public LayoutEntryInstallationHandler(IHttpClientFactory httpClientFactory, IWorkshopService workshopService)
|
||||
public LayoutEntryInstallationHandler(IHttpClientFactory httpClientFactory, IWorkshopService workshopService, IDeviceService deviceService)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_workshopService = workshopService;
|
||||
_deviceService = deviceService;
|
||||
}
|
||||
|
||||
public async Task<EntryInstallResult> InstallAsync(IGetEntryById_Entry entry, long releaseId, Progress<StreamProgress> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
using MemoryStream stream = new();
|
||||
|
||||
// Download the provided release
|
||||
@@ -31,15 +36,46 @@ public class LayoutEntryInstallationHandler : IEntryInstallationHandler
|
||||
{
|
||||
return EntryInstallResult.FromFailure(e.Message);
|
||||
}
|
||||
|
||||
// return EntryInstallResult.FromSuccess();
|
||||
|
||||
// Ensure there is an installed entry
|
||||
InstalledEntry installedEntry = _workshopService.GetInstalledEntry(entry) ?? _workshopService.CreateInstalledEntry(entry);
|
||||
DirectoryInfo entryDirectory = installedEntry.GetDirectory();
|
||||
|
||||
// If the folder already exists, remove it so that if the layout now contains less files, old things dont stick around
|
||||
if (entryDirectory.Exists)
|
||||
entryDirectory.Delete(true);
|
||||
entryDirectory.Create();
|
||||
|
||||
// Extract the archive, we could go through the hoops of keeping track of progress but this should be so quick it doesn't matter
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
using ZipArchive archive = new(stream);
|
||||
archive.ExtractToDirectory(entryDirectory.FullName);
|
||||
|
||||
ArtemisLayout layout = new(Path.Combine(entryDirectory.FullName, "layout.xml"));
|
||||
if (layout.IsValid)
|
||||
return EntryInstallResult.FromSuccess(layout);
|
||||
|
||||
// If the layout ended up being invalid yoink it out again, shoooo
|
||||
entryDirectory.Delete(true);
|
||||
_workshopService.RemoveInstalledEntry(installedEntry);
|
||||
return EntryInstallResult.FromFailure("Layout failed to load because it is invalid");
|
||||
}
|
||||
|
||||
public async Task<EntryUninstallResult> UninstallAsync(InstalledEntry installedEntry, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
if (!Guid.TryParse(installedEntry.LocalReference, out Guid profileId))
|
||||
return EntryUninstallResult.FromFailure("Local reference does not contain a GUID");
|
||||
// Remove the layout from any devices currently using it
|
||||
foreach (ArtemisDevice device in _deviceService.Devices)
|
||||
{
|
||||
}
|
||||
|
||||
// Remove from filesystem
|
||||
DirectoryInfo directory = installedEntry.GetDirectory(true);
|
||||
if (directory.Exists)
|
||||
directory.Delete();
|
||||
|
||||
// Remove entry
|
||||
_workshopService.RemoveInstalledEntry(installedEntry);
|
||||
|
||||
return EntryUninstallResult.FromSuccess();
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -36,13 +36,13 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler
|
||||
|
||||
// Find existing installation to potentially replace the profile
|
||||
InstalledEntry? installedEntry = _workshopService.GetInstalledEntry(entry);
|
||||
if (installedEntry != null && Guid.TryParse(installedEntry.LocalReference, out Guid profileId))
|
||||
if (installedEntry != null && installedEntry.TryGetMetadata("ProfileId", out Guid profileId))
|
||||
{
|
||||
ProfileConfiguration? existing = _profileService.ProfileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(c => c.ProfileId == profileId);
|
||||
if (existing != null)
|
||||
{
|
||||
ProfileConfiguration overwritten = await _profileService.OverwriteProfile(stream, existing);
|
||||
installedEntry.LocalReference = overwritten.ProfileId.ToString();
|
||||
installedEntry.SetMetadata("ProfileId", overwritten.ProfileId);
|
||||
|
||||
// Update the release and return the profile configuration
|
||||
UpdateRelease(releaseId, installedEntry);
|
||||
@@ -56,8 +56,8 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler
|
||||
// Add the profile as a fresh import
|
||||
ProfileCategory category = _profileService.ProfileCategories.FirstOrDefault(c => c.Name == "Workshop") ?? _profileService.CreateProfileCategory("Workshop", true);
|
||||
ProfileConfiguration imported = await _profileService.ImportProfile(stream, category, true, true, null);
|
||||
installedEntry.LocalReference = imported.ProfileId.ToString();
|
||||
|
||||
installedEntry.SetMetadata("ProfileId", imported.ProfileId);
|
||||
|
||||
// Update the release and return the profile configuration
|
||||
UpdateRelease(releaseId, installedEntry);
|
||||
return EntryInstallResult.FromSuccess(imported);
|
||||
@@ -65,7 +65,7 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler
|
||||
|
||||
public async Task<EntryUninstallResult> UninstallAsync(InstalledEntry installedEntry, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!Guid.TryParse(installedEntry.LocalReference, out Guid profileId))
|
||||
if (!installedEntry.TryGetMetadata("ProfileId", out Guid profileId))
|
||||
return EntryUninstallResult.FromFailure("Local reference does not contain a GUID");
|
||||
|
||||
return await Task.Run(() =>
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Providers;
|
||||
using Artemis.WebClient.Workshop.Services;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Providers;
|
||||
|
||||
public class WorkshopLayoutProvider : ILayoutProvider
|
||||
{
|
||||
public static string LayoutType = "Workshop";
|
||||
|
||||
private readonly IWorkshopService _workshopService;
|
||||
|
||||
public WorkshopLayoutProvider(IWorkshopService workshopService)
|
||||
{
|
||||
_workshopService = workshopService;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ArtemisLayout? GetDeviceLayout(ArtemisDevice device)
|
||||
{
|
||||
InstalledEntry? layoutEntry = _workshopService.GetInstalledEntries().FirstOrDefault(e => e.EntryType == EntryType.Layout && MatchesDevice(e, device));
|
||||
if (layoutEntry == null)
|
||||
return null;
|
||||
|
||||
string layoutPath = Path.Combine(Constants.WorkshopFolder, layoutEntry.EntryId.ToString(), "layout.xml");
|
||||
if (!File.Exists(layoutPath))
|
||||
return null;
|
||||
|
||||
return new ArtemisLayout(layoutPath);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ApplyLayout(ArtemisDevice device, ArtemisLayout layout)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsMatch(ArtemisDevice device)
|
||||
{
|
||||
return device.LayoutSelection.Type == LayoutType;
|
||||
}
|
||||
|
||||
private bool MatchesDevice(InstalledEntry entry, ArtemisDevice device)
|
||||
{
|
||||
return entry.TryGetMetadata("DeviceId", out HashSet<string>? deviceIds) && deviceIds.Contains(device.Identifier);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
using Artemis.Storage.Entities.Workshop;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Artemis.Core;
|
||||
using Artemis.Storage.Entities.Workshop;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Services;
|
||||
|
||||
public class InstalledEntry
|
||||
{
|
||||
private Dictionary<string, object> _metadata = new();
|
||||
|
||||
internal InstalledEntry(EntryEntity entity)
|
||||
{
|
||||
Entity = entity;
|
||||
|
||||
Load();
|
||||
}
|
||||
|
||||
@@ -32,8 +35,6 @@ public class InstalledEntry
|
||||
public string ReleaseVersion { get; set; } = string.Empty;
|
||||
public DateTimeOffset InstalledAt { get; set; }
|
||||
|
||||
public string? LocalReference { get; set; }
|
||||
|
||||
internal EntryEntity Entity { get; }
|
||||
|
||||
internal void Load()
|
||||
@@ -48,7 +49,7 @@ public class InstalledEntry
|
||||
ReleaseVersion = Entity.ReleaseVersion;
|
||||
InstalledAt = Entity.InstalledAt;
|
||||
|
||||
LocalReference = Entity.LocalReference;
|
||||
_metadata = new Dictionary<string, object>(Entity.Metadata);
|
||||
}
|
||||
|
||||
internal void Save()
|
||||
@@ -63,6 +64,60 @@ public class InstalledEntry
|
||||
Entity.ReleaseVersion = ReleaseVersion;
|
||||
Entity.InstalledAt = InstalledAt;
|
||||
|
||||
Entity.LocalReference = LocalReference;
|
||||
Entity.Metadata = new Dictionary<string, object>(_metadata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the metadata value associated with the specified key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the value to get.</param>
|
||||
/// <param name="value">When this method returns, contains the value associated with the specified key, if the key is found and of type <typeparamref name="T"/>;
|
||||
/// otherwise, the default value for the type of the value parameter. This parameter is passed uninitialized.</param>
|
||||
/// <typeparam name="T">The type of the value.</typeparam>
|
||||
/// <returns><see langword="true"/> if the metadata contains an element with the specified key; otherwise, <see langword="false"/>.</returns>
|
||||
public bool TryGetMetadata<T>(string key, [NotNullWhen(true)] out T? value)
|
||||
{
|
||||
if (!_metadata.TryGetValue(key, out object? objectValue) || objectValue is not T result)
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
value = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets metadata with the provided key to the provided value.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the value to set</param>
|
||||
/// <param name="value">The value to set.</param>
|
||||
public void SetMetadata(string key, object value)
|
||||
{
|
||||
_metadata.Add(key, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes metadata with the provided key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the metadata to remove</param>
|
||||
/// <returns><see langword="true"/> if the element is successfully found and removed; otherwise, <see langword="false"/>.</returns>
|
||||
public bool RemoveMetadata(string key)
|
||||
{
|
||||
return _metadata.Remove(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the directory info of the entry, where any files would be stored if applicable.
|
||||
/// </summary>
|
||||
/// <param name="rootDirectory">A value indicating whether or not to return the root directory of the entry, and not the version.</param>
|
||||
/// <returns>The directory info of the entry, where any files would be stored if applicable.</returns>
|
||||
public DirectoryInfo GetDirectory(bool rootDirectory = false)
|
||||
{
|
||||
if (rootDirectory)
|
||||
return new DirectoryInfo(Path.Combine(Constants.WorkshopFolder, EntryId.ToString()));
|
||||
|
||||
string safeVersion = Path.GetInvalidFileNameChars().Aggregate(ReleaseVersion, (current, c) => current.Replace(c, '-'));
|
||||
return new DirectoryInfo(Path.Combine(Constants.WorkshopFolder, EntryId.ToString(), safeVersion));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user