using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using Newtonsoft.Json; using Wox.Infrastructure.Exception; using Wox.Infrastructure.Logger; using Wox.Plugin; namespace Wox.Core.Plugin { /// /// Represent the plugin that using JsonPRC /// every JsonRPC plugin should has its own plugin instance /// internal abstract class JsonRPCPlugin : IPlugin, IContextMenu { protected PluginInitContext context; public const string JsonRPC = "JsonRPC"; /// /// The language this JsonRPCPlugin support /// public abstract string SupportedLanguage { get; set; } protected abstract string ExecuteQuery(Query query); protected abstract string ExecuteCallback(JsonRPCRequestModel rpcRequest); protected abstract string ExecuteContextMenu(Result selectedResult); public List Query(Query query) { string output = ExecuteQuery(query); try { return DeserializedResult(output); } catch (Exception e) { Log.Exception($"|JsonRPCPlugin.Query|Exception when query <{query}>", e); return null; } } public List LoadContextMenus(Result selectedResult) { string output = ExecuteContextMenu(selectedResult); try { return DeserializedResult(output); } catch (Exception e) { Log.Exception($"|JsonRPCPlugin.LoadContextMenus|Exception on result <{selectedResult}>", e); return null; } } private List DeserializedResult(string output) { if (!String.IsNullOrEmpty(output)) { List results = new List(); JsonRPCQueryResponseModel queryResponseModel = JsonConvert.DeserializeObject(output); if (queryResponseModel.Result == null) return null; foreach (JsonRPCResult result in queryResponseModel.Result) { JsonRPCResult result1 = result; result.Action = c => { if (result1.JsonRPCAction == null) return false; if (!String.IsNullOrEmpty(result1.JsonRPCAction.Method)) { if (result1.JsonRPCAction.Method.StartsWith("Wox.")) { ExecuteWoxAPI(result1.JsonRPCAction.Method.Substring(4), result1.JsonRPCAction.Parameters); } else { string actionReponse = ExecuteCallback(result1.JsonRPCAction); JsonRPCRequestModel jsonRpcRequestModel = JsonConvert.DeserializeObject(actionReponse); if (jsonRpcRequestModel != null && !String.IsNullOrEmpty(jsonRpcRequestModel.Method) && jsonRpcRequestModel.Method.StartsWith("Wox.")) { ExecuteWoxAPI(jsonRpcRequestModel.Method.Substring(4), jsonRpcRequestModel.Parameters); } } } return !result1.JsonRPCAction.DontHideAfterAction; }; results.Add(result); } return results; } else { return null; } } private void ExecuteWoxAPI(string method, object[] parameters) { MethodInfo methodInfo = PluginManager.API.GetType().GetMethod(method); if (methodInfo != null) { try { methodInfo.Invoke(PluginManager.API, parameters); } catch (Exception) { #if (DEBUG) { throw; } #endif } } } /// /// Execute external program and return the output /// /// /// /// protected string Execute(string fileName, string arguments) { ProcessStartInfo start = new ProcessStartInfo(); start.FileName = fileName; start.Arguments = arguments; start.UseShellExecute = false; start.CreateNoWindow = true; start.RedirectStandardOutput = true; start.RedirectStandardError = true; return Execute(start); } protected string Execute(ProcessStartInfo startInfo) { try { using (var process = Process.Start(startInfo)) { if (process != null) { using (var standardOutput = process.StandardOutput) { var result = standardOutput.ReadToEnd(); if (string.IsNullOrEmpty(result)) { using (var standardError = process.StandardError) { var error = standardError.ReadToEnd(); if (!string.IsNullOrEmpty(error)) { Log.Error($"|JsonRPCPlugin.Execute|{error}"); return string.Empty; } else { Log.Error("|JsonRPCPlugin.Execute|Empty standard output and standard error."); return string.Empty; } } } else if (result.StartsWith("DEBUG:")) { MessageBox.Show(new Form { TopMost = true }, result.Substring(6)); return string.Empty; } else { return result; } } } else { Log.Error("|JsonRPCPlugin.Execute|Can't start new process"); return string.Empty; } } } catch (Exception e) { Log.Exception($"|JsonRPCPlugin.Execute|Exception for filename <{startInfo.FileName}> with argument <{startInfo.Arguments}>", e); return string.Empty; } } public void Init(PluginInitContext ctx) { context = ctx; } } }