diff --git a/Flow.Launcher.Core/Flow.Launcher.Core.csproj b/Flow.Launcher.Core/Flow.Launcher.Core.csproj
index 9f146a457..189a6669e 100644
--- a/Flow.Launcher.Core/Flow.Launcher.Core.csproj
+++ b/Flow.Launcher.Core/Flow.Launcher.Core.csproj
@@ -55,7 +55,6 @@
-
diff --git a/Flow.Launcher.Core/Plugin/PluginInstaller.cs b/Flow.Launcher.Core/Plugin/PluginInstaller.cs
deleted file mode 100644
index 7b980a3ee..000000000
--- a/Flow.Launcher.Core/Plugin/PluginInstaller.cs
+++ /dev/null
@@ -1,169 +0,0 @@
-using System;
-using System.IO;
-using System.Windows;
-using ICSharpCode.SharpZipLib.Zip;
-using Newtonsoft.Json;
-using Flow.Launcher.Plugin;
-using Flow.Launcher.Infrastructure;
-using Flow.Launcher.Infrastructure.Logger;
-
-namespace Flow.Launcher.Core.Plugin
-{
- internal class PluginInstaller
- {
- internal static void Install(string path)
- {
- if (File.Exists(path))
- {
- string tempFolder = Path.Combine(Path.GetTempPath(), "flowlauncher", "plugins");
- if (Directory.Exists(tempFolder))
- {
- Directory.Delete(tempFolder, true);
- }
- UnZip(path, tempFolder, true);
-
- string jsonPath = Path.Combine(tempFolder, Constant.PluginMetadataFileName);
- if (!File.Exists(jsonPath))
- {
- MessageBox.Show("Install failed: plugin config is missing");
- return;
- }
-
- PluginMetadata plugin = GetMetadataFromJson(tempFolder);
- if (plugin == null || plugin.Name == null)
- {
- MessageBox.Show("Install failed: plugin config is invalid");
- return;
- }
-
- string pluginFolderPath = Infrastructure.UserSettings.DataLocation.PluginsDirectory;
-
- string newPluginName = plugin.Name
- .Replace("/", "_")
- .Replace("\\", "_")
- .Replace(":", "_")
- .Replace("<", "_")
- .Replace(">", "_")
- .Replace("?", "_")
- .Replace("*", "_")
- .Replace("|", "_")
- + "-" + Guid.NewGuid();
-
- string newPluginPath = Path.Combine(pluginFolderPath, newPluginName);
-
- string content = $"Do you want to install following plugin?{Environment.NewLine}{Environment.NewLine}" +
- $"Name: {plugin.Name}{Environment.NewLine}" +
- $"Version: {plugin.Version}{Environment.NewLine}" +
- $"Author: {plugin.Author}";
- PluginPair existingPlugin = PluginManager.GetPluginForId(plugin.ID);
-
- if (existingPlugin != null)
- {
- content = $"Do you want to update following plugin?{Environment.NewLine}{Environment.NewLine}" +
- $"Name: {plugin.Name}{Environment.NewLine}" +
- $"Old Version: {existingPlugin.Metadata.Version}" +
- $"{Environment.NewLine}New Version: {plugin.Version}" +
- $"{Environment.NewLine}Author: {plugin.Author}";
- }
-
- var result = MessageBox.Show(content, "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question);
- if (result == MessageBoxResult.Yes)
- {
- if (existingPlugin != null && Directory.Exists(existingPlugin.Metadata.PluginDirectory))
- {
- //when plugin is in use, we can't delete them. That's why we need to make plugin folder a random name
- File.Create(Path.Combine(existingPlugin.Metadata.PluginDirectory, "NeedDelete.txt")).Close();
- }
-
- Directory.Move(tempFolder, newPluginPath);
-
- //exsiting plugins may be has loaded by application,
- //if we try to delelte those kind of plugins, we will get a error that indicate the
- //file is been used now.
- //current solution is to restart Flow Launcher. Ugly.
- //if (MainWindow.Initialized)
- //{
- // Plugins.Initialize();
- //}
- if (MessageBox.Show($"You have installed plugin {plugin.Name} successfully.{Environment.NewLine}" +
- "Restart Flow Launcher to take effect?",
- "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
- {
- PluginManager.API.RestartApp();
- }
- }
- }
- }
-
- private static PluginMetadata GetMetadataFromJson(string pluginDirectory)
- {
- string configPath = Path.Combine(pluginDirectory, Constant.PluginMetadataFileName);
- PluginMetadata metadata;
-
- if (!File.Exists(configPath))
- {
- return null;
- }
-
- try
- {
- metadata = JsonConvert.DeserializeObject(File.ReadAllText(configPath));
- metadata.PluginDirectory = pluginDirectory;
- }
- catch (Exception e)
- {
- Log.Exception($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: invalid json format", e);
- return null;
- }
-
- if (!AllowedLanguage.IsAllowed(metadata.Language))
- {
- Log.Error($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: invalid language {metadata.Language}");
- return null;
- }
- if (!File.Exists(metadata.ExecuteFilePath))
- {
- Log.Error($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: file {metadata.ExecuteFilePath} doesn't exist");
- return null;
- }
-
- return metadata;
- }
-
- ///
- /// unzip plugin contents to the given directory.
- ///
- /// The path to the zip file.
- /// The output directory.
- /// overwirte
- private static void UnZip(string zipFile, string strDirectory, bool overWrite)
- {
- if (strDirectory == "")
- strDirectory = Directory.GetCurrentDirectory();
-
- using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(zipFile)))
- {
- ZipEntry theEntry;
-
- while ((theEntry = zipStream.GetNextEntry()) != null)
- {
- var pathToZip = theEntry.Name;
- var directoryName = String.IsNullOrEmpty(pathToZip) ? "" : Path.GetDirectoryName(pathToZip);
- var fileName = Path.GetFileName(pathToZip);
- var destinationDir = Path.Combine(strDirectory, directoryName);
- var destinationFile = Path.Combine(destinationDir, fileName);
-
- Directory.CreateDirectory(destinationDir);
-
- if (String.IsNullOrEmpty(fileName) || (File.Exists(destinationFile) && !overWrite))
- continue;
-
- using (FileStream streamWriter = File.Create(destinationFile))
- {
- zipStream.CopyTo(streamWriter);
- }
- }
- }
- }
- }
-}
diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs
index 5cde9de83..3b697a1ee 100644
--- a/Flow.Launcher.Core/Plugin/PluginManager.cs
+++ b/Flow.Launcher.Core/Plugin/PluginManager.cs
@@ -133,11 +133,6 @@ namespace Flow.Launcher.Core.Plugin
}
}
- public static void InstallPlugin(string path)
- {
- PluginInstaller.Install(path);
- }
-
public static List ValidPluginsForQuery(Query query)
{
if (NonGlobalPlugins.ContainsKey(query.ActionKeyword))
diff --git a/Flow.Launcher.Plugin/IPublicAPI.cs b/Flow.Launcher.Plugin/IPublicAPI.cs
index 681973905..ccc00d5e9 100644
--- a/Flow.Launcher.Plugin/IPublicAPI.cs
+++ b/Flow.Launcher.Plugin/IPublicAPI.cs
@@ -63,12 +63,6 @@ namespace Flow.Launcher.Plugin
///
void OpenSettingDialog();
- ///
- /// Install Flow Launcher plugin
- ///
- /// Plugin path (ends with .flowlauncher)
- void InstallPlugin(string path);
-
///
/// Get translation of current language
/// You need to implement IPluginI18n if you want to support multiple languages for your plugin
diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs
index 0cc5a0e5d..90d4fff63 100644
--- a/Flow.Launcher/PublicAPIInstance.cs
+++ b/Flow.Launcher/PublicAPIInstance.cs
@@ -115,11 +115,6 @@ namespace Flow.Launcher
_mainVM.ProgressBarVisibility = Visibility.Collapsed;
}
- public void InstallPlugin(string path)
- {
- Application.Current.Dispatcher.Invoke(() => PluginManager.InstallPlugin(path));
- }
-
public string GetTranslation(string key)
{
return InternationalizationManager.Instance.GetTranslation(key);
diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj b/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj
index 84cc5ffb1..cc1a931ce 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj
+++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj
@@ -39,4 +39,8 @@
PreserveNewest
+
+
+
+
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs
index 6a9da4eea..5484fdf85 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs
+++ b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs
@@ -3,6 +3,7 @@ using Flow.Launcher.Infrastructure.Http;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin.PluginsManager.Models;
+using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.IO;
@@ -36,6 +37,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
var filePath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}.zip");
PluginDownload(plugin.UrlDownload, filePath);
+ context.API.InstallPlugin(filePath);
}
private void PluginDownload(string downloadUrl, string toFilePath)
@@ -105,5 +107,160 @@ namespace Flow.Launcher.Plugin.PluginsManager
.Select(x => x)
.ToList();
}
+
+ private void Install(string path)
+ {
+ if (File.Exists(path))
+ {
+ string tempFolder = Path.Combine(Path.GetTempPath(), "flowlauncher", "plugins");
+ if (Directory.Exists(tempFolder))
+ {
+ Directory.Delete(tempFolder, true);
+ }
+ UnZip(path, tempFolder, true);
+
+ string jsonPath = Path.Combine(tempFolder, Constant.PluginMetadataFileName);
+ if (!File.Exists(jsonPath))
+ {
+ MessageBox.Show("Install failed: plugin config is missing");
+ return;
+ }
+
+ PluginMetadata plugin = GetMetadataFromJson(tempFolder);
+ if (plugin == null || plugin.Name == null)
+ {
+ MessageBox.Show("Install failed: plugin config is invalid");
+ return;
+ }
+
+ string pluginFolderPath = Infrastructure.UserSettings.DataLocation.PluginsDirectory;
+
+ string newPluginName = plugin.Name
+ .Replace("/", "_")
+ .Replace("\\", "_")
+ .Replace(":", "_")
+ .Replace("<", "_")
+ .Replace(">", "_")
+ .Replace("?", "_")
+ .Replace("*", "_")
+ .Replace("|", "_")
+ + "-" + Guid.NewGuid();
+
+ string newPluginPath = Path.Combine(pluginFolderPath, newPluginName);
+
+ string content = $"Do you want to install following plugin?{Environment.NewLine}{Environment.NewLine}" +
+ $"Name: {plugin.Name}{Environment.NewLine}" +
+ $"Version: {plugin.Version}{Environment.NewLine}" +
+ $"Author: {plugin.Author}";
+ PluginPair existingPlugin = PluginManager.GetPluginForId(plugin.ID);
+
+ if (existingPlugin != null)
+ {
+ content = $"Do you want to update following plugin?{Environment.NewLine}{Environment.NewLine}" +
+ $"Name: {plugin.Name}{Environment.NewLine}" +
+ $"Old Version: {existingPlugin.Metadata.Version}" +
+ $"{Environment.NewLine}New Version: {plugin.Version}" +
+ $"{Environment.NewLine}Author: {plugin.Author}";
+ }
+
+ var result = MessageBox.Show(content, "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question);
+ if (result == MessageBoxResult.Yes)
+ {
+ if (existingPlugin != null && Directory.Exists(existingPlugin.Metadata.PluginDirectory))
+ {
+ //when plugin is in use, we can't delete them. That's why we need to make plugin folder a random name
+ File.Create(Path.Combine(existingPlugin.Metadata.PluginDirectory, "NeedDelete.txt")).Close();
+ }
+
+ Directory.Move(tempFolder, newPluginPath);
+
+ //exsiting plugins may be has loaded by application,
+ //if we try to delelte those kind of plugins, we will get a error that indicate the
+ //file is been used now.
+ //current solution is to restart Flow Launcher. Ugly.
+ //if (MainWindow.Initialized)
+ //{
+ // Plugins.Initialize();
+ //}
+ if (MessageBox.Show($"You have installed plugin {plugin.Name} successfully.{Environment.NewLine}" +
+ "Restart Flow Launcher to take effect?",
+ "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
+ {
+ PluginManager.API.RestartApp();
+ }
+ }
+ }
+ }
+
+ private PluginMetadata GetMetadataFromJson(string pluginDirectory)
+ {
+ string configPath = Path.Combine(pluginDirectory, Constant.PluginMetadataFileName);
+ PluginMetadata metadata;
+
+ if (!File.Exists(configPath))
+ {
+ return null;
+ }
+
+ try
+ {
+ metadata = JsonConvert.DeserializeObject(File.ReadAllText(configPath));
+ metadata.PluginDirectory = pluginDirectory;
+ }
+ catch (Exception e)
+ {
+ Log.Exception($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: invalid json format", e);
+ return null;
+ }
+
+ if (!AllowedLanguage.IsAllowed(metadata.Language))
+ {
+ Log.Error($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: invalid language {metadata.Language}");
+ return null;
+ }
+ if (!File.Exists(metadata.ExecuteFilePath))
+ {
+ Log.Error($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: file {metadata.ExecuteFilePath} doesn't exist");
+ return null;
+ }
+
+ return metadata;
+ }
+
+ ///
+ /// unzip plugin contents to the given directory.
+ ///
+ /// The path to the zip file.
+ /// The output directory.
+ /// overwirte
+ private void UnZip(string zipFile, string strDirectory, bool overWrite)
+ {
+ if (strDirectory == "")
+ strDirectory = Directory.GetCurrentDirectory();
+
+ using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(zipFile)))
+ {
+ ZipEntry theEntry;
+
+ while ((theEntry = zipStream.GetNextEntry()) != null)
+ {
+ var pathToZip = theEntry.Name;
+ var directoryName = String.IsNullOrEmpty(pathToZip) ? "" : Path.GetDirectoryName(pathToZip);
+ var fileName = Path.GetFileName(pathToZip);
+ var destinationDir = Path.Combine(strDirectory, directoryName);
+ var destinationFile = Path.Combine(destinationDir, fileName);
+
+ Directory.CreateDirectory(destinationDir);
+
+ if (String.IsNullOrEmpty(fileName) || (File.Exists(destinationFile) && !overWrite))
+ continue;
+
+ using (FileStream streamWriter = File.Create(destinationFile))
+ {
+ zipStream.CopyTo(streamWriter);
+ }
+ }
+ }
+ }
}
}