aboutsummaryrefslogtreecommitdiff
path: root/lib/Plugins.Runtime
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Plugins.Runtime')
-rw-r--r--lib/Plugins.Runtime/src/AssemblyWatcher.cs91
-rw-r--r--lib/Plugins.Runtime/src/PluginStackBuilder.cs6
-rw-r--r--lib/Plugins.Runtime/src/RuntimePluginLoader.cs17
3 files changed, 35 insertions, 79 deletions
diff --git a/lib/Plugins.Runtime/src/AssemblyWatcher.cs b/lib/Plugins.Runtime/src/AssemblyWatcher.cs
index 09b49dc..69c53ed 100644
--- a/lib/Plugins.Runtime/src/AssemblyWatcher.cs
+++ b/lib/Plugins.Runtime/src/AssemblyWatcher.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Runtime
@@ -22,95 +22,52 @@
* along with VNLib.Plugins.Runtime. If not, see http://www.gnu.org/licenses/.
*/
+using System;
using System.IO;
using System.Threading;
-using System.Collections.Generic;
using VNLib.Utils;
+using VNLib.Utils.IO;
using VNLib.Utils.Extensions;
-namespace VNLib.Plugins.Runtime
-{
- internal sealed class AssemblyWatcher : IPluginAssemblyWatcher
- {
- private readonly object _lock = new ();
- private readonly Dictionary<IPluginReloadEventHandler, AsmFileWatcher> _watchers;
- public AssemblyWatcher()
- {
- _watchers = new();
- }
+namespace VNLib.Plugins.Runtime
+{
- ///<inheritdoc/>
- public void StopWatching(IPluginReloadEventHandler handler)
- {
- lock (_lock)
- {
- //Find old watcher by its handler, then dispose it
- if (_watchers.Remove(handler, out AsmFileWatcher? watcher))
- {
- //dispose the watcher
- watcher.Dispose();
- }
- }
- }
+ internal static class AssemblyWatcher
+ {
- ///<inheritdoc/>
- public void WatchAssembly(IPluginReloadEventHandler handler, IPluginAssemblyLoader loader)
+ internal static IDisposable WatchAssembly(IPluginReloadEventHandler handler, IPluginAssemblyLoader loader)
{
- lock(_lock)
- {
- if(_watchers.Remove(handler, out AsmFileWatcher? watcher))
- {
- //dispose the watcher
- watcher.Dispose();
- }
+ ArgumentNullException.ThrowIfNull(handler);
+ ArgumentNullException.ThrowIfNull(loader);
- //Queue up a new watcher
- watcher = new(loader, handler);
+ DebouncedFSEventHandler dbh = new(loader, handler);
+ FileWatcher.Subscribe(loader.Config.AssemblyFile, dbh);
- //Store watcher
- _watchers.Add(handler, watcher);
- }
+ return dbh;
}
- private sealed class AsmFileWatcher : VnDisposeable
+ internal sealed class DebouncedFSEventHandler : VnDisposeable, IFSChangeHandler
{
- public IPluginReloadEventHandler Handler { get; }
+ private readonly IPluginReloadEventHandler _handler;
private readonly IPluginAssemblyLoader _loaderSource;
private readonly Timer _delayTimer;
- private readonly FileSystemWatcher _watcher;
private bool _pause;
- public AsmFileWatcher(IPluginAssemblyLoader LoaderSource, IPluginReloadEventHandler handler)
+ public DebouncedFSEventHandler(IPluginAssemblyLoader loader, IPluginReloadEventHandler handler)
{
- Handler = handler;
- _loaderSource = LoaderSource;
-
- string dir = Path.GetDirectoryName(LoaderSource.Config.AssemblyFile)!;
-
- //Configure watcher to notify only when the assembly file changes
- _watcher = new FileSystemWatcher(dir)
- {
- Filter = "*.dll",
- EnableRaisingEvents = false,
- IncludeSubdirectories = true,
- NotifyFilter = NotifyFilters.LastWrite,
- };
-
- //Configure listener
- _watcher.Changed += OnFileChanged;
- _watcher.Created += OnFileChanged;
-
- _watcher.EnableRaisingEvents = true;
+ _handler = handler;
+ _loaderSource = loader;
//setup delay timer to wait on the config
- _delayTimer = new(OnTimeout, this, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
+ _delayTimer = new(OnTimeout, null, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
}
- void OnFileChanged(object sender, FileSystemEventArgs e)
+ ///<inheritdoc/>
+ void IFSChangeHandler.OnFileChanged(FileSystemEventArgs e)
{
//if were already waiting to process an event, we dont need to stage another
if (_pause)
@@ -130,7 +87,7 @@ namespace VNLib.Plugins.Runtime
_delayTimer.Stop();
//Fire event, let exception crash app
- Handler.OnPluginUnloaded(_loaderSource);
+ _handler.OnPluginUnloaded(_loaderSource);
//Clear pause flag
_pause = false;
@@ -140,9 +97,7 @@ namespace VNLib.Plugins.Runtime
{
_delayTimer.Dispose();
- //Detach event handler and dispose watcher
- _watcher.Changed -= OnFileChanged;
- _watcher.Dispose();
+ FileWatcher.Unsubscribe(_loaderSource.Config.AssemblyFile, this);
}
}
}
diff --git a/lib/Plugins.Runtime/src/PluginStackBuilder.cs b/lib/Plugins.Runtime/src/PluginStackBuilder.cs
index eed08e2..ef3ffc9 100644
--- a/lib/Plugins.Runtime/src/PluginStackBuilder.cs
+++ b/lib/Plugins.Runtime/src/PluginStackBuilder.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Runtime
@@ -83,8 +83,10 @@ namespace VNLib.Plugins.Runtime
/// <returns>The current builder instance for chaining</returns>
public PluginStackBuilder WithConfigurationReader(IPluginConfigReader pluginConfig)
{
+ ArgumentNullException.ThrowIfNull(pluginConfig);
+
//Store binary copy
- PluginConfig = pluginConfig ?? throw new ArgumentNullException(nameof(pluginConfig));
+ PluginConfig = pluginConfig;
return this;
}
diff --git a/lib/Plugins.Runtime/src/RuntimePluginLoader.cs b/lib/Plugins.Runtime/src/RuntimePluginLoader.cs
index 60edf55..23bbcab 100644
--- a/lib/Plugins.Runtime/src/RuntimePluginLoader.cs
+++ b/lib/Plugins.Runtime/src/RuntimePluginLoader.cs
@@ -38,10 +38,9 @@ namespace VNLib.Plugins.Runtime
/// </summary>
public sealed class RuntimePluginLoader : VnDisposeable, IPluginReloadEventHandler
{
- private static readonly IPluginAssemblyWatcher Watcher = new AssemblyWatcher();
-
- private readonly IPluginAssemblyLoader Loader;
+ private readonly IPluginAssemblyLoader Loader;
private readonly ILogProvider? Log;
+ private readonly IDisposable? Watcher;
/// <summary>
/// Gets the plugin assembly loader configuration information
@@ -61,13 +60,15 @@ namespace VNLib.Plugins.Runtime
/// <exception cref="ArgumentNullException"></exception>
public RuntimePluginLoader(IPluginAssemblyLoader loader, ILogProvider? log)
{
- Log = log;
- Loader = loader ?? throw new ArgumentNullException(nameof(loader));
+ ArgumentNullException.ThrowIfNull(loader);
+
+ Log = log;
+ Loader = loader;
//Configure watcher if requested
if (loader.Config.WatchForReload)
{
- Watcher.WatchAssembly(this, loader);
+ Watcher = AssemblyWatcher.WatchAssembly(this, loader);
}
//Init container
@@ -200,10 +201,8 @@ namespace VNLib.Plugins.Runtime
///<inheritdoc/>
protected override void Free()
{
- //Stop watching for events
- Watcher.StopWatching(this);
-
//Cleanup
+ Watcher?.Dispose();
Controller.Dispose();
Loader.Dispose();
}