Flow.Launcher/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs

335 lines
15 KiB
C#
Raw Normal View History

2020-12-07 10:21:14 +00:00
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Http;
2020-12-07 10:21:14 +00:00
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Infrastructure.UserSettings;
2020-12-06 20:40:42 +00:00
using Flow.Launcher.Plugin.PluginsManager.Models;
2020-12-06 08:58:27 +00:00
using System;
using System.Collections.Generic;
2020-12-07 10:21:14 +00:00
using System.IO;
2020-12-06 20:40:42 +00:00
using System.Linq;
2020-12-07 10:21:14 +00:00
using System.Windows;
2020-12-06 08:58:27 +00:00
namespace Flow.Launcher.Plugin.PluginsManager
{
internal class PluginsManager
{
private readonly PluginsManifest pluginsManifest;
2020-12-10 10:28:01 +00:00
private PluginInitContext Context { get; set; }
2020-12-06 20:42:23 +00:00
private Settings Settings { get; set; }
2020-12-17 10:07:47 +00:00
private bool shouldHideWindow = true;
private bool ShouldHideWindow
{
set { shouldHideWindow = value; }
get
{
var setValue = shouldHideWindow;
// Default value for hide main window is true. Revert after get call.
// This ensures when set by another method to false, it is only used once.
shouldHideWindow = true;
return setValue;
}
}
2020-12-10 11:09:27 +00:00
private readonly string icoPath = "Images\\pluginsmanager.png";
2020-12-06 20:42:23 +00:00
internal PluginsManager(PluginInitContext context, Settings settings)
2020-12-06 20:40:42 +00:00
{
pluginsManifest = new PluginsManifest();
2020-12-10 10:28:01 +00:00
Context = context;
Settings = settings;
2020-12-06 20:40:42 +00:00
}
2020-12-10 08:54:30 +00:00
internal void InstallOrUpdate(UserPlugin plugin)
2020-12-06 08:58:27 +00:00
{
if (PluginExists(plugin.ID))
2020-12-06 08:58:27 +00:00
{
if (Context.API.GetAllPlugins().Any(x => x.Metadata.ID == plugin.ID && x.Metadata.Version != plugin.Version))
{
if (MessageBox.Show(Context.API.GetTranslation("plugin_pluginsmanager_update_exists"),
Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
Context
.API
.ChangeQuery($"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {Settings.HotkeyUpdate} {plugin.Name}");
Application.Current.MainWindow.Show();
shouldHideWindow = false;
return;
}
Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_update_alreadyexists"));
2020-12-10 20:45:01 +00:00
return;
2020-12-06 08:58:27 +00:00
}
var message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_prompt"),
plugin.Name, plugin.Author,
Environment.NewLine, Environment.NewLine);
2020-12-10 11:58:18 +00:00
if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_install_title"), MessageBoxButton.YesNo) == MessageBoxResult.No)
2020-12-10 11:58:18 +00:00
return;
2020-12-17 07:54:30 +00:00
var filePath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}-{plugin.Version}.zip");
2020-12-07 10:21:14 +00:00
try
2020-12-06 08:58:27 +00:00
{
2020-12-10 20:45:01 +00:00
Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"),
Context.API.GetTranslation("plugin_pluginsmanager_please_wait"));
Http.Download(plugin.UrlDownload, filePath);
2020-12-07 10:21:14 +00:00
2020-12-10 10:28:01 +00:00
Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"),
Context.API.GetTranslation("plugin_pluginsmanager_download_success"));
2020-12-07 10:21:14 +00:00
}
catch (Exception e)
2020-12-07 10:21:14 +00:00
{
2020-12-10 10:28:01 +00:00
Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"),
Context.API.GetTranslation("plugin_pluginsmanager_download_success"));
2020-12-07 10:21:14 +00:00
Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "PluginDownload");
2020-12-06 08:58:27 +00:00
}
2020-12-17 09:37:01 +00:00
Application.Current.Dispatcher.Invoke(() => { Install(plugin, filePath); Context.API.RestartApp(); });
2020-12-06 08:58:27 +00:00
}
2020-12-17 09:37:01 +00:00
internal List<Result> RequestUpdate(string search)
2020-12-06 08:58:27 +00:00
{
2020-12-17 09:37:01 +00:00
var autocompletedResults = AutoCompleteReturnAllResults(search,
Settings.HotkeyUpdate,
"Update",
"Select a plugin to update");
2020-12-17 07:54:30 +00:00
2020-12-17 09:37:01 +00:00
if (autocompletedResults.Any())
return autocompletedResults;
var uninstallSearch = search.Replace(Settings.HotkeyUpdate, string.Empty).TrimStart();
var resultsForUpdate =
from existingPlugin in Context.API.GetAllPlugins()
join pluginFromManifest in pluginsManifest.UserPlugins
on existingPlugin.Metadata.ID equals pluginFromManifest.ID
where existingPlugin.Metadata.Version != pluginFromManifest.Version
select
new
{
pluginFromManifest.Name,
pluginFromManifest.Author,
CurrentVersion = existingPlugin.Metadata.Version,
NewVersion = pluginFromManifest.Version,
existingPlugin.Metadata.IcoPath,
PluginExistingMetadata = existingPlugin.Metadata,
PluginNewUserPlugin = pluginFromManifest
};
if (!resultsForUpdate.Any())
return new List<Result> {
new Result
{
Title = Context.API.GetTranslation("plugin_pluginsmanager_update_noresult_title"),
SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_update_noresult_subtitle"),
IcoPath = icoPath
}};
var results = resultsForUpdate
.Select(x =>
new Result
{
Title = $"{x.Name} by {x.Author}",
SubTitle = $"Update from version {x.CurrentVersion} to {x.NewVersion}",
IcoPath = x.IcoPath,
Action = e =>
{
string message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_update_prompt"),
x.Name, x.Author,
Environment.NewLine, Environment.NewLine);
if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
Uninstall(x.PluginExistingMetadata);
var downloadToFilePath = Path.Combine(DataLocation.PluginsDirectory, $"{x.Name}-{x.NewVersion}.zip");
Http.Download(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath);
Install(x.PluginNewUserPlugin, downloadToFilePath);
Context.API.RestartApp();
return true;
}
return false;
}
})
.ToList();
return Search(results, uninstallSearch);
2020-12-06 08:58:27 +00:00
}
2020-12-10 11:58:18 +00:00
internal bool PluginExists(string id)
2020-12-06 08:58:27 +00:00
{
2020-12-10 11:58:18 +00:00
return Context.API.GetAllPlugins().Any(x => x.Metadata.ID == id);
2020-12-06 08:58:27 +00:00
}
2020-12-10 10:28:01 +00:00
internal List<Result> Search(List<Result> results, string searchName)
{
if (string.IsNullOrEmpty(searchName))
return results;
return results
2020-12-14 08:14:50 +00:00
.Where(x =>
{
var matchResult = StringMatcher.FuzzySearch(searchName, x.Title);
if (matchResult.IsSearchPrecisionScoreMet())
x.Score = matchResult.Score;
return matchResult.IsSearchPrecisionScoreMet();
2020-12-14 08:14:50 +00:00
})
2020-12-10 10:28:01 +00:00
.ToList();
}
internal List<Result> RequestInstallOrUpdate(string searchName)
2020-12-06 20:40:42 +00:00
{
var results =
2020-12-14 02:46:37 +00:00
pluginsManifest
2020-12-07 10:21:14 +00:00
.UserPlugins
2020-12-14 02:46:37 +00:00
.Select(x =>
new Result
{
Title = $"{x.Name} by {x.Author}",
SubTitle = x.Description,
IcoPath = icoPath,
Action = e =>
2020-12-06 20:40:42 +00:00
{
2020-12-14 02:46:37 +00:00
Application.Current.MainWindow.Hide();
InstallOrUpdate(x);
2020-12-17 10:07:47 +00:00
return ShouldHideWindow;
2020-12-14 02:46:37 +00:00
}
})
.ToList();
2020-12-06 20:40:42 +00:00
2020-12-10 10:28:01 +00:00
return Search(results, searchName);
2020-12-06 20:40:42 +00:00
}
private void Install(UserPlugin plugin, string downloadedFilePath)
{
2020-12-10 11:58:18 +00:00
if (!File.Exists(downloadedFilePath))
return;
2020-12-10 11:58:18 +00:00
var tempFolderPath = Path.Combine(Path.GetTempPath(), "flowlauncher");
var tempFolderPluginPath = Path.Combine(tempFolderPath, "plugin");
2020-12-10 11:58:18 +00:00
if (Directory.Exists(tempFolderPath))
Directory.Delete(tempFolderPath, true);
2020-12-10 11:58:18 +00:00
Directory.CreateDirectory(tempFolderPath);
2020-12-10 11:58:18 +00:00
var zipFilePath = Path.Combine(tempFolderPath, Path.GetFileName(downloadedFilePath));
2020-12-10 11:58:18 +00:00
File.Move(downloadedFilePath, zipFilePath);
2020-12-10 11:58:18 +00:00
Utilities.UnZip(zipFilePath, tempFolderPluginPath, true);
2020-12-10 11:58:18 +00:00
var pluginFolderPath = Utilities.GetContainingFolderPathAfterUnzip(tempFolderPluginPath);
2020-12-10 11:58:18 +00:00
var metadataJsonFilePath = string.Empty;
if (File.Exists(Path.Combine(pluginFolderPath, Constant.PluginMetadataFileName)))
metadataJsonFilePath = Path.Combine(pluginFolderPath, Constant.PluginMetadataFileName);
2020-12-10 11:58:18 +00:00
if (string.IsNullOrEmpty(metadataJsonFilePath) || string.IsNullOrEmpty(pluginFolderPath))
{
2020-12-10 20:45:01 +00:00
MessageBox.Show(Context.API.GetTranslation("plugin_pluginsmanager_install_errormetadatafile"));
2020-12-10 11:58:18 +00:00
return;
}
string newPluginPath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}-{plugin.Version}");
2020-12-10 11:58:18 +00:00
Directory.Move(pluginFolderPath, newPluginPath);
}
2020-12-10 10:28:01 +00:00
internal List<Result> RequestUninstall(string search)
{
2020-12-17 07:54:30 +00:00
var autocompletedResults = AutoCompleteReturnAllResults(search,
2020-12-17 09:37:01 +00:00
Settings.HotkeyUninstall,
2020-12-17 07:54:30 +00:00
"Uninstall",
"Select a plugin to uninstall");
2020-12-17 07:54:30 +00:00
if (autocompletedResults.Any())
return autocompletedResults;
2020-12-17 09:37:01 +00:00
var uninstallSearch = search.Replace(Settings.HotkeyUninstall, string.Empty).TrimStart();
2020-12-14 02:46:37 +00:00
var results= Context.API
.GetAllPlugins()
.Select(x =>
new Result
{
Title = $"{x.Metadata.Name} by {x.Metadata.Author}",
SubTitle = x.Metadata.Description,
IcoPath = x.Metadata.IcoPath,
Action = e =>
{
2020-12-17 09:37:01 +00:00
string message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_uninstall_prompt"),
x.Metadata.Name, x.Metadata.Author,
Environment.NewLine, Environment.NewLine);
if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_uninstall_title"),
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
Application.Current.MainWindow.Hide();
Uninstall(x.Metadata);
Context.API.RestartApp();
2020-12-14 02:46:37 +00:00
2020-12-17 09:37:01 +00:00
return true;
}
return false;
2020-12-14 02:46:37 +00:00
}
})
.ToList();
2020-12-10 10:28:01 +00:00
return Search(results, uninstallSearch);
2020-12-10 10:28:01 +00:00
}
private void Uninstall(PluginMetadata plugin)
{
2020-12-17 09:37:01 +00:00
// Marked for deletion. Will be deleted on next start up
using var _ = File.CreateText(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt"));
2020-12-10 10:28:01 +00:00
}
2020-12-17 07:54:30 +00:00
private List<Result> AutoCompleteReturnAllResults(string search, string hotkey, string title, string subtitle)
{
if (!string.IsNullOrEmpty(search)
&& hotkey.StartsWith(search)
&& (hotkey != search || !search.StartsWith(hotkey)))
{
return
new List<Result>
{
new Result
{
Title = title,
IcoPath = icoPath,
SubTitle = subtitle,
Action = e =>
{
Context
.API
.ChangeQuery($"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {hotkey} ");
return false;
}
}
};
}
return new List<Result>();
}
2020-12-06 08:58:27 +00:00
}
}