wenxiangchao
4 天以前 559890c482f5973f06aafdfec9550fee5ba3c7f2
HMI.Base/PluginLoader.cs
@@ -1,32 +1,41 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.IO;
using System.Reflection;
using System.Windows.Media.Imaging;
using HMI.Core.Api;
using HMI.Core.Api;
using HMI.Core.Entity;
using HMI.Core.Util;
using log4net;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
namespace HMI.Base
{
    public class PluginLoader
    {
        private static ILog log = LogManager.GetLogger("PluginLoader");
        private static string PluginFolder = PathHelper.PluginFolder();
        public bool Completed { get; private set; } = false;
        public SqliteHelper sqliteHelper;
        public ObservableCollection<PluginInfo> Menus { get; private set; }
        public ObservableCollection<PluginInfo> Plugins { get; private set; }
        public List<PluginInfo> Menus { get; private set; }
        public List<PluginInfo> Plugins { get; private set; }
        public static PluginLoader Instance { get; private set; }
        public event EventHandler<string> LoadMessageAppend;
        public event EventHandler<LoadMsg> LoadMessageAppend;
        private PluginLoader()
        {
            sqliteHelper = new SqliteHelper(PathHelper.DatabasePath);
        }
        public static void Reset()
        {
            if (Instance != null)
            {
                Instance = null;
            }
            GC.Collect();
        }
        public static PluginLoader GetLoader()
@@ -38,95 +47,188 @@
            return Instance;
        }
        public void LoadMenuAndPlugin()
        private IPluginContainer pluginContainer;
        public void LoadMenuAndPlugin(IPluginContainer container, Dispatcher dispatcher)
        {
            pluginContainer = container;
            if (Menus == null)
            {
                Plugins = new ObservableCollection<PluginInfo>();
                Menus = LoadTreeMenu();
                Plugins = new List<PluginInfo>();
                Menus = LoadTreeMenu(dispatcher);
                sqliteHelper.Close();
                LoadMessageAppend?.Invoke(this, new LoadMsg { Type = LoadMsgType.FINISHED });
            }
            pluginContainer.DoCloseEvent += PluginContainer_DoCloseEvent;
        }
        private void PluginContainer_DoCloseEvent(object sender, EventArgs e)
        {
            Reset();
        }
        private void LoadChildrenMenu()
        {
            foreach (var menu in Plugins)
            {
                CountdownEvent c = new CountdownEvent(1);
                Thread.Sleep(50);
                Application.Current.Dispatcher.Invoke(new Action(() =>
                {
                    try
                    {
                        var start = DateTime.Now;
                        log.Info(this.lang("App.IsLoadingMenu", menu.Name));
                        LoadMessageAppend?.Invoke(this,
                            new LoadMsg
                            {
                                Type = LoadMsgType.LOADING,
                                Message = this.lang("App.IsLoadingMenu", menu.Name)
                            }
                        );
                        if (!string.IsNullOrEmpty(menu.DllPath))
                        {
                            string dllPath = Path.Combine(PluginFolder, menu.DllPath);
                            Assembly ass = Assembly.LoadFrom(dllPath);
                            var tss = ass.GetTypes();
                            Type ClassType = ass.GetType(menu.ClassName);
                            object Instance = Activator.CreateInstance(ClassType);
                            menu.Content = Instance;
                            if (Instance is IPlugin plugin)
                            {
                            }
                            else
                            {
                                plugin = new PluginPackage(Instance);
                            }
                            plugin.SetLogger(LogManager.GetLogger(menu.Code));
                            string configFolder = Path.Combine(PathHelper.ConfigFolder, menu.Code);
                            if (!Directory.Exists(configFolder))
                            {
                                Directory.CreateDirectory(configFolder);
                            }
                            plugin.SetBaseFolder(configFolder);
                            plugin.InitFinish();
                            pluginContainer.OnCloseEvent += plugin.OnClose;
                            pluginContainer.DoCloseEvent += plugin.DoClose;
                            Type SettingType = ass.GetType($"{menu.ClassName}_Setting");
                            if (SettingType != null)
                            {
                                object SettingInstance = Activator.CreateInstance(SettingType);
                                if (SettingInstance is IFolderOwner fo)
                                {
                                    fo.SetBaseFolder(configFolder);
                                }
                                menu.SettingControl = SettingInstance;
                            }
                        }
                        log.Info($"{this.lang("App.MenuLoadSuccess", menu.Name)} Cost: {(DateTime.Now - start).TotalMilliseconds}ms");
                        LoadMessageAppend?.Invoke(this,
                            new LoadMsg
                            {
                                Type = LoadMsgType.LOADING,
                                Result = true,
                                Message = this.lang("App.MenuLoadSuccess", menu.Name),
                            });
                    }
                    catch (Exception ex)
                    {
                        log.Error($"Load Plugin [{menu.Name}] Failed.", ex);
                        LoadMessageAppend?.Invoke(this, new LoadMsg
                        {
                            Type = LoadMsgType.LOADING,
                            Result = false,
                            Message = this.lang("App.MenuLoadFailed", menu.Name, ex.Message, ex.StackTrace)
                        });
                    }
                    finally
                    {
                        c.Signal();
                    }
                }));
                c.Wait();
            }
        }
        private void LoadChildrenMenu(PluginInfo menu)
        private PluginInfo ConvertPermission2PluginInfo(PermissionData data)
        {
            LoadMessageAppend?.Invoke(this, $"正在加载{menu.Name}菜单...");
            try
            if (data.Type == "权限") return null;
            PluginInfo info = new PluginInfo
            {
                if (!string.IsNullOrEmpty(menu.DllPath))
                Code = data.Code,
                Name = data.Name,
                Type = data.Type,
                ParentCode = data.ParentCode,
                DllPath = data.DllPath,
                ClassName = data.ClassName,
                IconFont = data.IconFont
                //Icon = new BitmapImage(new Uri(Path.Combine(PathHelper.IconFolder, dr["iconPath"].ToString())))
            };
            if (data.Children != null && data.Children.Count > 0)
            {
                foreach (var child in data.Children)
                {
                    string dllPath = Path.Combine(PluginFolder, menu.DllPath);
                    Assembly ass = Assembly.LoadFrom(dllPath);
                    Type ClassType = ass.GetType(menu.ClassName);
                    object Instance = Activator.CreateInstance(ClassType);
                    menu.Content = Instance;
                    if (Instance is IPlugin plugin)
                    {
                        plugin.SetLogger(LogManager.GetLogger(menu.Code));
                        string configFolder = Path.Combine(PathHelper.ConfigFolder, menu.Code);
                        if (!Directory.Exists(configFolder))
                        {
                            Directory.CreateDirectory(configFolder);
                        }
                        plugin.SetBaseFolder(configFolder);
                        plugin.InitFinish();
                    }
                    Type SettingType = ass.GetType($"{menu.ClassName}_Setting");
                    if (SettingType != null)
                    {
                        object SettingInstance = Activator.CreateInstance(SettingType);
                        menu.SettingControl = SettingInstance;
                    }
                    var childInfo = ConvertPermission2PluginInfo(child);
                    if (childInfo != null) info.Children.Add(childInfo);
                }
            }
            catch (Exception ex)
            {
                LoadMessageAppend?.Invoke(this, $"{ex.Message} {ex.StackTrace}");
            }
            return info;
        }
        public ObservableCollection<PluginInfo> LoadTreeMenu()
        public List<PluginInfo> LoadTreeMenu(Dispatcher dispatcher)
        {
            ObservableCollection<PluginInfo> data = new ObservableCollection<PluginInfo>();
            List<PluginInfo> menus = new List<PluginInfo>();
            Dictionary<string, PluginInfo> cache = new Dictionary<string, PluginInfo>();
            try
            {
                LoadMessageAppend?.Invoke(this, "开始加载菜单...");
                DataTable dt = sqliteHelper.GetDataTable(@"SELECT * FROM menu ORDER BY level,id;");
                if (dt != null)
                List<PermissionData> allPermissions = UserInfo.User?.AllPermissions;
                if (allPermissions != null)
                {
                    LoadMessageAppend?.Invoke(this, $"共有{dt.Rows.Count}条菜单待加载...");
                    foreach (DataRow dr in dt.Rows)
                    Application.Current.Dispatcher.Invoke(new Action(() =>
                    {
                        string path = Path.Combine(PathHelper.IconFolder, dr["iconPath"].ToString());
                        var menu = new PluginInfo
                        log.Info(this.lang("App.MenuCount", allPermissions.Count));
                        LoadMessageAppend?.Invoke(this,
                          new LoadMsg
                          {
                              Type = LoadMsgType.INIT,
                              NumData = allPermissions.Count,
                              Message = this.lang("App.MenuCount", allPermissions.Count),
                          });
                        foreach (PermissionData data in allPermissions)
                        {
                            Code = dr["code"].ToString(),
                            Name = dr["name"].ToString(),
                            ParentCode = dr["parentCode"].ToString(),
                            DllPath = dr["dllPath"].ToString(),
                            ClassName = dr["className"].ToString(),
                            Icon = new BitmapImage(new Uri(Path.Combine(PathHelper.IconFolder, dr["iconPath"].ToString())))
                        };
                        cache[menu.Code] = menu;
                        if (!cache.ContainsKey(menu.ParentCode))
                        {
                            data.Add(menu);
                            if (data.Type == "Permission") continue;
                            var menu = new PluginInfo
                            {
                                Code = data.Code,
                                Name = data.Name,
                                Type = data.Type,
                                ParentCode = data.ParentCode,
                                DllPath = data.DllPath,
                                ClassName = data.ClassName,
                                IconFont = data.IconFont
                            };
                            cache[menu.Code] = menu;
                            if (!cache.ContainsKey(menu.ParentCode))
                            {
                                menus.Add(menu);
                            }
                            else
                            {
                                cache[menu.ParentCode].Children.Add(menu);
                            }
                            Plugins.Add(menu);
                        }
                        else
                        {
                            cache[menu.ParentCode].Children.Add(menu);
                        }
                        Plugins.Add(menu);
                        LoadChildrenMenu(menu);
                    }
                    }));
                    LoadChildrenMenu();
                }
            }
            catch (Exception ex)
            {
                LoadMessageAppend?.Invoke(this, ex.Message);
                //LoadMessageAppend?.Invoke(this, ex.Message);
            }
            return data;
            return menus;
        }
    }
}