Expose read-only collections in PluginManager instead of full collections

This commit is contained in:
John Gross
2017-09-21 22:30:48 -07:00
parent 1f4197ce67
commit b7f2a62b3c
5 changed files with 72 additions and 15 deletions

View File

@@ -14,12 +14,12 @@ namespace Torch.API.Managers
/// <summary>
/// Fired when plugins are loaded.
/// </summary>
event Action<ICollection<ITorchPlugin>> PluginsLoaded;
event Action<IReadOnlyCollection<ITorchPlugin>> PluginsLoaded;
/// <summary>
/// Collection of loaded plugins.
/// </summary>
IDictionary<Guid, ITorchPlugin> Plugins { get; }
IReadOnlyDictionary<Guid, ITorchPlugin> Plugins { get; }
/// <summary>
/// Updates all loaded plugins.

View File

@@ -29,7 +29,7 @@ namespace Torch.Server.ViewModels
pluginManager.PluginsLoaded += PluginManager_PluginsLoaded;
}
private void PluginManager_PluginsLoaded(ICollection<ITorchPlugin> obj)
private void PluginManager_PluginsLoaded(IReadOnlyCollection<ITorchPlugin> obj)
{
Plugins.Clear();
foreach (var plugin in obj)

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Torch
{
public static class ICollectionExtensions
{
/// <summary>
/// Returns a read-only wrapped <see cref="ICollection{T}"/>
/// </summary>
public static IReadOnlyCollection<T> AsReadOnly<T>(this ICollection<T> source)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
return source as IReadOnlyCollection<T> ?? new ReadOnlyCollectionAdapter<T>(source);
}
/// <summary>
/// Returns a read-only wrapped <see cref="IList{T}"/>
/// </summary>
public static IReadOnlyList<T> AsReadOnly<T>(this IList<T> source)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
return source as IReadOnlyList<T> ?? new ReadOnlyCollection<T>(source);
}
/// <summary>
/// Returns a read-only wrapped <see cref="IDictionary{TKey, TValue}"/>
/// </summary>
public static IReadOnlyDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(this IDictionary<TKey, TValue> source)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
return source as IReadOnlyDictionary<TKey, TValue> ?? new ReadOnlyDictionary<TKey, TValue>(source);
}
sealed class ReadOnlyCollectionAdapter<T> : IReadOnlyCollection<T>
{
private readonly ICollection<T> _source;
public ReadOnlyCollectionAdapter(ICollection<T> source)
{
_source = source;
}
public int Count => _source.Count;
public IEnumerator<T> GetEnumerator() => _source.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
}

View File

@@ -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<Guid, ITorchPlugin> _plugins = new ObservableDictionary<Guid, ITorchPlugin>();
[Dependency]
private CommandManager _commandManager;
/// <inheritdoc />
public IDictionary<Guid, ITorchPlugin> Plugins { get; } = new ObservableDictionary<Guid, ITorchPlugin>();
public IReadOnlyDictionary<Guid, ITorchPlugin> Plugins => _plugins.AsReadOnly();
public event Action<ICollection<ITorchPlugin>> PluginsLoaded;
public event Action<IReadOnlyCollection<ITorchPlugin>> PluginsLoaded;
public PluginManager(ITorchBase torchInstance) : base(torchInstance)
{
@@ -44,7 +46,7 @@ namespace Torch.Managers
/// </summary>
public void UpdatePlugins()
{
foreach (var plugin in Plugins.Values)
foreach (var plugin in _plugins.Values)
plugin.Update();
}
@@ -53,10 +55,10 @@ namespace Torch.Managers
/// </summary>
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);
}
/// <inheritdoc cref="IEnumerable.GetEnumerator"/>
public IEnumerator<ITorchPlugin> GetEnumerator()
{
return Plugins.Values.GetEnumerator();
return _plugins.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()

View File

@@ -157,6 +157,7 @@
<Compile Include="ChatMessage.cs" />
<Compile Include="Collections\ObservableList.cs" />
<Compile Include="Extensions\DispatcherExtensions.cs" />
<Compile Include="Extensions\ICollectionExtensions.cs" />
<Compile Include="Managers\DependencyManager.cs" />
<Compile Include="Managers\PatchManager\AssemblyMemory.cs" />
<Compile Include="Managers\PatchManager\DecoratedMethod.cs" />