You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
10 KiB
275 lines
10 KiB
|
3 months ago
|
//------------------------------------------------------------------------------
|
||
|
|
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||
|
|
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||
|
|
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||
|
|
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||
|
|
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||
|
|
// Github源代码仓库:https://github.com/RRQM
|
||
|
|
// API首页:https://www.yuque.com/rrqm/touchsocket/index
|
||
|
|
// 交流QQ群:234762506
|
||
|
|
// 感谢您的下载和使用
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
using System;
|
||
|
|
using System.Collections;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Linq;
|
||
|
|
using System.Reflection;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
|
||
|
|
namespace TouchSocket.Core
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 表示插件管理器。
|
||
|
|
/// </summary>
|
||
|
|
public class PluginsManager : IPluginsManager
|
||
|
|
{
|
||
|
|
private readonly Dictionary<Type, Dictionary<string, PluginMethod>> m_pluginInfoes = new Dictionary<Type, Dictionary<string, PluginMethod>>();
|
||
|
|
private readonly List<PluginModel> m_plugins = new List<PluginModel>();
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 构造函数
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="container"></param>
|
||
|
|
public PluginsManager(IContainer container)
|
||
|
|
{
|
||
|
|
Container = container;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public IContainer Container { get; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public bool Enable { get; set; } = true;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 添加插件
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="plugin">插件</param>
|
||
|
|
/// <exception cref="ArgumentNullException"></exception>
|
||
|
|
void IPluginsManager.Add(IPlugin plugin)
|
||
|
|
{
|
||
|
|
lock (this)
|
||
|
|
{
|
||
|
|
if (plugin == null)
|
||
|
|
{
|
||
|
|
throw new ArgumentNullException();
|
||
|
|
}
|
||
|
|
if (plugin.GetType().GetCustomAttribute<SingletonPluginAttribute>() is SingletonPluginAttribute singletonPlugin)
|
||
|
|
{
|
||
|
|
foreach (var item in m_plugins)
|
||
|
|
{
|
||
|
|
if (item.PluginType == plugin.GetType())
|
||
|
|
{
|
||
|
|
throw new InvalidOperationException($"插件{plugin.GetType()}不能重复使用。");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
m_plugins.Add(new PluginModel(plugin, plugin.GetType()));
|
||
|
|
var types = plugin.GetType().GetInterfaces().Where(a => typeof(IPlugin).IsAssignableFrom(a)).ToArray();
|
||
|
|
foreach (var type in types)
|
||
|
|
{
|
||
|
|
if (!m_pluginInfoes.ContainsKey(type))
|
||
|
|
{
|
||
|
|
Dictionary<string, PluginMethod> pairs = new Dictionary<string, PluginMethod>();
|
||
|
|
var ms = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
|
||
|
|
foreach (var item in ms)
|
||
|
|
{
|
||
|
|
if (item.GetParameters().Length == 2 && typeof(TouchSocketEventArgs).IsAssignableFrom(item.GetParameters()[1].ParameterType))
|
||
|
|
{
|
||
|
|
if (pairs.ContainsKey(item.Name))
|
||
|
|
{
|
||
|
|
throw new Exception("插件的接口方法不允许重载");
|
||
|
|
}
|
||
|
|
PluginMethod pluginMethod = new PluginMethod(type);
|
||
|
|
if (item.GetCustomAttribute<AsyncRaiserAttribute>() != null)
|
||
|
|
{
|
||
|
|
var asyncMethod = type.GetMethod($"{item.Name}Async", BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
|
||
|
|
if (asyncMethod == null)
|
||
|
|
{
|
||
|
|
throw new Exception("当接口标识为异步时,还应当定义其异步方法,以“Async”结尾");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (asyncMethod.GetParameters().Length != 2 && typeof(TouchSocketEventArgs).IsAssignableFrom(asyncMethod.GetParameters()[1].ParameterType))
|
||
|
|
{
|
||
|
|
throw new Exception("异步接口方法不符合设定");
|
||
|
|
}
|
||
|
|
if (asyncMethod.ReturnType != typeof(Task))
|
||
|
|
{
|
||
|
|
throw new Exception("异步接口方法返回值必须为Task。");
|
||
|
|
}
|
||
|
|
pluginMethod.MethodAsync=new Method(asyncMethod);
|
||
|
|
}
|
||
|
|
pluginMethod.Method = new Method(item);
|
||
|
|
pairs.Add(item.Name, pluginMethod);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
m_pluginInfoes.Add(type, pairs);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
m_plugins.Sort(delegate (PluginModel x, PluginModel y)
|
||
|
|
{
|
||
|
|
if (x.Plugin.Order == y.Plugin.Order) return 0;
|
||
|
|
else if (x.Plugin.Order < y.Plugin.Order) return 1;
|
||
|
|
else return -1;
|
||
|
|
});
|
||
|
|
|
||
|
|
Container.RegisterSingleton(plugin);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 清除所有插件
|
||
|
|
/// </summary>
|
||
|
|
void IPluginsManager.Clear()
|
||
|
|
{
|
||
|
|
lock (this)
|
||
|
|
{
|
||
|
|
foreach (var item in m_plugins)
|
||
|
|
{
|
||
|
|
item.Plugin.SafeDispose();
|
||
|
|
}
|
||
|
|
m_plugins.Clear();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
IEnumerator<IPlugin> IEnumerable<IPlugin>.GetEnumerator()
|
||
|
|
{
|
||
|
|
lock (this)
|
||
|
|
{
|
||
|
|
return m_plugins.Select(a => a.Plugin).GetEnumerator();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
IEnumerator IEnumerable.GetEnumerator()
|
||
|
|
{
|
||
|
|
lock (this)
|
||
|
|
{
|
||
|
|
return m_plugins.Select(a => a.Plugin).GetEnumerator();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 触发对应方法
|
||
|
|
/// </summary>
|
||
|
|
/// <typeparam name="TPlugin">接口类型,此处也必须是接口类型</typeparam>
|
||
|
|
/// <param name="name">触发名称</param>
|
||
|
|
/// <param name="sender"></param>
|
||
|
|
/// <param name="e"></param>
|
||
|
|
bool IPluginsManager.Raise<TPlugin>(string name, object sender, TouchSocketEventArgs e)
|
||
|
|
{
|
||
|
|
if (!Enable)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (m_pluginInfoes.TryGetValue(typeof(TPlugin), out var value))
|
||
|
|
{
|
||
|
|
if (value.TryGetValue(name, out PluginMethod pluginMethod))
|
||
|
|
{
|
||
|
|
for (int i = 0; i < m_plugins.Count; i++)
|
||
|
|
{
|
||
|
|
if (e.Handled)
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
if (pluginMethod.Type.IsAssignableFrom(m_plugins[i].PluginType))
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
pluginMethod.Method.Invoke(m_plugins[i].Plugin, sender, e);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
Container.Resolve<ILog>()?.Exception(ex);
|
||
|
|
}
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
pluginMethod.MethodAsync?.InvokeAsync(m_plugins[i].Plugin, sender, e);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
Container.Resolve<ILog>()?.Exception(ex);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 移除插件
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="plugin"></param>
|
||
|
|
void IPluginsManager.Remove(IPlugin plugin)
|
||
|
|
{
|
||
|
|
lock (this)
|
||
|
|
{
|
||
|
|
if (plugin == null)
|
||
|
|
{
|
||
|
|
throw new ArgumentNullException();
|
||
|
|
}
|
||
|
|
foreach (var item in m_plugins)
|
||
|
|
{
|
||
|
|
if (plugin == item.Plugin)
|
||
|
|
{
|
||
|
|
if (m_plugins.Remove(item))
|
||
|
|
{
|
||
|
|
plugin.SafeDispose();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 移除插件
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="type"></param>
|
||
|
|
void IPluginsManager.Remove(Type type)
|
||
|
|
{
|
||
|
|
lock (this)
|
||
|
|
{
|
||
|
|
for (int i = m_plugins.Count - 1; i >= 0; i--)
|
||
|
|
{
|
||
|
|
IPlugin plugin = m_plugins[i].Plugin;
|
||
|
|
if (plugin.GetType() == type)
|
||
|
|
{
|
||
|
|
m_plugins.RemoveAt(i);
|
||
|
|
plugin.SafeDispose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
internal class PluginMethod
|
||
|
|
{
|
||
|
|
public PluginMethod(Type type)
|
||
|
|
{
|
||
|
|
this.Type = type;
|
||
|
|
}
|
||
|
|
public Method Method;
|
||
|
|
public Method MethodAsync;
|
||
|
|
public readonly Type Type;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal class PluginModel
|
||
|
|
{
|
||
|
|
public PluginModel(IPlugin plugin, Type pluginType)
|
||
|
|
{
|
||
|
|
Plugin = plugin;
|
||
|
|
PluginType = pluginType;
|
||
|
|
}
|
||
|
|
|
||
|
|
public IPlugin Plugin;
|
||
|
|
public Type PluginType;
|
||
|
|
}
|
||
|
|
}
|