diff --git a/DiscordBotCore.PluginManagement/IPluginManager.cs b/DiscordBotCore.PluginManagement/IPluginManager.cs index d07a0da..35d8495 100644 --- a/DiscordBotCore.PluginManagement/IPluginManager.cs +++ b/DiscordBotCore.PluginManagement/IPluginManager.cs @@ -1,20 +1,20 @@ using DiscordBotCore.PluginManagement.Models; +using DiscordBotCore.Utilities.Responses; namespace DiscordBotCore.PluginManagement; public interface IPluginManager { Task> GetPluginsList(); - Task GetPluginDataByName(string pluginName); - Task GetPluginDataById(int pluginId); - Task AppendPluginToDatabase(LocalPlugin pluginData); + Task> GetPluginDataByName(string pluginName); + Task> GetPluginDataById(int pluginId); + Task> AppendPluginToDatabase(LocalPlugin pluginData); Task> GetInstalledPlugins(); - Task IsPluginInstalled(string pluginName); - Task GetDependencyLocation(string dependencyName); - Task GetDependencyLocation(string dependencyName, string pluginName); + Task> GetDependencyLocation(string dependencyName); + Task> GetDependencyLocation(string dependencyName, string pluginName); string GenerateDependencyRelativePath(string pluginName, string dependencyPath); - Task InstallPlugin(OnlinePlugin plugin, IProgress progress); + Task> InstallPlugin(OnlinePlugin plugin, IProgress progress); Task SetEnabledStatus(string pluginName, bool status); - Task UninstallPluginByName(string pluginName); - Task GetLocalPluginByName(string pluginName); + Task> UninstallPluginByName(string pluginName); + Task> GetLocalPluginByName(string pluginName); } \ No newline at end of file diff --git a/DiscordBotCore.PluginManagement/PluginManager.cs b/DiscordBotCore.PluginManagement/PluginManager.cs index 118a276..f7bf0b0 100644 --- a/DiscordBotCore.PluginManagement/PluginManager.cs +++ b/DiscordBotCore.PluginManagement/PluginManager.cs @@ -1,9 +1,11 @@ -using DiscordBotCore.Logging; +using System.Diagnostics; +using DiscordBotCore.Logging; using DiscordBotCore.Networking; using DiscordBotCore.PluginManagement.Helpers; using DiscordBotCore.PluginManagement.Models; using DiscordBotCore.Utilities; using DiscordBotCore.Configuration; +using DiscordBotCore.Utilities.Responses; using OperatingSystem = DiscordBotCore.Utilities.OperatingSystem; namespace DiscordBotCore.PluginManagement; @@ -36,53 +38,53 @@ public sealed class PluginManager : IPluginManager return onlinePlugins; } - public async Task GetPluginDataByName(string pluginName) + public async Task> GetPluginDataByName(string pluginName) { int os = OperatingSystem.GetOperatingSystemInt(); var plugin = await _PluginRepository.GetPluginByName(pluginName, os, false); - if (plugin == null) + if (plugin is null) { - _Logger.Log($"Plugin {pluginName} not found in the repository for operating system {OperatingSystem.GetOperatingSystemString((OperatingSystem.OperatingSystemEnum)os)}.", LogType.Warning); - return null; + return Response.Failure($"Plugin {pluginName} not found in the repository for operating system {OperatingSystem.GetOperatingSystemString((OperatingSystem.OperatingSystemEnum)os)}."); } - return plugin; + return Response.Success(plugin); } - public async Task GetPluginDataById(int pluginId) + public async Task> GetPluginDataById(int pluginId) { var plugin = await _PluginRepository.GetPluginById(pluginId); if (plugin is null) { - _Logger.Log($"Plugin {pluginId} not found in the repository.", this, LogType.Warning); - return null; + return Response.Failure($"Plugin {pluginId} not found in the repository."); } - return plugin; + return Response.Success(plugin); } - private async Task RemovePluginFromDatabase(string pluginName) + private async Task> RemovePluginFromDatabase(string pluginName) { string? pluginDatabaseFile = _Configuration.Get("PluginDatabase"); if (pluginDatabaseFile is null) { - throw new Exception("Plugin database file not found"); + return Response.Failure("PluginDatabase file path is not present in the config file"); } List installedPlugins = await JsonManager.ConvertFromJson>(await File.ReadAllTextAsync(pluginDatabaseFile)); installedPlugins.RemoveAll(p => p.PluginName == pluginName); await JsonManager.SaveToJsonFile(pluginDatabaseFile, installedPlugins); + + return Response.Success(); } - public async Task AppendPluginToDatabase(LocalPlugin pluginData) + public async Task> AppendPluginToDatabase(LocalPlugin pluginData) { string? pluginDatabaseFile = _Configuration.Get("PluginDatabase"); if (pluginDatabaseFile is null) { - throw new Exception("Plugin database file not found"); + return Response.Failure("PluginDatabase file path is not present in the config file"); } List installedPlugins = await GetInstalledPlugins(); @@ -100,6 +102,8 @@ public sealed class PluginManager : IPluginManager installedPlugins.Add(pluginData); await JsonManager.SaveToJsonFile(pluginDatabaseFile, installedPlugins); + + return Response.Success(); } public async Task> GetInstalledPlugins() @@ -121,19 +125,7 @@ public sealed class PluginManager : IPluginManager return await JsonManager.ConvertFromJson>(await File.ReadAllTextAsync(pluginDatabaseFile)); } - public async Task IsPluginInstalled(string pluginName) - { - string? pluginDatabaseFile = _Configuration.Get("PluginDatabase"); - if (pluginDatabaseFile is null) - { - throw new Exception("Plugin database file not found"); - } - - List installedPlugins = await JsonManager.ConvertFromJson>(await File.ReadAllTextAsync(pluginDatabaseFile)); - return installedPlugins.Any(plugin => plugin.PluginName == pluginName); - } - - public async Task GetDependencyLocation(string dependencyName) + public async Task> GetDependencyLocation(string dependencyName) { List installedPlugins = await GetInstalledPlugins(); @@ -142,14 +134,14 @@ public sealed class PluginManager : IPluginManager if (plugin.ListOfExecutableDependencies.TryGetValue(dependencyName, out var dependencyPath)) { string relativePath = GenerateDependencyRelativePath(plugin.PluginName, dependencyPath); - return relativePath; + return Response.Success(relativePath); } } - return null; + return Response.Failure($"Dependency {dependencyName} not found in the installed plugins."); } - public async Task GetDependencyLocation(string dependencyName, string pluginName) + public async Task> GetDependencyLocation(string dependencyName, string pluginName) { List installedPlugins = await GetInstalledPlugins(); @@ -159,11 +151,11 @@ public sealed class PluginManager : IPluginManager { string dependencyPath = plugin.ListOfExecutableDependencies[dependencyName]; string relativePath = GenerateDependencyRelativePath(pluginName, dependencyPath); - return relativePath; + return Response.Success(relativePath); } } - return null; + return Response.Failure($"Dependency {dependencyName} not found in the installed plugins."); } public string GenerateDependencyRelativePath(string pluginName, string dependencyPath) @@ -172,12 +164,22 @@ public sealed class PluginManager : IPluginManager return relative; } - public async Task InstallPlugin(OnlinePlugin plugin, IProgress progress) + public async Task> InstallPlugin(OnlinePlugin plugin, IProgress progress) { string? pluginsFolder = _Configuration.Get("PluginFolder"); if (pluginsFolder is null) { - throw new Exception("Plugin folder not found"); + return Response.Failure("Plugin folder path is not present in the config file"); + } + + var localPluginResponse = await GetLocalPluginByName(plugin.Name); + if (localPluginResponse is { IsSuccess: true, Data: not null }) + { + var response = await IsNewVersion(localPluginResponse.Data.PluginVersion, plugin.Version); + if (!response.IsSuccess) + { + return response; + } } List dependencies = await _PluginRepository.GetDependenciesForPlugin(plugin.Id); @@ -201,7 +203,9 @@ public sealed class PluginManager : IPluginManager await executor.ExecuteAllTasks(); LocalPlugin localPlugin = LocalPlugin.FromOnlineInfo(plugin, dependencies, downloadLocation); - await AppendPluginToDatabase(localPlugin); + var result = await AppendPluginToDatabase(localPlugin); + + return result; } public async Task SetEnabledStatus(string pluginName, bool status) @@ -219,12 +223,19 @@ public sealed class PluginManager : IPluginManager } - public async Task UninstallPluginByName(string pluginName) + public async Task> UninstallPluginByName(string pluginName) { - var localPlugin = await GetLocalPluginByName(pluginName); - if (localPlugin == null) + var localPluginResponse = await GetLocalPluginByName(pluginName); + if (!localPluginResponse.IsSuccess) { - return false; + return Response.Failure(localPluginResponse.Message); + } + + var localPlugin = localPluginResponse.Data; + + if (localPlugin is null) + { + return Response.Failure($"Plugin {pluginName} not found in the database"); } File.Delete(localPlugin.FilePath); @@ -237,25 +248,49 @@ public sealed class PluginManager : IPluginManager } } - await RemovePluginFromDatabase(pluginName); - - _Logger.Log($"Plugin {pluginName} uninstalled successfully", this, LogType.Info); - - return true; + var response = await RemovePluginFromDatabase(pluginName); + return response; } - public async Task GetLocalPluginByName(string pluginName) + public async Task> GetLocalPluginByName(string pluginName) { List installedPlugins = await GetInstalledPlugins(); var plugin = installedPlugins.Find(p => p.PluginName == pluginName); - if (plugin == null) + if (plugin is null) { - _Logger.Log($"Plugin {pluginName} not found in the database", this, LogType.Warning); - return null; + return Response.Failure($"Plugin {pluginName} not found in the database"); } - return plugin; + return Response.Success(plugin); + } + + private async Task> IsNewVersion(string currentVersion, string newVersion) + { + // currentVersion = "1.0.0" + // newVersion = "1.0.1" + + var currentVersionParts = currentVersion.Split('.').Select(int.Parse).ToArray(); + var newVersionParts = newVersion.Split('.').Select(int.Parse).ToArray(); + + if (currentVersionParts.Length != 3 || newVersionParts.Length != 3) + { + return Response.Failure("Invalid version format"); + } + + for (int i = 0; i < 3; i++) + { + if (newVersionParts[i] > currentVersionParts[i]) + { + return Response.Success(); + } + else if (newVersionParts[i] < currentVersionParts[i]) + { + return Response.Failure("Current version is newer"); + } + } + + return Response.Failure("Versions are the same"); } private async Task CreateEmptyPluginDatabase() diff --git a/DiscordBotCore.Utilities/Responses/IResponse.cs b/DiscordBotCore.Utilities/Responses/IResponse.cs new file mode 100644 index 0000000..dfe01c5 --- /dev/null +++ b/DiscordBotCore.Utilities/Responses/IResponse.cs @@ -0,0 +1,8 @@ +namespace DiscordBotCore.Utilities.Responses; + +public interface IResponse +{ + public bool IsSuccess { get; } + public string Message { get; } + public T? Data { get; } +} \ No newline at end of file diff --git a/DiscordBotCore.Utilities/Responses/Response.cs b/DiscordBotCore.Utilities/Responses/Response.cs new file mode 100644 index 0000000..144396f --- /dev/null +++ b/DiscordBotCore.Utilities/Responses/Response.cs @@ -0,0 +1,45 @@ +namespace DiscordBotCore.Utilities.Responses; + +public class Response : IResponse +{ + public bool IsSuccess => Data; + public string Message { get; } + public bool Data { get; } + + private Response(bool result) + { + Data = result; + Message = string.Empty; + } + + private Response(string message) + { + Data = false; + Message = message; + } + + public static Response Success() => new Response(true); + public static Response Failure(string message) => new Response(message); +} + +public class Response : IResponse where T : class +{ + public bool IsSuccess => Data is not null; + public string Message { get; } + public T? Data { get; } + + private Response(T data) + { + Data = data; + Message = string.Empty; + } + + private Response(string message) + { + Data = null; + Message = message; + } + + public static Response Success(T data) => new Response(data); + public static Response Failure(string message) => new Response(message); +} \ No newline at end of file diff --git a/WebUI/Components/Layout/MainLayout.razor b/WebUI/Components/Layout/MainLayout.razor index 7ff1bf0..6d3116e 100644 --- a/WebUI/Components/Layout/MainLayout.razor +++ b/WebUI/Components/Layout/MainLayout.razor @@ -1,5 +1,7 @@ -@inherits LayoutComponentBase +@using WebUI.Components.Notification +@inherits LayoutComponentBase +