Unity Udexreal开发插件包
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

//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在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;
}
}