From c50d98c5e2dd1726c973b13917ef4e28308b49fb Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Mon, 3 Jul 2023 16:44:50 +0800 Subject: [PATCH] Abstract out ProcessStreamPluginV2.cs and add ExecutablePluginV2.cs --- .../Plugin/ExecutablePluginV2.cs | 26 +++++++ Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs | 7 ++ .../Plugin/ProcessStreamPluginV2.cs | 68 +++++++++++++++++++ Flow.Launcher.Core/Plugin/PythonPluginV2.cs | 66 ++---------------- 4 files changed, 107 insertions(+), 60 deletions(-) create mode 100644 Flow.Launcher.Core/Plugin/ExecutablePluginV2.cs create mode 100644 Flow.Launcher.Core/Plugin/ProcessStreamPluginV2.cs diff --git a/Flow.Launcher.Core/Plugin/ExecutablePluginV2.cs b/Flow.Launcher.Core/Plugin/ExecutablePluginV2.cs new file mode 100644 index 000000000..ee1b315c2 --- /dev/null +++ b/Flow.Launcher.Core/Plugin/ExecutablePluginV2.cs @@ -0,0 +1,26 @@ +using System.Diagnostics; +using System.IO; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +namespace Flow.Launcher.Core.Plugin +{ + internal sealed class ExecutablePluginV2 : ProcessStreamPluginV2 + { + protected override ProcessStartInfo StartInfo { get; set; } + + public ExecutablePluginV2(string filename) + { + StartInfo = new ProcessStartInfo + { + FileName = filename, + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true + }; + } + + } +} diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs b/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs index c6ef870c3..60130843e 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs @@ -6,7 +6,9 @@ using System.Threading; using System.Threading.Tasks; using Flow.Launcher.Core.Plugin.JsonRPCV2Models; using Flow.Launcher.Plugin; +using Microsoft.VisualStudio.Threading; using StreamJsonRpc; +using IAsyncDisposable = System.IAsyncDisposable; namespace Flow.Launcher.Core.Plugin @@ -39,6 +41,11 @@ namespace Flow.Launcher.Core.Plugin } } + public override List LoadContextMenus(Result selectedResult) + { + throw new NotImplementedException(); + } + public override async Task> QueryAsync(Query query, CancellationToken token) { try diff --git a/Flow.Launcher.Core/Plugin/ProcessStreamPluginV2.cs b/Flow.Launcher.Core/Plugin/ProcessStreamPluginV2.cs new file mode 100644 index 000000000..be35d481c --- /dev/null +++ b/Flow.Launcher.Core/Plugin/ProcessStreamPluginV2.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO.Pipelines; +using System.Threading.Tasks; +using Flow.Launcher.Infrastructure; +using Flow.Launcher.Plugin; +using Nerdbank.Streams; + +namespace Flow.Launcher.Core.Plugin +{ + internal abstract class ProcessStreamPluginV2 : JsonRPCPluginV2 + { + + public override string SupportedLanguage { get; set; } + protected override IDuplexPipe ClientPipe { get; set; } + + protected abstract ProcessStartInfo StartInfo { get; set; } + + public Process ClientProcess { get; set; } + + public override async Task InitAsync(PluginInitContext context) + { + StartInfo.EnvironmentVariables["FLOW_VERSION"] = Constant.Version; + StartInfo.EnvironmentVariables["FLOW_PROGRAM_DIRECTORY"] = Constant.ProgramDirectory; + StartInfo.EnvironmentVariables["FLOW_APPLICATION_DIRECTORY"] = Constant.ApplicationDirectory; + + StartInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); + StartInfo.WorkingDirectory = context.CurrentPluginMetadata.PluginDirectory; + + ClientProcess = Process.Start(StartInfo); + ArgumentNullException.ThrowIfNull(ClientProcess); + + SetupPipe(ClientProcess); + + await base.InitAsync(context); + } + + private void SetupPipe(Process process) + { + var (reader, writer) = (PipeReader.Create(process.StandardOutput.BaseStream), + PipeWriter.Create(process.StandardInput.BaseStream)); + ClientPipe = new DuplexPipe(reader, writer); + } + + + public override async Task ReloadDataAsync() + { + var oldProcess = ClientProcess; + ClientProcess = Process.Start(StartInfo); + ArgumentNullException.ThrowIfNull(ClientProcess); + SetupPipe(ClientProcess); + await base.ReloadDataAsync(); + oldProcess.Kill(true); + await oldProcess.WaitForExitAsync(); + oldProcess.Dispose(); + } + + + public override async ValueTask DisposeAsync() + { + ClientProcess.Kill(true); + await ClientProcess.WaitForExitAsync(); + ClientProcess.Dispose(); + await base.DisposeAsync(); + } + } +} diff --git a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs index 98b55f896..09c1a069a 100644 --- a/Flow.Launcher.Core/Plugin/PythonPluginV2.cs +++ b/Flow.Launcher.Core/Plugin/PythonPluginV2.cs @@ -16,19 +16,16 @@ using StreamJsonRpc; namespace Flow.Launcher.Core.Plugin { - internal class PythonPluginV2 : JsonRPCPluginV2 + internal sealed class PythonPluginV2 : ProcessStreamPluginV2 { - private readonly ProcessStartInfo _startInfo; - private Process _process; - public override string SupportedLanguage { get; set; } = AllowedLanguage.Python; protected override IDuplexPipe ClientPipe { get; set; } - - + protected override ProcessStartInfo StartInfo { get; set; } + public PythonPluginV2(string filename) { - _startInfo = new ProcessStartInfo + StartInfo = new ProcessStartInfo { FileName = filename, UseShellExecute = false, @@ -40,61 +37,10 @@ namespace Flow.Launcher.Core.Plugin // temp fix for issue #667 var path = Path.Combine(Constant.ProgramDirectory, JsonRpc); - _startInfo.EnvironmentVariables["PYTHONPATH"] = path; - - _startInfo.EnvironmentVariables["FLOW_VERSION"] = Constant.Version; - _startInfo.EnvironmentVariables["FLOW_PROGRAM_DIRECTORY"] = Constant.ProgramDirectory; - _startInfo.EnvironmentVariables["FLOW_APPLICATION_DIRECTORY"] = Constant.ApplicationDirectory; - + StartInfo.EnvironmentVariables["PYTHONPATH"] = path; //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"); - } - - - public override List LoadContextMenus(Result selectedResult) - { - throw new NotImplementedException(); - } - - public override async Task InitAsync(PluginInitContext context) - { - _startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath); - _startInfo.WorkingDirectory = context.CurrentPluginMetadata.PluginDirectory; - - _process = Process.Start(_startInfo); - ArgumentNullException.ThrowIfNull(_process); - - SetupPipe(_process); - - await base.InitAsync(context); - } - - public override async ValueTask DisposeAsync() - { - _process.Kill(true); - await _process.WaitForExitAsync(); - _process.Dispose(); - await base.DisposeAsync(); - } - - private void SetupPipe(Process process) - { - var (reader, writer) = (PipeReader.Create(process.StandardOutput.BaseStream), - PipeWriter.Create(process.StandardInput.BaseStream)); - ClientPipe = new DuplexPipe(reader, writer); - } - - public override async Task ReloadDataAsync() - { - var oldProcess = _process; - _process = Process.Start(_startInfo); - ArgumentNullException.ThrowIfNull(_process); - SetupPipe(_process); - await base.ReloadDataAsync(); - oldProcess.Kill(true); - await oldProcess.WaitForExitAsync(); - oldProcess.Dispose(); + StartInfo.ArgumentList.Add("-B"); } } }