From b7f2a62b3c08b8deb9839ffc66c89144552a808a Mon Sep 17 00:00:00 2001 From: John Gross Date: Thu, 21 Sep 2017 22:30:48 -0700 Subject: [PATCH] Expose read-only collections in PluginManager instead of full collections --- Torch.API/Managers/IPluginManager.cs | 4 +- .../ViewModels/PluginManagerViewModel.cs | 2 +- Torch/Extensions/ICollectionExtensions.cs | 54 +++++++++++++++++++ Torch/Plugins/PluginManager.cs | 26 ++++----- Torch/Torch.csproj | 1 + 5 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 Torch/Extensions/ICollectionExtensions.cs diff --git a/Torch.API/Managers/IPluginManager.cs b/Torch.API/Managers/IPluginManager.cs index 2028e42..2a2ee08 100644 --- a/Torch.API/Managers/IPluginManager.cs +++ b/Torch.API/Managers/IPluginManager.cs @@ -14,12 +14,12 @@ namespace Torch.API.Managers /// /// Fired when plugins are loaded. /// - event Action> PluginsLoaded; + event Action> PluginsLoaded; /// /// Collection of loaded plugins. /// - IDictionary Plugins { get; } + IReadOnlyDictionary Plugins { get; } /// /// Updates all loaded plugins. diff --git a/Torch.Server/ViewModels/PluginManagerViewModel.cs b/Torch.Server/ViewModels/PluginManagerViewModel.cs index ec87acb..d910cf8 100644 --- a/Torch.Server/ViewModels/PluginManagerViewModel.cs +++ b/Torch.Server/ViewModels/PluginManagerViewModel.cs @@ -29,7 +29,7 @@ namespace Torch.Server.ViewModels pluginManager.PluginsLoaded += PluginManager_PluginsLoaded; } - private void PluginManager_PluginsLoaded(ICollection obj) + private void PluginManager_PluginsLoaded(IReadOnlyCollection obj) { Plugins.Clear(); foreach (var plugin in obj) diff --git a/Torch/Extensions/ICollectionExtensions.cs b/Torch/Extensions/ICollectionExtensions.cs new file mode 100644 index 0000000..acc952c --- /dev/null +++ b/Torch/Extensions/ICollectionExtensions.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace Torch +{ + public static class ICollectionExtensions + { + /// + /// Returns a read-only wrapped + /// + public static IReadOnlyCollection AsReadOnly(this ICollection source) + { + if (source == null) + throw new ArgumentNullException(nameof(source)); + return source as IReadOnlyCollection ?? new ReadOnlyCollectionAdapter(source); + } + + /// + /// Returns a read-only wrapped + /// + public static IReadOnlyList AsReadOnly(this IList source) + { + if (source == null) + throw new ArgumentNullException(nameof(source)); + return source as IReadOnlyList ?? new ReadOnlyCollection(source); + } + + /// + /// Returns a read-only wrapped + /// + public static IReadOnlyDictionary AsReadOnly(this IDictionary source) + { + if (source == null) + throw new ArgumentNullException(nameof(source)); + return source as IReadOnlyDictionary ?? new ReadOnlyDictionary(source); + } + + sealed class ReadOnlyCollectionAdapter : IReadOnlyCollection + { + private readonly ICollection _source; + + public ReadOnlyCollectionAdapter(ICollection source) + { + _source = source; + } + + public int Count => _source.Count; + public IEnumerator GetEnumerator() => _source.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/Torch/Plugins/PluginManager.cs b/Torch/Plugins/PluginManager.cs index d480b46..25eb10c 100644 --- a/Torch/Plugins/PluginManager.cs +++ b/Torch/Plugins/PluginManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; using System.IO.Compression; using System.Linq; @@ -25,13 +26,14 @@ namespace Torch.Managers private static Logger _log = LogManager.GetLogger(nameof(PluginManager)); private const string MANIFEST_NAME = "manifest.xml"; public readonly string PluginDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins"); + private readonly ObservableDictionary _plugins = new ObservableDictionary(); [Dependency] private CommandManager _commandManager; /// - public IDictionary Plugins { get; } = new ObservableDictionary(); + public IReadOnlyDictionary Plugins => _plugins.AsReadOnly(); - public event Action> PluginsLoaded; + public event Action> PluginsLoaded; public PluginManager(ITorchBase torchInstance) : base(torchInstance) { @@ -44,7 +46,7 @@ namespace Torch.Managers /// public void UpdatePlugins() { - foreach (var plugin in Plugins.Values) + foreach (var plugin in _plugins.Values) plugin.Update(); } @@ -53,10 +55,10 @@ namespace Torch.Managers /// public override void Detach() { - foreach (var plugin in Plugins.Values) + foreach (var plugin in _plugins.Values) plugin.Dispose(); - Plugins.Clear(); + _plugins.Clear(); } public void LoadPlugins() @@ -75,9 +77,9 @@ namespace Torch.Managers continue; } - if (Plugins.ContainsKey(manifest.Guid)) + if (_plugins.ContainsKey(manifest.Guid)) { - _log.Error($"The GUID provided by {manifest.Name} ({item}) is already in use by {Plugins[manifest.Guid].Name}"); + _log.Error($"The GUID provided by {manifest.Name} ({item}) is already in use by {_plugins[manifest.Guid].Name}"); continue; } @@ -87,9 +89,9 @@ namespace Torch.Managers LoadPluginFromFolder(path); } - Plugins.ForEach(x => x.Value.Init(Torch)); - _log.Info($"Loaded {Plugins.Count} plugins."); - PluginsLoaded?.Invoke(Plugins.Values); + _plugins.ForEach(x => x.Value.Init(Torch)); + _log.Info($"Loaded {_plugins.Count} plugins."); + PluginsLoaded?.Invoke(_plugins.Values.AsReadOnly()); } private void DownloadPluginUpdates() @@ -307,14 +309,14 @@ namespace Torch.Managers plugin.Manifest = manifest; plugin.StoragePath = Torch.Config.InstancePath; plugin.Torch = Torch; - Plugins.Add(manifest.Guid, plugin); + _plugins.Add(manifest.Guid, plugin); _commandManager.RegisterPluginCommands(plugin); } /// public IEnumerator GetEnumerator() { - return Plugins.Values.GetEnumerator(); + return _plugins.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() diff --git a/Torch/Torch.csproj b/Torch/Torch.csproj index 464bf34..bab46f8 100644 --- a/Torch/Torch.csproj +++ b/Torch/Torch.csproj @@ -157,6 +157,7 @@ +