/// <summary> /// 插件 /// </summary> /// <param name="query"></param> /// <returns></returns> public async Task <ActionResult <ResponseModel> > Plugins(string query = "") { ResponseModel responseDTO = new ResponseModel(); IList <PluginRegistryResponseModel> pluginRegistryModels = new List <PluginRegistryResponseModel>(); try { // 1. TODO: 从json文件中读取插件订阅源 registry url string registryUrl = ""; // 2. TODO: 向订阅源发送 http get 获取插件列表信息 eg: http://rem-core-plugins-registry.moeci.com/?query=xxx IList <string> remotePluginIds = new List <string>(); // 3. 根据本地已有 PluginId 插件情况 状态赋值 PluginConfigModel pluginConfigModel = PluginConfigModelFactory.Create(); IList <string> localPluginIds = pluginConfigModel.EnabledPlugins.Concat(pluginConfigModel.DisabledPlugins).Concat(pluginConfigModel.UninstalledPlugins).ToList(); responseDTO.code = 1; responseDTO.message = "获取远程插件数据成功"; responseDTO.data = pluginRegistryModels; } catch (Exception ex) { responseDTO.code = -1; responseDTO.message = "获取远程插件数据失败: " + ex.Message; responseDTO.data = pluginRegistryModels; } return(await Task.FromResult(responseDTO)); }
public static void AddPluginFramework(this IServiceCollection services) { // 用于添加插件Controller 时,通知Controller.Action发生变化 services.AddSingleton <IActionDescriptorChangeProvider>(PluginActionDescriptorChangeProvider.Instance); services.AddSingleton(PluginActionDescriptorChangeProvider.Instance); services.AddTransient <PluginControllerManager>(); services.AddTransient <PluginManager>(); services.AddTransient <PluginFinder>(); using (var serviceProvider = services.BuildServiceProvider()) { using (var scope = serviceProvider.GetRequiredService <IServiceScopeFactory>().CreateScope()) { PluginManager pluginManager = scope.ServiceProvider.GetService <PluginManager>(); // 在程序启动时加载所有 已安装的插件 // 获取PluginConfigModel #region 获取 获取PluginConfigModel PluginConfigModel pluginConfigModel = PluginConfigModelFactory.Create(); #endregion // 已启用的插件 #region 加载 已启用插件的Assemblies IList <string> enabledPluginIds = pluginConfigModel.EnabledPlugins; foreach (var pluginId in enabledPluginIds) { pluginManager.LoadPlugin(pluginId); } #endregion } } }
public async Task <ActionResult <ResponseModel> > Delete(string pluginId) { ResponseModel responseData = new ResponseModel(); var pluginConfigModel = PluginConfigModelFactory.Create(); // 效验是否存在于 已卸载插件列表 if (!pluginConfigModel.UninstalledPlugins.Contains(pluginId)) { responseData.code = -1; responseData.message = "删除失败: 此插件不存在, 或未卸载"; return(await Task.FromResult(responseData)); } try { // 1.删除物理文件 string pluginPath = Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId); var directory = new DirectoryInfo(pluginPath); directory.Delete(true); // 2.从 pluginConfigModel.UninstalledPlugins 移除 pluginConfigModel.UninstalledPlugins.Remove(pluginId); // 3.保存到 plugin.config.json PluginConfigModelFactory.Save(pluginConfigModel); responseData.code = 1; responseData.message = "删除成功"; } catch (Exception ex) { responseData.code = -2; responseData.message = "删除失败: " + ex.Message; } return(await Task.FromResult(responseData)); }
public async Task <ActionResult <ResponseModel> > Install(string pluginId) { ResponseModel responseData = new ResponseModel(); PluginConfigModel pluginConfigModel = PluginConfigModelFactory.Create(); // TODO: 效验 #region 效验 if (string.IsNullOrEmpty(pluginId)) { responseData.code = -1; responseData.message = "安装失败, pluginId不能为空"; return(await Task.FromResult(responseData)); } #endregion try { // 1. 从 pluginConfigModel.UninstalledPlugins 移除, 添加到 pluginConfigModel.DisabledPlugins pluginConfigModel.UninstalledPlugins.Remove(pluginId); pluginConfigModel.DisabledPlugins.Add(pluginId); // 2.保存到 plugin.config.json PluginConfigModelFactory.Save(pluginConfigModel); responseData.code = 1; responseData.message = "安装成功"; } catch (Exception ex) { responseData.code = -1; responseData.message = "安装失败: " + ex.Message; return(await Task.FromResult(responseData)); } return(await Task.FromResult(responseData)); }
public async Task <ActionResult <ResponseModel> > Settings(string pluginId) { ResponseModel responseData = new ResponseModel(); try { #region 效验 var pluginConfigModel = PluginConfigModelFactory.Create(); var allPluginConfigModels = pluginConfigModel.EnabledPlugins.Concat(pluginConfigModel.DisabledPlugins) .Concat(pluginConfigModel.UninstalledPlugins).ToList(); if (!allPluginConfigModels.Contains(pluginId)) { responseData.code = -1; responseData.message = $"查看设置失败: 不存在 {pluginId} 插件"; return(await Task.FromResult(responseData)); } #endregion string settingsJsonStr = PluginSettingsModelFactory.Create(pluginId); responseData.code = 1; responseData.message = "查看设置成功"; responseData.data = settingsJsonStr ?? "无设置项"; } catch (Exception ex) { responseData.code = -1; responseData.message = "查看设置失败: " + ex.Message; } return(await Task.FromResult(responseData)); }
public async Task <ActionResult <ResponseModel> > Uninstall(string pluginId) { ResponseModel responseData = new ResponseModel(); var pluginConfigModel = PluginConfigModelFactory.Create(); // 卸载插件 必须 先禁用插件 #region 效验 if (pluginConfigModel.UninstalledPlugins.Contains(pluginId)) { responseData.code = -3; responseData.message = "卸载失败: 此插件已卸载"; return(await Task.FromResult(responseData)); } if (pluginConfigModel.EnabledPlugins.Contains(pluginId)) { responseData.code = -1; responseData.message = "卸载失败: 请先禁用此插件"; return(await Task.FromResult(responseData)); } if (!pluginConfigModel.DisabledPlugins.Contains(pluginId)) { responseData.code = -2; responseData.message = "卸载失败: 此插件不存在"; return(await Task.FromResult(responseData)); } #endregion try { // PS:卸载插件必须先禁用插件,所以此时插件LoadContext已被移除释放(插件Assemblies已被释放), 此处不需移除LoadContext // 1.从 pluginConfigModel.DisabledPlugins 移除, 添加到 pluginConfigModel.UninstalledPlugins pluginConfigModel.DisabledPlugins.Remove(pluginId); pluginConfigModel.UninstalledPlugins.Add(pluginId); // 2.保存到 plugin.config.json PluginConfigModelFactory.Save(pluginConfigModel); responseData.code = 1; responseData.message = "卸载成功"; } catch (Exception ex) { responseData.code = -1; responseData.message = "卸载失败: " + ex.Message; } return(await Task.FromResult(responseData)); }
/// <summary> /// 加载插件列表 /// </summary> /// <param name="status">插件状态</param> /// <returns></returns> public async Task <ActionResult <ResponseModel> > List(string status = "all") { ResponseModel responseData = new ResponseModel(); var pluginConfigModel = PluginConfigModelFactory.Create(); // 获取所有插件信息 IList <PluginInfoModel> pluginInfoModels = PluginInfoModelFactory.CreateAll(); IList <PluginInfoResponseModel> responseModels = new List <PluginInfoResponseModel>(); // 添加插件状态 responseModels = PluginInfoModelToResponseModel(pluginInfoModels, pluginConfigModel); #region 筛选插件状态 switch (status.ToLower()) { case "all": break; case "installed": responseModels = responseModels.Where(m => m.Status == PluginStatus.Enabled || m.Status == PluginStatus.Disabled).ToList(); break; case "enabled": responseModels = responseModels.Where(m => m.Status == PluginStatus.Enabled).ToList(); break; case "disabled": responseModels = responseModels.Where(m => m.Status == PluginStatus.Disabled).ToList(); break; case "uninstalled": responseModels = responseModels.Where(m => m.Status == PluginStatus.Uninstalled).ToList(); break; default: break; } #endregion responseData.code = 1; responseData.message = "加载插件列表成功"; responseData.data = responseModels; return(await Task.FromResult(responseData)); }
public async Task <ActionResult <ResponseModel> > Details(string pluginId) { ResponseModel responseData = new ResponseModel(); try { var pluginConfigModel = PluginConfigModelFactory.Create(); var allPluginConfigModels = pluginConfigModel.EnabledPlugins.Concat(pluginConfigModel.DisabledPlugins) .Concat(pluginConfigModel.UninstalledPlugins).ToList(); #region 效验 if (!allPluginConfigModels.Contains(pluginId)) { responseData.code = -1; responseData.message = $"查看详细失败: 不存在 {pluginId} 插件"; return(await Task.FromResult(responseData)); } #endregion PluginInfoModel pluginInfoModel = PluginInfoModelFactory.Create(pluginId); PluginInfoResponseModel pluginInfoResponseModel = PluginInfoModelToResponseModel(new List <PluginInfoModel>() { pluginInfoModel }, pluginConfigModel).FirstOrDefault(); responseData.code = 1; responseData.message = "查看详细成功"; responseData.data = pluginInfoResponseModel; } catch (Exception ex) { responseData.code = -1; responseData.message = "查看详细失败: " + ex.Message; } return(await Task.FromResult(responseData)); }
public async Task <ActionResult <ResponseModel> > Readme(string pluginId) { ResponseModel responseData = new ResponseModel(); try { var pluginConfigModel = PluginConfigModelFactory.Create(); var allPluginConfigModels = pluginConfigModel.EnabledPlugins.Concat(pluginConfigModel.DisabledPlugins) .Concat(pluginConfigModel.UninstalledPlugins).ToList(); #region 效验 if (!allPluginConfigModels.Contains(pluginId)) { responseData.code = -1; responseData.message = $"查看文档失败: 不存在 {pluginId} 插件"; return(await Task.FromResult(responseData)); } #endregion PluginReadmeModel readmeModel = PluginReadmeModelFactory.Create(pluginId); PluginReadmeResponseModel readmeResponseModel = new PluginReadmeResponseModel(); readmeResponseModel.Content = readmeModel?.Content ?? ""; readmeResponseModel.PluginId = pluginId; responseData.code = 1; responseData.message = "查看文档成功"; responseData.data = readmeResponseModel; } catch (Exception ex) { responseData.code = -1; responseData.message = "查看文档失败: " + ex.Message; } return(await Task.FromResult(responseData)); }
public async Task <ActionResult <ResponseModel> > Settings(PluginSettingsInputModel inputModel) { ResponseModel responseData = new ResponseModel(); try { #region 效验 var pluginConfigModel = PluginConfigModelFactory.Create(); var allPluginConfigModels = pluginConfigModel.EnabledPlugins.Concat(pluginConfigModel.DisabledPlugins) .Concat(pluginConfigModel.UninstalledPlugins).ToList(); if (!allPluginConfigModels.Contains(inputModel.PluginId)) { responseData.code = -1; responseData.message = $"设置失败: 不存在 {inputModel.PluginId} 插件"; return(await Task.FromResult(responseData)); } #endregion inputModel.Data = inputModel.Data ?? ""; PluginSettingsModelFactory.Save(pluginSettingsJsonStr: inputModel.Data, pluginId: inputModel.PluginId); responseData.code = 1; responseData.message = "设置成功"; responseData.data = inputModel.Data; } catch (Exception ex) { responseData.code = -1; responseData.message = "设置失败: " + ex.Message; } return(await Task.FromResult(responseData)); }
/// <summary> /// 上传插件 /// </summary> /// <param name="file">注意: 参数名一定为 file, 对应前端传过来时以 file 为名</param> /// <returns></returns> public async Task <ActionResult <ResponseModel> > Upload([FromForm] IFormFile file) { ResponseModel responseData = new ResponseModel(); #region 效验 if (file == null) { responseData.code = -1; responseData.message = "上传的文件不能为空"; return(responseData); } //文件后缀 string fileExtension = Path.GetExtension(file.FileName);//获取文件格式,拓展名 if (fileExtension != ".zip") { responseData.code = -1; responseData.message = "只能上传zip格式文件"; return(responseData); } //判断文件大小 var fileSize = file.Length; if (fileSize > 1024 * 1024 * 5) // 5M { responseData.code = -1; responseData.message = "上传的文件不能大于5MB"; return(responseData); } #endregion try { // 1.先上传到 临时插件上传目录, 用Guid.zip作为保存文件名 string tempZipFilePath = Path.Combine(PluginPathProvider.TempPluginUploadDir(), Guid.NewGuid() + ".zip"); using (var fs = System.IO.File.Create(tempZipFilePath)) { file.CopyTo(fs); //将上传的文件文件流,复制到fs中 fs.Flush(); //清空文件流 } // 2.解压 bool isDecomparessSuccess = Core.Common.ZipHelper.DecomparessFile(tempZipFilePath, tempZipFilePath.Replace(".zip", "")); // 3.删除原压缩包 System.IO.File.Delete(tempZipFilePath); if (!isDecomparessSuccess) { responseData.code = -1; responseData.message = "解压插件压缩包失败"; return(responseData); } // 4.读取其中的info.json, 获取 PluginId 值 PluginInfoModel pluginInfoModel = PluginInfoModelFactory.ReadPluginDir(tempZipFilePath.Replace(".zip", "")); if (pluginInfoModel == null || string.IsNullOrEmpty(pluginInfoModel.PluginId)) { // 记得删除已不再需要的临时插件文件夹 Directory.Delete(tempZipFilePath.Replace(".zip", ""), true); responseData.code = -1; responseData.message = "不合法的插件"; return(responseData); } string pluginId = pluginInfoModel.PluginId; // 5.检索 此 PluginId 是否本地插件已存在 var pluginConfigModel = PluginConfigModelFactory.Create(); // 本地已经存在的 PluginId IList <string> localExistPluginIds = pluginConfigModel.EnabledPlugins.Concat(pluginConfigModel.DisabledPlugins).Concat(pluginConfigModel.UninstalledPlugins).ToList(); if (localExistPluginIds.Contains(pluginId)) { // 记得删除已不再需要的临时插件文件夹 Directory.Delete(tempZipFilePath.Replace(".zip", ""), true); responseData.code = -1; responseData.message = $"本地已有此插件 (PluginId: {pluginId}), 请前往插件列表删除后, 再上传"; return(responseData); } // 6.本地无此插件 -> 移动插件文件夹到 Plugins 下, 并以 PluginId 为插件文件夹名 string pluginsRootPath = PluginPathProvider.PluginsRootPath(); string newPluginDir = Path.Combine(pluginsRootPath, pluginId); Directory.Move(tempZipFilePath.Replace(".zip", ""), newPluginDir); // 7. 加入 PluginConfigModel.UninstalledPlugins pluginConfigModel.UninstalledPlugins.Add(pluginId); PluginConfigModelFactory.Save(pluginConfigModel); responseData.code = 1; responseData.message = $"上传插件成功 (PluginId: {pluginId})"; } catch (Exception ex) { responseData.code = -1; responseData.message = "上传插件失败: " + ex.Message; } return(await Task.FromResult(responseData)); }
public async Task <ActionResult <ResponseModel> > Disable(string pluginId) { ResponseModel responseData = new ResponseModel(); var pluginConfigModel = PluginConfigModelFactory.Create(); // 效验是否存在于 已启用插件列表 #region 效验 if (!pluginConfigModel.EnabledPlugins.Contains(pluginId)) { responseData.code = -1; responseData.message = "禁用失败: 此插件不存在, 或未安装"; return(await Task.FromResult(responseData)); } #endregion try { // 1. 找到此插件实例 IPlugin plugin = _pluginFinder.Plugin(pluginId); if (plugin == null) { responseData.code = -1; responseData.message = "禁用失败: 此插件不存在, 或未启用"; return(await Task.FromResult(responseData)); } try { // 2.调取插件的 BeforeDisable(), 插件开发者可在此回收资源 var pluginDisableResult = plugin.BeforeDisable(); if (!pluginDisableResult.IsSuccess) { responseData.code = -1; responseData.message = "禁用失败: 来自插件的错误信息: " + pluginDisableResult.Message; return(await Task.FromResult(responseData)); } // 3.移除插件对应的程序集加载上下文 _pluginManager.UnloadPlugin(pluginId); // 4.从 pluginConfigModel.EnabledPlugins 移除 pluginConfigModel.EnabledPlugins.Remove(pluginId); // 5. 添加到 pluginConfigModel.DisabledPlugins pluginConfigModel.DisabledPlugins.Add(pluginId); // 6.保存到 plugin.config.json PluginConfigModelFactory.Save(pluginConfigModel); } catch (Exception ex) { responseData.code = -1; responseData.message = "禁用失败: 此插件不存在, 或未启用"; return(await Task.FromResult(responseData)); } responseData.code = 1; responseData.message = "禁用成功"; } catch (Exception ex) { responseData.code = -2; responseData.message = "禁用失败: " + ex.Message; } return(await Task.FromResult(responseData)); }
public async Task <ActionResult <ResponseModel> > Enable(string pluginId) { ResponseModel responseData = new ResponseModel(); var pluginConfigModel = PluginConfigModelFactory.Create(); // 效验是否存在于 已禁用插件列表 #region 效验 if (!pluginConfigModel.DisabledPlugins.Contains(pluginId)) { responseData.code = -1; responseData.message = "启用失败: 此插件不存在, 或未安装"; return(await Task.FromResult(responseData)); } #endregion try { // 1. 创建插件程序集加载上下文, 添加到 PluginsLoadContexts _pluginManager.LoadPlugin(pluginId); // 2.从 pluginConfigModel.DisabledPlugins 移除 pluginConfigModel.DisabledPlugins.Remove(pluginId); // 3. 添加到 pluginConfigModel.EnabledPlugins pluginConfigModel.EnabledPlugins.Add(pluginId); // 4.保存到 plugin.config.json PluginConfigModelFactory.Save(pluginConfigModel); // 5. 找到此插件实例 IPlugin plugin = _pluginFinder.Plugin(pluginId); if (plugin == null) { responseData.code = -1; responseData.message = "启用失败: 此插件不存在, 或未安装"; return(await Task.FromResult(responseData)); } // 6.调取插件的 AfterEnable(), 插件开发者可在此回收资源 var pluginEnableResult = plugin.AfterEnable(); if (!pluginEnableResult.IsSuccess) { // 7.启用不成功, 回滚插件状态: (1)释放插件上下文 (2)更新 plugin.config.json _pluginManager.UnloadPlugin(pluginId); // 从 pluginConfigModel.EnabledPlugins 移除 pluginConfigModel.EnabledPlugins.Remove(pluginId); // 添加到 pluginConfigModel.DisabledPlugins pluginConfigModel.DisabledPlugins.Add(pluginId); // 保存到 plugin.config.json PluginConfigModelFactory.Save(pluginConfigModel); responseData.code = -1; responseData.message = "启用失败: 来自插件的错误信息: " + pluginEnableResult.Message; return(await Task.FromResult(responseData)); } responseData.code = 1; responseData.message = "启用成功"; } catch (Exception ex) { responseData.code = -2; responseData.message = "启用失败: " + ex.Message; } return(await Task.FromResult(responseData)); }