mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-08 20:27:36 +02:00
Refactoring Plugin Loader [WIP].
This commit is contained in:
@@ -19,7 +19,7 @@ namespace Wox.Plugin
|
|||||||
|
|
||||||
public static string ExecutableFile
|
public static string ExecutableFile
|
||||||
{
|
{
|
||||||
get { return "ExecutableFile"; }
|
get { return "executablefile"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsAllowed(string language)
|
public static bool IsAllowed(string language)
|
||||||
|
|||||||
@@ -1,118 +1,32 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Text;
|
||||||
using System.Windows.Forms;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Wox.Helper;
|
|
||||||
using Wox.Infrastructure.Storage.UserSettings;
|
|
||||||
using Wox.Plugin;
|
using Wox.Plugin;
|
||||||
using Wox.Plugin.SystemPlugins;
|
using Wox.RPC;
|
||||||
|
|
||||||
namespace Wox.PluginLoader {
|
namespace Wox.PluginLoader
|
||||||
public abstract class BasePluginLoader {
|
{
|
||||||
private static string PluginPath = Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), "Plugins");
|
public class BasePluginLoader<T> where T :BasePluginWrapper,new()
|
||||||
private static string PluginConfigName = "plugin.json";
|
{
|
||||||
protected static List<PluginMetadata> pluginMetadatas = new List<PluginMetadata>();
|
public List<PluginPair> LoadPlugin(List<PluginMetadata> pluginMetadatas)
|
||||||
public abstract List<PluginPair> LoadPlugin();
|
{
|
||||||
|
List<PluginPair> plugins = new List<PluginPair>();
|
||||||
|
|
||||||
public static void ParsePluginsConfig() {
|
T pluginWrapper = new T();
|
||||||
pluginMetadatas.Clear();
|
List<string> allowedLanguages = pluginWrapper.GetAllowedLanguages();
|
||||||
ParseSystemPlugins();
|
List<PluginMetadata> metadatas = pluginMetadatas.Where(o => allowedLanguages.Contains(o.Language.ToUpper())).ToList();
|
||||||
ParseThirdPartyPlugins();
|
foreach (PluginMetadata metadata in metadatas)
|
||||||
|
{
|
||||||
|
PluginPair pair = new PluginPair()
|
||||||
|
{
|
||||||
|
Plugin = pluginWrapper,
|
||||||
|
Metadata = metadata
|
||||||
|
};
|
||||||
|
plugins.Add(pair);
|
||||||
|
}
|
||||||
|
|
||||||
if (Plugins.DebuggerMode != null) {
|
return plugins;
|
||||||
PluginMetadata metadata = GetMetadataFromJson(Plugins.DebuggerMode);
|
}
|
||||||
if (metadata != null) pluginMetadatas.Add(metadata);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ParseSystemPlugins() {
|
|
||||||
pluginMetadatas.Add(new PluginMetadata() {
|
|
||||||
Name = "System Plugins",
|
|
||||||
Author = "System",
|
|
||||||
Description = "system plugins collection",
|
|
||||||
Website = "http://www.getwox.com",
|
|
||||||
Language = AllowedLanguage.CSharp,
|
|
||||||
Version = "1.0",
|
|
||||||
PluginType = PluginType.System,
|
|
||||||
ActionKeyword = "*",
|
|
||||||
ExecuteFileName = "Wox.Plugin.SystemPlugins.dll",
|
|
||||||
PluginDirecotry = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ParseThirdPartyPlugins() {
|
|
||||||
if (!Directory.Exists(PluginPath))
|
|
||||||
Directory.CreateDirectory(PluginPath);
|
|
||||||
|
|
||||||
string[] directories = Directory.GetDirectories(PluginPath);
|
|
||||||
foreach (string directory in directories) {
|
|
||||||
if (File.Exists((Path.Combine(directory, "NeedDelete.txt")))) {
|
|
||||||
Directory.Delete(directory, true);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
PluginMetadata metadata = GetMetadataFromJson(directory);
|
|
||||||
if (metadata != null) pluginMetadatas.Add(metadata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PluginMetadata GetMetadataFromJson(string pluginDirectory) {
|
|
||||||
string configPath = Path.Combine(pluginDirectory, PluginConfigName);
|
|
||||||
PluginMetadata metadata;
|
|
||||||
|
|
||||||
if (!File.Exists(configPath)) {
|
|
||||||
Log.Warn(string.Format("parse plugin {0} failed: didn't find config file.", configPath));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
metadata = JsonConvert.DeserializeObject<PluginMetadata>(File.ReadAllText(configPath));
|
|
||||||
metadata.PluginType = PluginType.ThirdParty;
|
|
||||||
metadata.PluginDirecotry = pluginDirectory;
|
|
||||||
}
|
|
||||||
catch (Exception) {
|
|
||||||
string error = string.Format("Parse plugin config {0} failed: json format is not valid", configPath);
|
|
||||||
Log.Warn(error);
|
|
||||||
#if (DEBUG)
|
|
||||||
{
|
|
||||||
throw new WoxException(error);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!AllowedLanguage.IsAllowed(metadata.Language)) {
|
|
||||||
string error = string.Format("Parse plugin config {0} failed: invalid language {1}", configPath, metadata.Language);
|
|
||||||
Log.Warn(error);
|
|
||||||
#if (DEBUG)
|
|
||||||
{
|
|
||||||
throw new WoxException(error);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!File.Exists(metadata.ExecuteFilePath)) {
|
|
||||||
string error = string.Format("Parse plugin config {0} failed: ExecuteFile {1} didn't exist", configPath, metadata.ExecuteFilePath);
|
|
||||||
Log.Warn(error);
|
|
||||||
#if (DEBUG)
|
|
||||||
{
|
|
||||||
throw new WoxException(error);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var customizedPluginConfig =
|
|
||||||
UserSettingStorage.Instance.CustomizedPluginConfigs.FirstOrDefault(o => o.ID == metadata.ID);
|
|
||||||
if (customizedPluginConfig != null && !string.IsNullOrEmpty(customizedPluginConfig.Actionword))
|
|
||||||
{
|
|
||||||
metadata.ActionKeyword = customizedPluginConfig.Actionword;
|
|
||||||
}
|
|
||||||
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
92
Wox/PluginLoader/BasePluginWrapper.cs
Normal file
92
Wox/PluginLoader/BasePluginWrapper.cs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Wox.Plugin;
|
||||||
|
using Wox.RPC;
|
||||||
|
|
||||||
|
namespace Wox.PluginLoader
|
||||||
|
{
|
||||||
|
public abstract class BasePluginWrapper : IPlugin
|
||||||
|
{
|
||||||
|
protected PluginInitContext context;
|
||||||
|
|
||||||
|
public abstract List<string> GetAllowedLanguages();
|
||||||
|
protected abstract string GetFileName();
|
||||||
|
|
||||||
|
protected abstract string GetQueryArguments(Query query);
|
||||||
|
|
||||||
|
protected abstract string GetActionJsonRPCArguments(ActionJsonRPCResult result);
|
||||||
|
|
||||||
|
public List<Result> Query(Query query)
|
||||||
|
{
|
||||||
|
string fileName = GetFileName();
|
||||||
|
string arguments = GetQueryArguments(query);
|
||||||
|
string output = Execute(fileName, arguments);
|
||||||
|
if (!string.IsNullOrEmpty(output))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JsonPRCModel rpc = JsonConvert.DeserializeObject<JsonPRCModel>(output);
|
||||||
|
List<ActionJsonRPCResult> rpcresults =
|
||||||
|
JsonConvert.DeserializeObject<List<ActionJsonRPCResult>>(rpc.result);
|
||||||
|
List<Result> results = new List<Result>();
|
||||||
|
foreach (ActionJsonRPCResult result in rpcresults)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(result.ActionJSONRPC))
|
||||||
|
{
|
||||||
|
ActionJsonRPCResult resultCopy = result;
|
||||||
|
result.Action = (c) =>
|
||||||
|
{
|
||||||
|
Execute(fileName, GetActionJsonRPCArguments(resultCopy));
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Execute(string fileName, string arguments)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ProcessStartInfo start = new ProcessStartInfo();
|
||||||
|
start.FileName = fileName;
|
||||||
|
start.Arguments = arguments;
|
||||||
|
start.UseShellExecute = false;
|
||||||
|
start.CreateNoWindow = true;
|
||||||
|
start.RedirectStandardOutput = true;
|
||||||
|
using (Process process = Process.Start(start))
|
||||||
|
{
|
||||||
|
if (process != null)
|
||||||
|
{
|
||||||
|
using (StreamReader reader = process.StandardOutput)
|
||||||
|
{
|
||||||
|
return reader.ReadToEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init(PluginInitContext ctx)
|
||||||
|
{
|
||||||
|
this.context = ctx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,9 +8,10 @@ using Wox.Plugin.SystemPlugins;
|
|||||||
|
|
||||||
namespace Wox.PluginLoader {
|
namespace Wox.PluginLoader {
|
||||||
|
|
||||||
public class CSharpPluginLoader : BasePluginLoader {
|
public class CSharpPluginConfigLoader
|
||||||
|
{
|
||||||
public override List<PluginPair> LoadPlugin() {
|
public List<PluginPair> LoadPlugin(List<PluginMetadata> pluginMetadatas)
|
||||||
|
{
|
||||||
var plugins = new List<PluginPair>();
|
var plugins = new List<PluginPair>();
|
||||||
|
|
||||||
List<PluginMetadata> metadatas = pluginMetadatas.Where(o => o.Language.ToUpper() == AllowedLanguage.CSharp.ToUpper()).ToList();
|
List<PluginMetadata> metadatas = pluginMetadatas.Where(o => o.Language.ToUpper() == AllowedLanguage.CSharp.ToUpper()).ToList();
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Wox.Plugin;
|
|
||||||
|
|
||||||
namespace Wox.PluginLoader
|
|
||||||
{
|
|
||||||
public class ExecutablePluginLoader : BasePluginLoader
|
|
||||||
{
|
|
||||||
public override List<PluginPair> LoadPlugin()
|
|
||||||
{
|
|
||||||
List<PluginPair> plugins = new List<PluginPair>();
|
|
||||||
List<PluginMetadata> metadatas = pluginMetadatas.Where(o => o.Language.ToUpper() == AllowedLanguage.ExecutableFile.ToUpper()).ToList();
|
|
||||||
foreach (PluginMetadata metadata in metadatas)
|
|
||||||
{
|
|
||||||
ExecutablePluginWrapper executer = new ExecutablePluginWrapper();
|
|
||||||
PluginPair pair = new PluginPair()
|
|
||||||
{
|
|
||||||
Plugin = executer,
|
|
||||||
Metadata = metadata
|
|
||||||
};
|
|
||||||
plugins.Add(pair);
|
|
||||||
}
|
|
||||||
|
|
||||||
return plugins;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Wox.Plugin;
|
|
||||||
using Wox.RPC;
|
|
||||||
|
|
||||||
namespace Wox.PluginLoader
|
|
||||||
{
|
|
||||||
public class ExecutablePluginWrapper : IPlugin
|
|
||||||
{
|
|
||||||
private PluginInitContext context;
|
|
||||||
private static string executeDirectory = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath);
|
|
||||||
|
|
||||||
public List<Result> Query(Query query)
|
|
||||||
{
|
|
||||||
List<Result> results = new List<Result>();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ProcessStartInfo start = new ProcessStartInfo();
|
|
||||||
start.FileName = Path.Combine(executeDirectory, "PYTHONTHOME\\Scripts\\python.exe");
|
|
||||||
start.Arguments = string.Format("{0} \"{1}\"",
|
|
||||||
context.CurrentPluginMetadata.ExecuteFilePath,
|
|
||||||
RPC.JsonRPC.GetRPC("query", query.GetAllRemainingParameter()));
|
|
||||||
start.UseShellExecute = false;
|
|
||||||
start.CreateNoWindow = true;
|
|
||||||
start.RedirectStandardOutput = true;
|
|
||||||
using (Process process = Process.Start(start))
|
|
||||||
{
|
|
||||||
if (process != null)
|
|
||||||
{
|
|
||||||
using (StreamReader reader = process.StandardOutput)
|
|
||||||
{
|
|
||||||
string output = reader.ReadToEnd();
|
|
||||||
if (!string.IsNullOrEmpty(output))
|
|
||||||
{
|
|
||||||
JsonPRCModel rpc = JsonConvert.DeserializeObject<JsonPRCModel>(output);
|
|
||||||
var rpcresults = JsonConvert.DeserializeObject<List<ActionJsonRPCResult>>(rpc.result);
|
|
||||||
List<Result> r = new List<Result>();
|
|
||||||
foreach (ActionJsonRPCResult result in rpcresults)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(result.ActionJSONRPC))
|
|
||||||
{
|
|
||||||
result.Action = (context) =>
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
r.Add(result);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Init(PluginInitContext context)
|
|
||||||
{
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
119
Wox/PluginLoader/PluginConfigLoader.cs
Normal file
119
Wox/PluginLoader/PluginConfigLoader.cs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Wox.Helper;
|
||||||
|
using Wox.Infrastructure.Storage.UserSettings;
|
||||||
|
using Wox.Plugin;
|
||||||
|
using Wox.Plugin.SystemPlugins;
|
||||||
|
|
||||||
|
namespace Wox.PluginLoader {
|
||||||
|
public abstract class PluginConfigLoader {
|
||||||
|
private static string PluginPath = Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), "Plugins");
|
||||||
|
private static string PluginConfigName = "plugin.json";
|
||||||
|
private static List<PluginMetadata> pluginMetadatas = new List<PluginMetadata>();
|
||||||
|
|
||||||
|
public static List<PluginMetadata> ParsePluginsConfig()
|
||||||
|
{
|
||||||
|
pluginMetadatas.Clear();
|
||||||
|
ParseSystemPlugins();
|
||||||
|
ParseThirdPartyPlugins();
|
||||||
|
|
||||||
|
if (Plugins.DebuggerMode != null) {
|
||||||
|
PluginMetadata metadata = GetMetadataFromJson(Plugins.DebuggerMode);
|
||||||
|
if (metadata != null) pluginMetadatas.Add(metadata);
|
||||||
|
}
|
||||||
|
return pluginMetadatas;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ParseSystemPlugins() {
|
||||||
|
pluginMetadatas.Add(new PluginMetadata() {
|
||||||
|
Name = "System Plugins",
|
||||||
|
Author = "System",
|
||||||
|
Description = "system plugins collection",
|
||||||
|
Website = "http://www.getwox.com",
|
||||||
|
Language = AllowedLanguage.CSharp,
|
||||||
|
Version = "1.0",
|
||||||
|
PluginType = PluginType.System,
|
||||||
|
ActionKeyword = "*",
|
||||||
|
ExecuteFileName = "Wox.Plugin.SystemPlugins.dll",
|
||||||
|
PluginDirecotry = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ParseThirdPartyPlugins() {
|
||||||
|
if (!Directory.Exists(PluginPath))
|
||||||
|
Directory.CreateDirectory(PluginPath);
|
||||||
|
|
||||||
|
string[] directories = Directory.GetDirectories(PluginPath);
|
||||||
|
foreach (string directory in directories) {
|
||||||
|
if (File.Exists((Path.Combine(directory, "NeedDelete.txt")))) {
|
||||||
|
Directory.Delete(directory, true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PluginMetadata metadata = GetMetadataFromJson(directory);
|
||||||
|
if (metadata != null) pluginMetadatas.Add(metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PluginMetadata GetMetadataFromJson(string pluginDirectory) {
|
||||||
|
string configPath = Path.Combine(pluginDirectory, PluginConfigName);
|
||||||
|
PluginMetadata metadata;
|
||||||
|
|
||||||
|
if (!File.Exists(configPath)) {
|
||||||
|
Log.Warn(string.Format("parse plugin {0} failed: didn't find config file.", configPath));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
metadata = JsonConvert.DeserializeObject<PluginMetadata>(File.ReadAllText(configPath));
|
||||||
|
metadata.PluginType = PluginType.ThirdParty;
|
||||||
|
metadata.PluginDirecotry = pluginDirectory;
|
||||||
|
}
|
||||||
|
catch (Exception) {
|
||||||
|
string error = string.Format("Parse plugin config {0} failed: json format is not valid", configPath);
|
||||||
|
Log.Warn(error);
|
||||||
|
#if (DEBUG)
|
||||||
|
{
|
||||||
|
throw new WoxException(error);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!AllowedLanguage.IsAllowed(metadata.Language)) {
|
||||||
|
string error = string.Format("Parse plugin config {0} failed: invalid language {1}", configPath, metadata.Language);
|
||||||
|
Log.Warn(error);
|
||||||
|
#if (DEBUG)
|
||||||
|
{
|
||||||
|
throw new WoxException(error);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!File.Exists(metadata.ExecuteFilePath)) {
|
||||||
|
string error = string.Format("Parse plugin config {0} failed: ExecuteFile {1} didn't exist", configPath, metadata.ExecuteFilePath);
|
||||||
|
Log.Warn(error);
|
||||||
|
#if (DEBUG)
|
||||||
|
{
|
||||||
|
throw new WoxException(error);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var customizedPluginConfig =
|
||||||
|
UserSettingStorage.Instance.CustomizedPluginConfigs.FirstOrDefault(o => o.ID == metadata.ID);
|
||||||
|
if (customizedPluginConfig != null && !string.IsNullOrEmpty(customizedPluginConfig.Actionword))
|
||||||
|
{
|
||||||
|
metadata.ActionKeyword = customizedPluginConfig.Actionword;
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,11 +14,10 @@ namespace Wox.PluginLoader
|
|||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
plugins.Clear();
|
plugins.Clear();
|
||||||
BasePluginLoader.ParsePluginsConfig();
|
List<PluginMetadata> pluginMetadatas = PluginConfigLoader.ParsePluginsConfig();
|
||||||
|
|
||||||
plugins.AddRange(new PythonPluginLoader().LoadPlugin());
|
plugins.AddRange(new CSharpPluginConfigLoader().LoadPlugin(pluginMetadatas));
|
||||||
plugins.AddRange(new CSharpPluginLoader().LoadPlugin());
|
plugins.AddRange(new BasePluginLoader<PythonPluginWrapper>().LoadPlugin(pluginMetadatas));
|
||||||
plugins.AddRange(new ExecutablePluginLoader().LoadPlugin());
|
|
||||||
|
|
||||||
Forker forker = new Forker();
|
Forker forker = new Forker();
|
||||||
foreach (IPlugin plugin in plugins.Select(pluginPair => pluginPair.Plugin))
|
foreach (IPlugin plugin in plugins.Select(pluginPair => pluginPair.Plugin))
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using Python.Runtime;
|
|
||||||
using Wox.Plugin;
|
|
||||||
using Wox.Helper;
|
|
||||||
|
|
||||||
namespace Wox.PluginLoader
|
|
||||||
{
|
|
||||||
public class PythonPluginLoader : BasePluginLoader
|
|
||||||
{
|
|
||||||
public override List<PluginPair> LoadPlugin()
|
|
||||||
{
|
|
||||||
if (!CheckPythonEnvironmentInstalled()) return new List<PluginPair>();
|
|
||||||
|
|
||||||
List<PluginPair> plugins = new List<PluginPair>();
|
|
||||||
List<PluginMetadata> metadatas = pluginMetadatas.Where(o => o.Language.ToUpper() == AllowedLanguage.Python.ToUpper()).ToList();
|
|
||||||
foreach (PluginMetadata metadata in metadatas)
|
|
||||||
{
|
|
||||||
PythonPluginWrapper python = new PythonPluginWrapper(metadata);
|
|
||||||
PluginPair pair = new PluginPair()
|
|
||||||
{
|
|
||||||
Plugin = python,
|
|
||||||
Metadata = metadata
|
|
||||||
};
|
|
||||||
plugins.Add(pair);
|
|
||||||
}
|
|
||||||
|
|
||||||
return plugins;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CheckPythonEnvironmentInstalled() {
|
|
||||||
try
|
|
||||||
{
|
|
||||||
SetPythonHome();
|
|
||||||
PythonEngine.Initialize();
|
|
||||||
PythonEngine.Shutdown();
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Log.Warn("Could't find python environment, all python plugins disabled.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetPythonHome()
|
|
||||||
{
|
|
||||||
//Environment.SetEnvironmentVariable("PYTHONHOME",Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),"PythonHome"));
|
|
||||||
//PythonEngine.PythonHome =
|
|
||||||
//PythonEngine.ProgramName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,142 +1,43 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using System.Threading;
|
||||||
using Python.Runtime;
|
using Python.Runtime;
|
||||||
using Wox.Helper;
|
|
||||||
using Wox.Plugin;
|
using Wox.Plugin;
|
||||||
|
using Wox.Helper;
|
||||||
|
using Wox.RPC;
|
||||||
|
|
||||||
namespace Wox.PluginLoader
|
namespace Wox.PluginLoader
|
||||||
{
|
{
|
||||||
public class PythonPluginWrapper : IPlugin
|
public class PythonPluginWrapper : BasePluginWrapper
|
||||||
{
|
{
|
||||||
private PluginMetadata metadata;
|
private static string woxDirectory = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath);
|
||||||
private string moduleName;
|
|
||||||
|
|
||||||
public PythonPluginWrapper(PluginMetadata metadata)
|
public override List<string> GetAllowedLanguages()
|
||||||
{
|
{
|
||||||
this.metadata = metadata;
|
return new List<string>()
|
||||||
moduleName = metadata.ExecuteFileName.Replace(".py", "");
|
{
|
||||||
|
AllowedLanguage.Python
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Result> Query(Query query)
|
protected override string GetFileName()
|
||||||
{
|
{
|
||||||
try
|
return Path.Combine(woxDirectory, "PYTHONTHOME\\Scripts\\python.exe");
|
||||||
{
|
|
||||||
string jsonResult = InvokeFunc("query", query.RawQuery);
|
|
||||||
if (string.IsNullOrEmpty(jsonResult))
|
|
||||||
{
|
|
||||||
return new List<Result>();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<PythonResult> o = JsonConvert.DeserializeObject<List<PythonResult>>(jsonResult);
|
|
||||||
List<Result> r = new List<Result>();
|
|
||||||
foreach (PythonResult pythonResult in o)
|
|
||||||
{
|
|
||||||
PythonResult ps = pythonResult;
|
|
||||||
if (!string.IsNullOrEmpty(ps.ActionName))
|
|
||||||
{
|
|
||||||
ps.Action = (context) =>
|
|
||||||
{
|
|
||||||
InvokeFunc(ps.ActionName, GetPythonActionContext(context), new PyString(ps.ActionPara));
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
r.Add(ps);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
#if (DEBUG)
|
|
||||||
{
|
|
||||||
throw new WoxPythonException(e.Message);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
Log.Error(string.Format("Python Plugin {0} query failed: {1}", metadata.Name, e.Message));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new List<Result>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PyObject GetPythonActionContext(ActionContext context)
|
protected override string GetQueryArguments(Query query)
|
||||||
{
|
{
|
||||||
PyDict dict = new PyDict();
|
return string.Format("{0} \"{1}\"",
|
||||||
PyDict specialKeyStateDict = new PyDict();
|
context.CurrentPluginMetadata.ExecuteFilePath,
|
||||||
specialKeyStateDict["CtrlPressed"] = new PyString(context.SpecialKeyState.CtrlPressed.ToString());
|
JsonRPC.GetRPC("query", query.GetAllRemainingParameter()));
|
||||||
specialKeyStateDict["AltPressed"] = new PyString(context.SpecialKeyState.AltPressed.ToString());
|
|
||||||
specialKeyStateDict["WinPressed"] = new PyString(context.SpecialKeyState.WinPressed.ToString());
|
|
||||||
specialKeyStateDict["ShiftPressed"] = new PyString(context.SpecialKeyState.ShiftPressed.ToString());
|
|
||||||
|
|
||||||
dict["SpecialKeyState"] = specialKeyStateDict;
|
|
||||||
return dict;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string InvokeFunc(string func, params PyObject[] paras)
|
protected override string GetActionJsonRPCArguments(ActionJsonRPCResult result)
|
||||||
{
|
{
|
||||||
string json = null;
|
return string.Format("{0} \"{1}\"", context.CurrentPluginMetadata.ExecuteFilePath,
|
||||||
|
result.ActionJSONRPC);
|
||||||
//if pythobn plugin folder name is chinese, here will deadlock.
|
|
||||||
IntPtr gs = PythonEngine.AcquireLock();
|
|
||||||
|
|
||||||
PyObject module = PythonEngine.ImportModule(moduleName);
|
|
||||||
if (module == null)
|
|
||||||
{
|
|
||||||
string error = string.Format("Python Invoke failed: {0} doesn't has module {1}",
|
|
||||||
metadata.ExecuteFilePath, moduleName);
|
|
||||||
Log.Error(error);
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (module.HasAttr(func))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PyObject res = paras.Length > 0 ? module.InvokeMethod(func, paras) : module.InvokeMethod(func);
|
|
||||||
json = Runtime.GetManagedString(res.Handle);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
string error = string.Format("Python Invoke failed: {0}", e.Message);
|
|
||||||
Log.Error(error);
|
|
||||||
#if (DEBUG)
|
|
||||||
{
|
|
||||||
throw new WoxPythonException(error);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string error = string.Format("Python Invoke failed: {0} doesn't has function {1}",
|
|
||||||
metadata.ExecuteFilePath, func);
|
|
||||||
Log.Error(error);
|
|
||||||
#if (DEBUG)
|
|
||||||
{
|
|
||||||
throw new WoxPythonException(error);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
PythonEngine.ReleaseLock(gs);
|
|
||||||
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string InvokeFunc(string func, params string[] para)
|
|
||||||
{
|
|
||||||
PyObject[] paras = { };
|
|
||||||
if (para != null && para.Length > 0)
|
|
||||||
{
|
|
||||||
paras = para.Select(o => new PyString(o)).ToArray();
|
|
||||||
}
|
|
||||||
return InvokeFunc(func, paras);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Init(PluginInitContext context)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,13 +142,12 @@
|
|||||||
<Compile Include="Msg.xaml.cs">
|
<Compile Include="Msg.xaml.cs">
|
||||||
<DependentUpon>Msg.xaml</DependentUpon>
|
<DependentUpon>Msg.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="PluginLoader\PluginConfigLoader.cs" />
|
||||||
|
<Compile Include="PluginLoader\CSharpPluginConfigLoader.cs" />
|
||||||
<Compile Include="PluginLoader\BasePluginLoader.cs" />
|
<Compile Include="PluginLoader\BasePluginLoader.cs" />
|
||||||
<Compile Include="PluginLoader\CSharpPluginLoader.cs" />
|
<Compile Include="PluginLoader\BasePluginWrapper.cs" />
|
||||||
<Compile Include="PluginLoader\ExecutablePluginLoader.cs" />
|
|
||||||
<Compile Include="PluginLoader\ExecutablePluginWrapper.cs" />
|
|
||||||
<Compile Include="RPC\JsonPRCModel.cs" />
|
<Compile Include="RPC\JsonPRCModel.cs" />
|
||||||
<Compile Include="PluginLoader\Plugins.cs" />
|
<Compile Include="PluginLoader\Plugins.cs" />
|
||||||
<Compile Include="PluginLoader\PythonPluginLoader.cs" />
|
|
||||||
<Compile Include="PluginLoader\PythonPluginWrapper.cs" />
|
<Compile Include="PluginLoader\PythonPluginWrapper.cs" />
|
||||||
<Compile Include="Properties\Annotations.cs" />
|
<Compile Include="Properties\Annotations.cs" />
|
||||||
<Compile Include="ResultPanel.xaml.cs">
|
<Compile Include="ResultPanel.xaml.cs">
|
||||||
|
|||||||
Reference in New Issue
Block a user