public bool InstallPlugin(string filePath)
        {
            var file = new FileInfo(filePath);

            if (!file.Exists)
            {
                return(false);
            }

            var name    = file.Name.Replace(file.Extension, string.Empty);
            var tempDir = new DirectoryInfo(Path.Join(TemporaryDirectory.FullName, name));

            if (!tempDir.Exists)
            {
                tempDir.Create();
            }

            var pluginPath = Path.Join(AppInfo.Current.PluginDirectory, name);
            var pluginDir  = new DirectoryInfo(pluginPath);

            switch (file.Extension)
            {
            case ".zip":
            {
                ZipFile.ExtractToDirectory(file.FullName, tempDir.FullName, true);
                break;
            }

            case ".dll":
            {
                file.CopyTo(Path.Join(tempDir.FullName, file.Name));
                break;
            }

            default:
                throw new InvalidOperationException($"Unsupported archive type: {file.Extension}");
            }
            var context = Plugins.FirstOrDefault(ctx => ctx.Directory.FullName == pluginDir.FullName);
            var result  = pluginDir.Exists ? UpdatePlugin(context, tempDir) : InstallPlugin(pluginDir, tempDir);

            if (!TemporaryDirectory.GetFileSystemInfos().Any())
            {
                Directory.Delete(TemporaryDirectory.FullName, true);
            }

            if (result)
            {
                LoadPlugin(pluginDir);
            }
            return(result);
        }
        public async Task <bool> DownloadPlugin(PluginMetadata metadata)
        {
            string sourcePath   = Path.Join(TemporaryDirectory.FullName, metadata.Name);
            string targetPath   = Path.Join(PluginDirectory.FullName, metadata.Name);
            string metadataPath = Path.Join(targetPath, "metadata.json");

            var sourceDir = new DirectoryInfo(sourcePath);
            var targetDir = new DirectoryInfo(targetPath);

            await metadata.DownloadAsync(sourcePath);

            var context = Plugins.FirstOrDefault(ctx => ctx.Directory.FullName == targetDir.FullName);
            var result  = targetDir.Exists ? UpdatePlugin(context, sourceDir) : InstallPlugin(targetDir, sourceDir);

            using (var fs = File.Create(metadataPath))
                Serialization.Serialize(fs, metadata);

            if (!TemporaryDirectory.GetFileSystemInfos().Any())
            {
                Directory.Delete(TemporaryDirectory.FullName, true);
            }
            return(result);
        }