Skip to content

Commit

Permalink
Merge pull request #260 from Flow-Launcher/dev
Browse files Browse the repository at this point in the history
Release 1.7.0 | Plugin 1.4.0
  • Loading branch information
jjw24 authored Feb 3, 2021
2 parents b3eb82a + 1ec5023 commit 1c39377
Show file tree
Hide file tree
Showing 135 changed files with 2,753 additions and 1,968 deletions.
File renamed without changes
6 changes: 3 additions & 3 deletions Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;
using Flow.Launcher.Infrastructure.Exception;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Plugin;
Expand Down Expand Up @@ -65,7 +65,7 @@ private List<Result> DeserializedResult(string output)
{
List<Result> results = new List<Result>();

JsonRPCQueryResponseModel queryResponseModel = JsonConvert.DeserializeObject<JsonRPCQueryResponseModel>(output);
JsonRPCQueryResponseModel queryResponseModel = JsonSerializer.Deserialize<JsonRPCQueryResponseModel>(output);
if (queryResponseModel.Result == null) return null;

foreach (JsonRPCResult result in queryResponseModel.Result)
Expand All @@ -84,7 +84,7 @@ private List<Result> DeserializedResult(string output)
else
{
string actionReponse = ExecuteCallback(result1.JsonRPCAction);
JsonRPCRequestModel jsonRpcRequestModel = JsonConvert.DeserializeObject<JsonRPCRequestModel>(actionReponse);
JsonRPCRequestModel jsonRpcRequestModel = JsonSerializer.Deserialize<JsonRPCRequestModel>(actionReponse);
if (jsonRpcRequestModel != null
&& !String.IsNullOrEmpty(jsonRpcRequestModel.Method)
&& jsonRpcRequestModel.Method.StartsWith("Flow.Launcher."))
Expand Down
8 changes: 4 additions & 4 deletions Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal PluginAssemblyLoader(string assemblyFilePath)
dependencyResolver = new AssemblyDependencyResolver(assemblyFilePath);
assemblyName = new AssemblyName(Path.GetFileNameWithoutExtension(assemblyFilePath));

referencedPluginPackageDependencyResolver =
referencedPluginPackageDependencyResolver =
new AssemblyDependencyResolver(Path.Combine(Constant.ProgramDirectory, "Flow.Launcher.Plugin.dll"));
}

Expand All @@ -38,15 +38,15 @@ protected override Assembly Load(AssemblyName assemblyName)
// that use Newtonsoft.Json
if (assemblyPath == null || ExistsInReferencedPluginPackage(assemblyName))
return null;

return LoadFromAssemblyPath(assemblyPath);
}

internal Type FromAssemblyGetTypeOfInterface(Assembly assembly, Type type)
internal Type FromAssemblyGetTypeOfInterface(Assembly assembly, params Type[] types)
{
var allTypes = assembly.ExportedTypes;

return allTypes.First(o => o.IsClass && !o.IsAbstract && o.GetInterfaces().Contains(type));
return allTypes.First(o => o.IsClass && !o.IsAbstract && o.GetInterfaces().Intersect(types).Any());
}

internal bool ExistsInReferencedPluginPackage(AssemblyName assemblyName)
Expand Down
4 changes: 2 additions & 2 deletions Flow.Launcher.Core/Plugin/PluginConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Newtonsoft.Json;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Plugin;
using System.Text.Json;

namespace Flow.Launcher.Core.Plugin
{
Expand Down Expand Up @@ -61,7 +61,7 @@ private static PluginMetadata GetPluginMetadata(string pluginDirectory)
PluginMetadata metadata;
try
{
metadata = JsonConvert.DeserializeObject<PluginMetadata>(File.ReadAllText(configPath));
metadata = JsonSerializer.Deserialize<PluginMetadata>(File.ReadAllText(configPath));
metadata.PluginDirectory = pluginDirectory;
// for plugins which doesn't has ActionKeywords key
metadata.ActionKeywords = metadata.ActionKeywords ?? new List<string> { metadata.ActionKeyword };
Expand Down
123 changes: 79 additions & 44 deletions Flow.Launcher.Core/Plugin/PluginManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Logger;
Expand Down Expand Up @@ -52,13 +53,14 @@ public static void Save()
}
}

public static void ReloadData()
public static async Task ReloadData()
{
foreach(var plugin in AllPlugins)
await Task.WhenAll(AllPlugins.Select(plugin => plugin.Plugin switch
{
var reloadablePlugin = plugin.Plugin as IReloadable;
reloadablePlugin?.ReloadData();
}
IReloadable p => Task.Run(p.ReloadData),
IAsyncReloadable p => p.ReloadDataAsync(),
_ => Task.CompletedTask,
}).ToArray());
}

static PluginManager()
Expand Down Expand Up @@ -86,50 +88,62 @@ public static void LoadPlugins(PluginsSettings settings)
/// Call initialize for all plugins
/// </summary>
/// <returns>return the list of failed to init plugins or null for none</returns>
public static void InitializePlugins(IPublicAPI api)
public static async Task InitializePlugins(IPublicAPI api)
{
API = api;
var failedPlugins = new ConcurrentQueue<PluginPair>();
Parallel.ForEach(AllPlugins, pair =>

var InitTasks = AllPlugins.Select(pair => Task.Run(async delegate
{
try
{
var milliseconds = Stopwatch.Debug($"|PluginManager.InitializePlugins|Init method time cost for <{pair.Metadata.Name}>", () =>
var milliseconds = pair.Plugin switch
{
pair.Plugin.Init(new PluginInitContext
{
CurrentPluginMetadata = pair.Metadata,
API = API
});
});
IAsyncPlugin plugin
=> await Stopwatch.DebugAsync($"|PluginManager.InitializePlugins|Init method time cost for <{pair.Metadata.Name}>",
() => plugin.InitAsync(new PluginInitContext(pair.Metadata, API))),
IPlugin plugin
=> Stopwatch.Debug($"|PluginManager.InitializePlugins|Init method time cost for <{pair.Metadata.Name}>",
() => plugin.Init(new PluginInitContext(pair.Metadata, API))),
_ => throw new ArgumentException(),
};
pair.Metadata.InitTime += milliseconds;
Log.Info($"|PluginManager.InitializePlugins|Total init cost for <{pair.Metadata.Name}> is <{pair.Metadata.InitTime}ms>");
Log.Info(
$"|PluginManager.InitializePlugins|Total init cost for <{pair.Metadata.Name}> is <{pair.Metadata.InitTime}ms>");
}
catch (Exception e)
{
Log.Exception(nameof(PluginManager), $"Fail to Init plugin: {pair.Metadata.Name}", e);
pair.Metadata.Disabled = true;
pair.Metadata.Disabled = true;
failedPlugins.Enqueue(pair);
}
});
}));

await Task.WhenAll(InitTasks);

_contextMenuPlugins = GetPluginsForInterface<IContextMenu>();
foreach (var plugin in AllPlugins)
{
if (IsGlobalPlugin(plugin.Metadata))
GlobalPlugins.Add(plugin);

// Plugins may have multiple ActionKeywords, eg. WebSearch
plugin.Metadata.ActionKeywords
.Where(x => x != Query.GlobalPluginWildcardSign)
.ToList()
.ForEach(x => NonGlobalPlugins[x] = plugin);
foreach (var actionKeyword in plugin.Metadata.ActionKeywords)
{
switch (actionKeyword)
{
case Query.GlobalPluginWildcardSign:
GlobalPlugins.Add(plugin);
break;
default:
NonGlobalPlugins[actionKeyword] = plugin;
break;
}
}
}

if (failedPlugins.Any())
{
var failed = string.Join(",", failedPlugins.Select(x => x.Metadata.Name));
API.ShowMsg($"Fail to Init Plugins", $"Plugins: {failed} - fail to load and would be disabled, please contact plugin creator for help", "", false);
API.ShowMsg($"Fail to Init Plugins",
$"Plugins: {failed} - fail to load and would be disabled, please contact plugin creator for help",
"", false);
}
}

Expand All @@ -146,24 +160,46 @@ public static List<PluginPair> ValidPluginsForQuery(Query query)
}
}

