mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge pull request #2578 from Flow-Launcher/node-plugin-processinfo
fix node plugin, job object association, v2 context menu
This commit is contained in:
commit
085de915d6
6 changed files with 68 additions and 48 deletions
|
|
@ -12,15 +12,9 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
|
|
||||||
public ExecutablePluginV2(string filename)
|
public ExecutablePluginV2(string filename)
|
||||||
{
|
{
|
||||||
StartInfo = new ProcessStartInfo
|
StartInfo = new ProcessStartInfo { FileName = filename };
|
||||||
{
|
|
||||||
FileName = filename,
|
|
||||||
UseShellExecute = false,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override MessageHandlerType MessageHandler { get; } = MessageHandlerType.NewLineDelimited;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,6 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
{
|
{
|
||||||
internal abstract class JsonRPCPluginV2 : JsonRPCPluginBase, IAsyncDisposable, IAsyncReloadable, IResultUpdated
|
internal abstract class JsonRPCPluginV2 : JsonRPCPluginBase, IAsyncDisposable, IAsyncReloadable, IResultUpdated
|
||||||
{
|
{
|
||||||
public abstract string SupportedLanguage { get; set; }
|
|
||||||
|
|
||||||
public const string JsonRpc = "JsonRPC";
|
public const string JsonRpc = "JsonRPC";
|
||||||
|
|
||||||
protected abstract IDuplexPipe ClientPipe { get; set; }
|
protected abstract IDuplexPipe ClientPipe { get; set; }
|
||||||
|
|
@ -41,9 +39,23 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private JoinableTaskFactory JTF { get; } = new JoinableTaskFactory(new JoinableTaskContext());
|
||||||
|
|
||||||
public override List<Result> LoadContextMenus(Result selectedResult)
|
public override List<Result> LoadContextMenus(Result selectedResult)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
try
|
||||||
|
{
|
||||||
|
var res = JTF.Run(() => RPC.InvokeWithCancellationAsync<JsonRPCQueryResponseModel>("context_menu",
|
||||||
|
new object[] { selectedResult.ContextData }));
|
||||||
|
|
||||||
|
var results = ParseResults(res);
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new List<Result>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
|
public override async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
|
||||||
|
|
@ -51,7 +63,7 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var res = await RPC.InvokeWithCancellationAsync<JsonRPCQueryResponseModel>("query",
|
var res = await RPC.InvokeWithCancellationAsync<JsonRPCQueryResponseModel>("query",
|
||||||
new[] { query },
|
new object[] { query, Settings.Inner },
|
||||||
token);
|
token);
|
||||||
|
|
||||||
var results = ParseResults(res);
|
var results = ParseResults(res);
|
||||||
|
|
@ -88,12 +100,26 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
|
|
||||||
public event ResultUpdatedEventHandler ResultsUpdated;
|
public event ResultUpdatedEventHandler ResultsUpdated;
|
||||||
|
|
||||||
|
protected enum MessageHandlerType
|
||||||
|
{
|
||||||
|
HeaderDelimited,
|
||||||
|
LengthHeaderDelimited,
|
||||||
|
NewLineDelimited
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract MessageHandlerType MessageHandler { get; }
|
||||||
|
|
||||||
|
|
||||||
private void SetupJsonRPC()
|
private void SetupJsonRPC()
|
||||||
{
|
{
|
||||||
var formatter = new SystemTextJsonFormatter { JsonSerializerOptions = RequestSerializeOption };
|
var formatter = new SystemTextJsonFormatter { JsonSerializerOptions = RequestSerializeOption };
|
||||||
var handler = new NewLineDelimitedMessageHandler(ClientPipe,
|
IJsonRpcMessageHandler handler = MessageHandler switch
|
||||||
formatter);
|
{
|
||||||
|
MessageHandlerType.HeaderDelimited => new HeaderDelimitedMessageHandler(ClientPipe, formatter),
|
||||||
|
MessageHandlerType.LengthHeaderDelimited => new LengthHeaderMessageHandler(ClientPipe, formatter),
|
||||||
|
MessageHandlerType.NewLineDelimited => new NewLineDelimitedMessageHandler(ClientPipe, formatter),
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
};
|
||||||
|
|
||||||
RPC = new JsonRpc(handler, new JsonRPCPublicAPI(Context.API));
|
RPC = new JsonRpc(handler, new JsonRPCPublicAPI(Context.API));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,29 +10,21 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Execution of JavaScript & TypeScript plugins
|
/// Execution of JavaScript & TypeScript plugins
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class NodePluginV2 : ProcessStreamPluginV2
|
internal sealed class NodePluginV2 : ProcessStreamPluginV2
|
||||||
{
|
{
|
||||||
public NodePluginV2(string filename)
|
public NodePluginV2(string filename)
|
||||||
{
|
{
|
||||||
StartInfo = new ProcessStartInfo
|
StartInfo = new ProcessStartInfo { FileName = filename, };
|
||||||
{
|
|
||||||
FileName = filename,
|
|
||||||
UseShellExecute = false,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string SupportedLanguage { get; set; }
|
|
||||||
protected override ProcessStartInfo StartInfo { get; set; }
|
protected override ProcessStartInfo StartInfo { get; set; }
|
||||||
|
|
||||||
public override async Task InitAsync(PluginInitContext context)
|
public override async Task InitAsync(PluginInitContext context)
|
||||||
{
|
{
|
||||||
StartInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath);
|
StartInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath);
|
||||||
StartInfo.ArgumentList.Add(string.Empty);
|
|
||||||
StartInfo.WorkingDirectory = context.CurrentPluginMetadata.PluginDirectory;
|
|
||||||
await base.InitAsync(context);
|
await base.InitAsync(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override MessageHandlerType MessageHandler { get; } = MessageHandlerType.HeaderDelimited;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
using System;
|
#nullable enable
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
|
|
@ -6,6 +8,7 @@ using System.Threading.Tasks;
|
||||||
using Flow.Launcher.Infrastructure;
|
using Flow.Launcher.Infrastructure;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
using Meziantou.Framework.Win32;
|
using Meziantou.Framework.Win32;
|
||||||
|
using Microsoft.VisualBasic.ApplicationServices;
|
||||||
using Nerdbank.Streams;
|
using Nerdbank.Streams;
|
||||||
|
|
||||||
namespace Flow.Launcher.Core.Plugin
|
namespace Flow.Launcher.Core.Plugin
|
||||||
|
|
@ -18,18 +21,18 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
{
|
{
|
||||||
_jobObject.SetLimits(new JobObjectLimits()
|
_jobObject.SetLimits(new JobObjectLimits()
|
||||||
{
|
{
|
||||||
Flags = JobObjectLimitFlags.KillOnJobClose | JobObjectLimitFlags.DieOnUnhandledException
|
Flags = JobObjectLimitFlags.KillOnJobClose | JobObjectLimitFlags.DieOnUnhandledException |
|
||||||
|
JobObjectLimitFlags.SilentBreakawayOk
|
||||||
});
|
});
|
||||||
|
|
||||||
_jobObject.AssignProcess(Process.GetCurrentProcess());
|
_jobObject.AssignProcess(Process.GetCurrentProcess());
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string SupportedLanguage { get; set; }
|
protected sealed override IDuplexPipe ClientPipe { get; set; } = null!;
|
||||||
protected sealed override IDuplexPipe ClientPipe { get; set; }
|
|
||||||
|
|
||||||
protected abstract ProcessStartInfo StartInfo { get; set; }
|
protected abstract ProcessStartInfo StartInfo { get; set; }
|
||||||
|
|
||||||
protected Process ClientProcess { get; set; }
|
protected Process ClientProcess { get; set; } = null!;
|
||||||
|
|
||||||
public override async Task InitAsync(PluginInitContext context)
|
public override async Task InitAsync(PluginInitContext context)
|
||||||
{
|
{
|
||||||
|
|
@ -37,12 +40,18 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
StartInfo.EnvironmentVariables["FLOW_PROGRAM_DIRECTORY"] = Constant.ProgramDirectory;
|
StartInfo.EnvironmentVariables["FLOW_PROGRAM_DIRECTORY"] = Constant.ProgramDirectory;
|
||||||
StartInfo.EnvironmentVariables["FLOW_APPLICATION_DIRECTORY"] = Constant.ApplicationDirectory;
|
StartInfo.EnvironmentVariables["FLOW_APPLICATION_DIRECTORY"] = Constant.ApplicationDirectory;
|
||||||
|
|
||||||
StartInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath);
|
StartInfo.RedirectStandardError = true;
|
||||||
|
StartInfo.RedirectStandardInput = true;
|
||||||
|
StartInfo.RedirectStandardOutput = true;
|
||||||
|
StartInfo.CreateNoWindow = true;
|
||||||
|
StartInfo.UseShellExecute = false;
|
||||||
StartInfo.WorkingDirectory = context.CurrentPluginMetadata.PluginDirectory;
|
StartInfo.WorkingDirectory = context.CurrentPluginMetadata.PluginDirectory;
|
||||||
|
|
||||||
ClientProcess = Process.Start(StartInfo);
|
var process = Process.Start(StartInfo);
|
||||||
ArgumentNullException.ThrowIfNull(ClientProcess);
|
ArgumentNullException.ThrowIfNull(process);
|
||||||
|
ClientProcess = process;
|
||||||
|
_jobObject.AssignProcess(ClientProcess);
|
||||||
|
|
||||||
SetupPipe(ClientProcess);
|
SetupPipe(ClientProcess);
|
||||||
|
|
||||||
ErrorStream = ClientProcess.StandardError;
|
ErrorStream = ClientProcess.StandardError;
|
||||||
|
|
|
||||||
|
|
@ -18,20 +18,11 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
{
|
{
|
||||||
internal sealed class PythonPluginV2 : ProcessStreamPluginV2
|
internal sealed class PythonPluginV2 : ProcessStreamPluginV2
|
||||||
{
|
{
|
||||||
public override string SupportedLanguage { get; set; } = AllowedLanguage.Python;
|
|
||||||
protected override ProcessStartInfo StartInfo { get; set; }
|
protected override ProcessStartInfo StartInfo { get; set; }
|
||||||
|
|
||||||
public PythonPluginV2(string filename)
|
public PythonPluginV2(string filename)
|
||||||
{
|
{
|
||||||
StartInfo = new ProcessStartInfo
|
StartInfo = new ProcessStartInfo { FileName = filename, };
|
||||||
{
|
|
||||||
FileName = filename,
|
|
||||||
UseShellExecute = false,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
RedirectStandardInput = true
|
|
||||||
};
|
|
||||||
|
|
||||||
var path = Path.Combine(Constant.ProgramDirectory, JsonRpc);
|
var path = Path.Combine(Constant.ProgramDirectory, JsonRpc);
|
||||||
StartInfo.EnvironmentVariables["PYTHONPATH"] = path;
|
StartInfo.EnvironmentVariables["PYTHONPATH"] = path;
|
||||||
|
|
@ -39,5 +30,13 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
//Add -B flag to tell python don't write .py[co] files. Because .pyc contains location infos which will prevent python portable
|
//Add -B flag to tell python don't write .py[co] files. Because .pyc contains location infos which will prevent python portable
|
||||||
StartInfo.ArgumentList.Add("-B");
|
StartInfo.ArgumentList.Add("-B");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task InitAsync(PluginInitContext context)
|
||||||
|
{
|
||||||
|
StartInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath);
|
||||||
|
await base.InitAsync(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override MessageHandlerType MessageHandler { get; } = MessageHandlerType.NewLineDelimited;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
FileName = FullPath,
|
FileName = FullPath,
|
||||||
WorkingDirectory = ParentDirectory,
|
WorkingDirectory = ParentDirectory,
|
||||||
UseShellExecute = true,
|
UseShellExecute = true,
|
||||||
Verb = runAsAdmin ? "runas" : ""
|
Verb = runAsAdmin ? "runas" : "",
|
||||||
};
|
};
|
||||||
|
|
||||||
_ = Task.Run(() => Main.StartProcess(Process.Start, info));
|
_ = Task.Run(() => Main.StartProcess(Process.Start, info));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue