mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Merge pull request #782 from Artemis-RGB/feature/hot-reload
Core - Added plugin hot reloading
This commit is contained in:
commit
afa76a262a
@ -28,6 +28,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
|
|||||||
private string _version = null!;
|
private string _version = null!;
|
||||||
private Uri? _website;
|
private Uri? _website;
|
||||||
private Uri? _helpPage;
|
private Uri? _helpPage;
|
||||||
|
private bool _hotReloadSupported;
|
||||||
|
|
||||||
internal PluginInfo()
|
internal PluginInfo()
|
||||||
{
|
{
|
||||||
@ -156,6 +157,17 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
|
|||||||
internal set => SetAndNotify(ref _requiresAdmin, value);
|
internal set => SetAndNotify(ref _requiresAdmin, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a boolean indicating whether hot reloading this plugin is supported
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue(true)]
|
||||||
|
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
|
||||||
|
public bool HotReloadSupported
|
||||||
|
{
|
||||||
|
get => _hotReloadSupported;
|
||||||
|
set => SetAndNotify(ref _hotReloadSupported, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets
|
/// Gets
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -5,6 +5,7 @@ using System.IO;
|
|||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core.DeviceProviders;
|
using Artemis.Core.DeviceProviders;
|
||||||
using Artemis.Core.DryIoc;
|
using Artemis.Core.DryIoc;
|
||||||
@ -30,6 +31,7 @@ internal class PluginManagementService : IPluginManagementService
|
|||||||
private readonly IPluginRepository _pluginRepository;
|
private readonly IPluginRepository _pluginRepository;
|
||||||
private readonly List<Plugin> _plugins;
|
private readonly List<Plugin> _plugins;
|
||||||
private readonly IQueuedActionRepository _queuedActionRepository;
|
private readonly IQueuedActionRepository _queuedActionRepository;
|
||||||
|
private FileSystemWatcher _hotReloadWatcher;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
private bool _isElevated;
|
private bool _isElevated;
|
||||||
|
|
||||||
@ -43,6 +45,8 @@ internal class PluginManagementService : IPluginManagementService
|
|||||||
_plugins = new List<Plugin>();
|
_plugins = new List<Plugin>();
|
||||||
|
|
||||||
ProcessPluginDeletionQueue();
|
ProcessPluginDeletionQueue();
|
||||||
|
|
||||||
|
StartHotReload();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CopyBuiltInPlugin(ZipArchive zipArchive, string targetDirectory)
|
private void CopyBuiltInPlugin(ZipArchive zipArchive, string targetDirectory)
|
||||||
@ -218,6 +222,14 @@ internal class PluginManagementService : IPluginManagementService
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Plugin? GetPluginByDirectory(DirectoryInfo directory)
|
||||||
|
{
|
||||||
|
lock (_plugins)
|
||||||
|
{
|
||||||
|
return _plugins.FirstOrDefault(p => p.Directory.FullName == directory.FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
// Disposal happens manually before container disposal but the container doesn't know that so a 2nd call will be made
|
// Disposal happens manually before container disposal but the container doesn't know that so a 2nd call will be made
|
||||||
@ -912,6 +924,67 @@ internal class PluginManagementService : IPluginManagementService
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Hot Reload
|
||||||
|
|
||||||
|
private void StartHotReload()
|
||||||
|
{
|
||||||
|
// Watch for changes in the plugin directory, "plugin.json".
|
||||||
|
// If this file is changed, reload the plugin.
|
||||||
|
_hotReloadWatcher = new FileSystemWatcher(Constants.PluginsFolder, "plugin.json");
|
||||||
|
_hotReloadWatcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.FileName;
|
||||||
|
_hotReloadWatcher.Created += FileSystemWatcherOnCreated;
|
||||||
|
_hotReloadWatcher.Error += FileSystemWatcherOnError;
|
||||||
|
_hotReloadWatcher.IncludeSubdirectories = true;
|
||||||
|
_hotReloadWatcher.EnableRaisingEvents = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FileSystemWatcherOnError(object sender, ErrorEventArgs e)
|
||||||
|
{
|
||||||
|
_logger.Error(e.GetException(), "File system watcher error");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FileSystemWatcherOnCreated(object sender, FileSystemEventArgs e)
|
||||||
|
{
|
||||||
|
string? pluginPath = Path.GetDirectoryName(e.FullPath);
|
||||||
|
if (pluginPath == null)
|
||||||
|
{
|
||||||
|
_logger.Warning("Plugin change detected, but could not get plugin directory. {fullPath}", e.FullPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryInfo pluginDirectory = new(pluginPath);
|
||||||
|
Plugin? plugin = GetPluginByDirectory(pluginDirectory);
|
||||||
|
|
||||||
|
if (plugin == null)
|
||||||
|
{
|
||||||
|
_logger.Warning("Plugin change detected, but could not find plugin. {fullPath}", e.FullPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!plugin.Info.HotReloadSupported)
|
||||||
|
{
|
||||||
|
_logger.Information("Plugin change detected, but hot reload not supported. {pluginName}", plugin.Info.Name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Information("Plugin change detected, reloading. {pluginName}", plugin.Info.Name);
|
||||||
|
bool wasEnabled = plugin.IsEnabled;
|
||||||
|
|
||||||
|
UnloadPlugin(plugin);
|
||||||
|
Thread.Sleep(500);
|
||||||
|
Plugin? loadedPlugin = LoadPlugin(pluginDirectory);
|
||||||
|
|
||||||
|
if (loadedPlugin == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (wasEnabled)
|
||||||
|
EnablePlugin(loadedPlugin, true, false);
|
||||||
|
|
||||||
|
_logger.Information("Plugin reloaded. {fullPath}", e.FullPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user