public static List<Result> QueryForPlugin(PluginPair pair, Query query)
public static async Task<List<Result>> QueryForPlugin(PluginPair pair, Query query, CancellationToken token)
{
var results = new List<Result>();
try
{
var metadata = pair.Metadata;
var milliseconds = Stopwatch.Debug($"|PluginManager.QueryForPlugin|Cost for {metadata.Name}", () =>

long milliseconds = -1L;

switch (pair.Plugin)
{
results = pair.Plugin.Query(query) ?? new List<Result>();
UpdatePluginMetadata(results, metadata, query);
});
case IAsyncPlugin plugin:
milliseconds = await Stopwatch.DebugAsync($"|PluginManager.QueryForPlugin|Cost for {metadata.Name}",
async () => results = await plugin.QueryAsync(query, token).ConfigureAwait(false));
break;
case IPlugin plugin:
await Task.Run(() => milliseconds = Stopwatch.Debug($"|PluginManager.QueryForPlugin|Cost for {metadata.Name}",
() => results = plugin.Query(query)), token).ConfigureAwait(false);
break;
default:
throw new ArgumentOutOfRangeException();
}
token.ThrowIfCancellationRequested();
UpdatePluginMetadata(results, metadata, query);

metadata.QueryCount += 1;
metadata.AvgQueryTime = metadata.QueryCount == 1 ? milliseconds : (metadata.AvgQueryTime + milliseconds) / 2;
metadata.AvgQueryTime =
metadata.QueryCount == 1 ? milliseconds : (metadata.AvgQueryTime + milliseconds) / 2;
token.ThrowIfCancellationRequested();
}
catch (OperationCanceledException)
{
// null will be fine since the results will only be added into queue if the token hasn't been cancelled
return results = null;
}
catch (Exception e)
{
Log.Exception($"|PluginManager.QueryForPlugin|Exception for plugin <{pair.Metadata.Name}> when query <{query}>", e);
}

return results;
}

Expand All @@ -182,11 +218,6 @@ public static void UpdatePluginMetadata(List<Result> results, PluginMetadata met
}
}

private static bool IsGlobalPlugin(PluginMetadata metadata)
{
return metadata.ActionKeywords.Contains(Query.GlobalPluginWildcardSign);
}

/// <summary>
/// get specified plugin, return null if not found
/// </summary>
Expand Down Expand Up @@ -222,16 +253,19 @@ public static List<Result> GetContextMenusForPlugin(Result result)
}
catch (Exception e)
{
Log.Exception($"|PluginManager.GetContextMenusForPlugin|Can't load context menus for plugin <{pluginPair.Metadata.Name}>", e);
Log.Exception(
$"|PluginManager.GetContextMenusForPlugin|Can't load context menus for plugin <{pluginPair.Metadata.Name}>",
e);
}
}

return results;
}

public static bool ActionKeywordRegistered(string actionKeyword)
{
return actionKeyword != Query.GlobalPluginWildcardSign
&& NonGlobalPlugins.ContainsKey(actionKeyword);
&& NonGlobalPlugins.ContainsKey(actionKeyword);
}

/// <summary>
Expand All @@ -249,6 +283,7 @@ public static void AddActionKeyword(string id, string newActionKeyword)
{
NonGlobalPlugins[newActionKeyword] = plugin;
}

plugin.Metadata.ActionKeywords.Add(newActionKeyword);
}

Expand All @@ -262,16 +297,16 @@ public static void RemoveActionKeyword(string id, string oldActionkeyword)
if (oldActionkeyword == Query.GlobalPluginWildcardSign
&& // Plugins may have multiple ActionKeywords that are global, eg. WebSearch
plugin.Metadata.ActionKeywords
.Where(x => x == Query.GlobalPluginWildcardSign)
.ToList()
.Count == 1)
.Where(x => x == Query.GlobalPluginWildcardSign)
.ToList()
.Count == 1)
{
GlobalPlugins.Remove(plugin);
}

if (oldActionkeyword != Query.GlobalPluginWildcardSign)
NonGlobalPlugins.Remove(oldActionkeyword);


plugin.Metadata.ActionKeywords.Remove(oldActionkeyword);
}
Expand Down
Loading

0 comments on commit 1c39377

Please sign in to comment.