diff --git a/Wox.Plugin/AllowedLanguage.cs b/Wox.Plugin/AllowedLanguage.cs index 32262b48f2..f226bb5815 100644 --- a/Wox.Plugin/AllowedLanguage.cs +++ b/Wox.Plugin/AllowedLanguage.cs @@ -19,7 +19,7 @@ namespace Wox.Plugin public static string ExecutableFile { - get { return "ExecutableFile"; } + get { return "executablefile"; } } public static bool IsAllowed(string language) diff --git a/Wox/PluginLoader/BasePluginLoader.cs b/Wox/PluginLoader/BasePluginLoader.cs index 6e13fec2b9..98b8e7b63f 100644 --- a/Wox/PluginLoader/BasePluginLoader.cs +++ b/Wox/PluginLoader/BasePluginLoader.cs @@ -1,118 +1,32 @@ 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 System.Text; using Wox.Plugin; -using Wox.Plugin.SystemPlugins; +using Wox.RPC; -namespace Wox.PluginLoader { - public abstract class BasePluginLoader { - private static string PluginPath = Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), "Plugins"); - private static string PluginConfigName = "plugin.json"; - protected static List pluginMetadatas = new List(); - public abstract List LoadPlugin(); +namespace Wox.PluginLoader +{ + public class BasePluginLoader where T :BasePluginWrapper,new() + { + public List LoadPlugin(List pluginMetadatas) + { + List plugins = new List(); - public static void ParsePluginsConfig() { - pluginMetadatas.Clear(); - ParseSystemPlugins(); - ParseThirdPartyPlugins(); + T pluginWrapper = new T(); + List allowedLanguages = pluginWrapper.GetAllowedLanguages(); + List metadatas = pluginMetadatas.Where(o => allowedLanguages.Contains(o.Language.ToUpper())).ToList(); + foreach (PluginMetadata metadata in metadatas) + { + PluginPair pair = new PluginPair() + { + Plugin = pluginWrapper, + Metadata = metadata + }; + plugins.Add(pair); + } - if (Plugins.DebuggerMode != null) { - 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(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; - } - } + return plugins; + } + } } diff --git a/Wox/PluginLoader/BasePluginWrapper.cs b/Wox/PluginLoader/BasePluginWrapper.cs new file mode 100644 index 0000000000..ff450f8fb7 --- /dev/null +++ b/Wox/PluginLoader/BasePluginWrapper.cs @@ -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 GetAllowedLanguages(); + protected abstract string GetFileName(); + + protected abstract string GetQueryArguments(Query query); + + protected abstract string GetActionJsonRPCArguments(ActionJsonRPCResult result); + + public List Query(Query query) + { + string fileName = GetFileName(); + string arguments = GetQueryArguments(query); + string output = Execute(fileName, arguments); + if (!string.IsNullOrEmpty(output)) + { + try + { + JsonPRCModel rpc = JsonConvert.DeserializeObject(output); + List rpcresults = + JsonConvert.DeserializeObject>(rpc.result); + List results = new List(); + 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; + } + } +} diff --git a/Wox/PluginLoader/CSharpPluginLoader.cs b/Wox/PluginLoader/CSharpPluginConfigLoader.cs similarity index 91% rename from Wox/PluginLoader/CSharpPluginLoader.cs rename to Wox/PluginLoader/CSharpPluginConfigLoader.cs index 065a824558..088817792f 100644 --- a/Wox/PluginLoader/CSharpPluginLoader.cs +++ b/Wox/PluginLoader/CSharpPluginConfigLoader.cs @@ -8,9 +8,10 @@ using Wox.Plugin.SystemPlugins; namespace Wox.PluginLoader { - public class CSharpPluginLoader : BasePluginLoader { - - public override List LoadPlugin() { + public class CSharpPluginConfigLoader + { + public List LoadPlugin(List pluginMetadatas) + { var plugins = new List(); List metadatas = pluginMetadatas.Where(o => o.Language.ToUpper() == AllowedLanguage.CSharp.ToUpper()).ToList(); diff --git a/Wox/PluginLoader/ExecutablePluginLoader.cs b/Wox/PluginLoader/ExecutablePluginLoader.cs deleted file mode 100644 index e49e08ae9b..0000000000 --- a/Wox/PluginLoader/ExecutablePluginLoader.cs +++ /dev/null @@ -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 LoadPlugin() - { - List plugins = new List(); - List 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; - } - } -} diff --git a/Wox/PluginLoader/ExecutablePluginWrapper.cs b/Wox/PluginLoader/ExecutablePluginWrapper.cs deleted file mode 100644 index a638c7a51a..0000000000 --- a/Wox/PluginLoader/ExecutablePluginWrapper.cs +++ /dev/null @@ -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 Query(Query query) - { - List results = new List(); - 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(output); - var rpcresults = JsonConvert.DeserializeObject>(rpc.result); - List r = new List(); - 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; - } - } -} diff --git a/Wox/PluginLoader/PluginConfigLoader.cs b/Wox/PluginLoader/PluginConfigLoader.cs new file mode 100644 index 0000000000..591af2143b --- /dev/null +++ b/Wox/PluginLoader/PluginConfigLoader.cs @@ -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 pluginMetadatas = new List(); + + public static List 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(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; + } + } +} diff --git a/Wox/PluginLoader/Plugins.cs b/Wox/PluginLoader/Plugins.cs index 03eecab4fc..5d10e0da6c 100644 --- a/Wox/PluginLoader/Plugins.cs +++ b/Wox/PluginLoader/Plugins.cs @@ -14,11 +14,10 @@ namespace Wox.PluginLoader public static void Init() { plugins.Clear(); - BasePluginLoader.ParsePluginsConfig(); + List pluginMetadatas = PluginConfigLoader.ParsePluginsConfig(); - plugins.AddRange(new PythonPluginLoader().LoadPlugin()); - plugins.AddRange(new CSharpPluginLoader().LoadPlugin()); - plugins.AddRange(new ExecutablePluginLoader().LoadPlugin()); + plugins.AddRange(new CSharpPluginConfigLoader().LoadPlugin(pluginMetadatas)); + plugins.AddRange(new BasePluginLoader().LoadPlugin(pluginMetadatas)); Forker forker = new Forker(); foreach (IPlugin plugin in plugins.Select(pluginPair => pluginPair.Plugin)) diff --git a/Wox/PluginLoader/PythonPluginLoader.cs b/Wox/PluginLoader/PythonPluginLoader.cs deleted file mode 100644 index e5bd223b3f..0000000000 --- a/Wox/PluginLoader/PythonPluginLoader.cs +++ /dev/null @@ -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 LoadPlugin() - { - if (!CheckPythonEnvironmentInstalled()) return new List(); - - List plugins = new List(); - List 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 - } - } -} diff --git a/Wox/PluginLoader/PythonPluginWrapper.cs b/Wox/PluginLoader/PythonPluginWrapper.cs index a021f7796d..f6c1f39667 100644 --- a/Wox/PluginLoader/PythonPluginWrapper.cs +++ b/Wox/PluginLoader/PythonPluginWrapper.cs @@ -1,142 +1,43 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; -using Newtonsoft.Json; +using System.Threading; using Python.Runtime; -using Wox.Helper; using Wox.Plugin; +using Wox.Helper; +using Wox.RPC; namespace Wox.PluginLoader { - public class PythonPluginWrapper : IPlugin + public class PythonPluginWrapper : BasePluginWrapper { - private PluginMetadata metadata; - private string moduleName; + private static string woxDirectory = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); - public PythonPluginWrapper(PluginMetadata metadata) + public override List GetAllowedLanguages() { - this.metadata = metadata; - moduleName = metadata.ExecuteFileName.Replace(".py", ""); + return new List() + { + AllowedLanguage.Python + }; } - public List Query(Query query) + protected override string GetFileName() { - try - { - string jsonResult = InvokeFunc("query", query.RawQuery); - if (string.IsNullOrEmpty(jsonResult)) - { - return new List(); - } - - List o = JsonConvert.DeserializeObject>(jsonResult); - List r = new List(); - 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(); + return Path.Combine(woxDirectory, "PYTHONTHOME\\Scripts\\python.exe"); } - private PyObject GetPythonActionContext(ActionContext context) + protected override string GetQueryArguments(Query query) { - PyDict dict = new PyDict(); - PyDict specialKeyStateDict = new PyDict(); - specialKeyStateDict["CtrlPressed"] = new PyString(context.SpecialKeyState.CtrlPressed.ToString()); - 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; + return string.Format("{0} \"{1}\"", + context.CurrentPluginMetadata.ExecuteFilePath, + JsonRPC.GetRPC("query", query.GetAllRemainingParameter())); } - private string InvokeFunc(string func, params PyObject[] paras) + protected override string GetActionJsonRPCArguments(ActionJsonRPCResult result) { - string json = null; - - //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) - { - + return string.Format("{0} \"{1}\"", context.CurrentPluginMetadata.ExecuteFilePath, + result.ActionJSONRPC); } } } diff --git a/Wox/Wox.csproj b/Wox/Wox.csproj index c67f6f5efc..384a3bc2bc 100644 --- a/Wox/Wox.csproj +++ b/Wox/Wox.csproj @@ -142,13 +142,12 @@ Msg.xaml + + - - - + -