using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using DiscordBotCore.Interfaces.PluginManagement; using DiscordBotCore.Others; using DiscordBotCore.Plugin; namespace DiscordBotCore.Online; public sealed class PluginManager { private static readonly string _LibrariesBaseFolder = "Libraries"; private readonly IPluginRepository _PluginRepository; internal InstallingPluginInformation? InstallingPluginInformation { get; private set; } internal PluginManager(IPluginRepository pluginRepository) { _PluginRepository = pluginRepository; } public async Task> GetPluginsList() { var onlinePlugins = await _PluginRepository.GetAllPlugins(); if (!onlinePlugins.Any()) { Application.Log("Failed to get all plugins from the repository", LogType.Warning); return []; } int os = OS.GetOperatingSystemInt(); var response = onlinePlugins.Where(plugin => plugin.OperatingSystem == os).ToList(); return response; } public async Task GetPluginDataByName(string pluginName) { var plugin = await _PluginRepository.GetPluginByName(pluginName); if (plugin == null) { Application.Log("Failed to get plugin from the repository", LogType.Warning); return null; } return plugin; } private async Task RemovePluginFromDatabase(string pluginName) { List installedPlugins = await JsonManager.ConvertFromJson>(await File.ReadAllTextAsync(Application.CurrentApplication.PluginDatabase)); installedPlugins.RemoveAll(p => p.PluginName == pluginName); await JsonManager.SaveToJsonFile(Application.CurrentApplication.PluginDatabase, installedPlugins); } public async Task AppendPluginToDatabase(PluginInfo pluginData) { List installedPlugins = await JsonManager.ConvertFromJson>(await File.ReadAllTextAsync(Application.CurrentApplication.PluginDatabase)); foreach (var dependency in pluginData.ListOfExecutableDependencies) { pluginData.ListOfExecutableDependencies[dependency.Key] = dependency.Value; } installedPlugins.Add(pluginData); await JsonManager.SaveToJsonFile(Application.CurrentApplication.PluginDatabase, installedPlugins); } public async Task> GetInstalledPlugins() { return await JsonManager.ConvertFromJson>(await File.ReadAllTextAsync(Application.CurrentApplication.PluginDatabase)); } public async Task IsPluginInstalled(string pluginName) { List installedPlugins = await JsonManager.ConvertFromJson>(await File.ReadAllTextAsync(Application.CurrentApplication.PluginDatabase)); return installedPlugins.Any(plugin => plugin.PluginName == pluginName); } public async Task MarkPluginToUninstall(string pluginName) { List installedPlugins = await GetInstalledPlugins(); List info = installedPlugins.Where(info => info.PluginName == pluginName).ToList(); if (!info.Any()) return false; foreach (var item in info) { await RemovePluginFromDatabase(item.PluginName); item.IsMarkedToUninstall = true; await AppendPluginToDatabase(item); } return true; } public async Task UninstallMarkedPlugins() { IEnumerable installedPlugins = (await GetInstalledPlugins()).AsEnumerable(); IEnumerable pluginsToRemove = installedPlugins.Where(plugin => plugin.IsMarkedToUninstall).AsEnumerable(); foreach (var plugin in pluginsToRemove) { await UninstallPlugin(plugin); } } private async Task UninstallPlugin(PluginInfo pluginInfo) { File.Delete(pluginInfo.FilePath); foreach (var dependency in pluginInfo.ListOfExecutableDependencies) File.Delete(dependency.Value); await RemovePluginFromDatabase(pluginInfo.PluginName); if (Directory.Exists($"{_LibrariesBaseFolder}/{pluginInfo.PluginName}")) Directory.Delete($"{_LibrariesBaseFolder}/{pluginInfo.PluginName}", true); } public async Task GetDependencyLocation(string dependencyName) { List installedPlugins = await GetInstalledPlugins(); foreach (var plugin in installedPlugins) { if (plugin.ListOfExecutableDependencies.TryGetValue(dependencyName, out var dependencyPath)) { string relativePath = GenerateDependencyRelativePath(plugin.PluginName, dependencyPath); return relativePath; } } return null; } public async Task GetDependencyLocation(string dependencyName, string pluginName) { List installedPlugins = await GetInstalledPlugins(); foreach (var plugin in installedPlugins) { if (plugin.PluginName == pluginName && plugin.ListOfExecutableDependencies.ContainsKey(dependencyName)) { string dependencyPath = plugin.ListOfExecutableDependencies[dependencyName]; string relativePath = GenerateDependencyRelativePath(pluginName, dependencyPath); return relativePath; } } return null; } public string GenerateDependencyRelativePath(string pluginName, string dependencyPath) { string relative = $"./{_LibrariesBaseFolder}/{pluginName}/{dependencyPath}"; return relative; } public async Task InstallPluginNoProgress(OnlinePlugin plugin) { InstallingPluginInformation = new InstallingPluginInformation() { PluginName = plugin.PluginName }; List dependencies = await _PluginRepository.GetDependenciesForPlugin(plugin.PluginId); int totalSteps = dependencies.Count + 1; float stepFraction = 100f / totalSteps; float currentProgress = 0f; InstallingPluginInformation.IsInstalling = true; var progress = currentProgress; IProgress downloadProgress = new Progress(fileProgress => { InstallingPluginInformation.InstallationProgress = progress + (fileProgress / 100f) * stepFraction; }); await ServerCom.DownloadFileAsync(plugin.PluginLink, $"{Application.CurrentApplication.ApplicationEnvironmentVariables.Get("PluginFolder")}/{plugin.PluginName}.dll", downloadProgress); currentProgress += stepFraction; if (dependencies.Count > 0) { foreach (var dependency in dependencies) { string dependencyLocation = GenerateDependencyRelativePath(plugin.PluginName, dependency.DownloadLocation); await ServerCom.DownloadFileAsync(dependency.DownloadLink, dependencyLocation, downloadProgress); currentProgress += stepFraction; } } PluginInfo pluginInfo = PluginInfo.FromOnlineInfo(plugin, dependencies); await AppendPluginToDatabase(pluginInfo); InstallingPluginInformation.IsInstalling = false; } public async Task, List>> GatherInstallDataForPlugin(OnlinePlugin plugin) { List dependencies = await _PluginRepository.GetDependenciesForPlugin(plugin.PluginId); var downloads = new Dictionary { { $"{Application.CurrentApplication.ApplicationEnvironmentVariables.Get("PluginFolder")}/{plugin.PluginName}.dll", plugin.PluginLink } }; foreach(var dependency in dependencies) { string dependencyLocation = GenerateDependencyRelativePath(plugin.PluginName, dependency.DownloadLocation); downloads.Add(dependencyLocation, dependency.DownloadLink); } return (downloads, dependencies).ToTuple(); } public async Task SetEnabledStatus(string pluginName, bool status) { var plugins = await GetInstalledPlugins(); var plugin = plugins.Find(p => p.PluginName == pluginName); if (plugin == null) return; plugin.IsEnabled = status; await RemovePluginFromDatabase(pluginName); await AppendPluginToDatabase(plugin); } }