1111using System . Windows . Forms ;
1212using Flow . Launcher . Infrastructure . Logger ;
1313using Flow . Launcher . Plugin ;
14+ using ICSharpCode . SharpZipLib . Zip ;
1415using JetBrains . Annotations ;
16+ using Microsoft . IO ;
1517
1618namespace Flow . Launcher . Core . Plugin
1719{
@@ -33,9 +35,11 @@ internal abstract class JsonRPCPlugin : IAsyncPlugin, IContextMenu
3335 protected abstract string ExecuteCallback ( JsonRPCRequestModel rpcRequest ) ;
3436 protected abstract string ExecuteContextMenu ( Result selectedResult ) ;
3537
38+ private static readonly RecyclableMemoryStreamManager BufferManager = new ( ) ;
39+
3640 public List < Result > LoadContextMenus ( Result selectedResult )
3741 {
38- string output = ExecuteContextMenu ( selectedResult ) ;
42+ var output = ExecuteContextMenu ( selectedResult ) ;
3943 try
4044 {
4145 return DeserializedResult ( output ) ;
@@ -61,12 +65,23 @@ private async Task<List<Result>> DeserializedResultAsync(Stream output)
6165 {
6266 if ( output == Stream . Null ) return null ;
6367
64- var queryResponseModel = await
65- JsonSerializer . DeserializeAsync < JsonRPCQueryResponseModel > ( output , options ) ;
68+ try
69+ {
70+ var queryResponseModel =
71+ await JsonSerializer . DeserializeAsync < JsonRPCQueryResponseModel > ( output , options ) ;
6672
67- await output . DisposeAsync ( ) ;
68-
69- return ParseResults ( queryResponseModel ) ;
73+ return ParseResults ( queryResponseModel ) ;
74+ }
75+ catch ( JsonException e )
76+ {
77+ Log . Exception ( GetType ( ) . FullName , "Unexpected Json Input" , e ) ;
78+ }
79+ finally
80+ {
81+ await output . DisposeAsync ( ) ;
82+ }
83+
84+ return null ;
7085 }
7186
7287 private List < Result > DeserializedResult ( string output )
@@ -81,15 +96,14 @@ private List<Result> DeserializedResult(string output)
8196
8297 private List < Result > ParseResults ( JsonRPCQueryResponseModel queryResponseModel )
8398 {
84- var results = new List < Result > ( ) ;
8599 if ( queryResponseModel . Result == null ) return null ;
86100
87101 if ( ! string . IsNullOrEmpty ( queryResponseModel . DebugMessage ) )
88102 {
89103 context . API . ShowMsg ( queryResponseModel . DebugMessage ) ;
90104 }
91105
92- foreach ( JsonRPCResult result in queryResponseModel . Result )
106+ foreach ( var result in queryResponseModel . Result )
93107 {
94108 result . Action = c =>
95109 {
@@ -114,7 +128,8 @@ private List<Result> ParseResults(JsonRPCQueryResponseModel queryResponseModel)
114128 return ! result . JsonRPCAction . DontHideAfterAction ;
115129 }
116130
117- var jsonRpcRequestModel = JsonSerializer . Deserialize < JsonRPCRequestModel > ( actionResponse , options ) ;
131+ var jsonRpcRequestModel =
132+ JsonSerializer . Deserialize < JsonRPCRequestModel > ( actionResponse , options ) ;
118133
119134 if ( jsonRpcRequestModel ? . Method ? . StartsWith ( "Flow.Launcher." ) ?? false )
120135 {
@@ -125,9 +140,12 @@ private List<Result> ParseResults(JsonRPCQueryResponseModel queryResponseModel)
125140
126141 return ! result . JsonRPCAction . DontHideAfterAction ;
127142 } ;
128- results . Add ( result ) ;
129143 }
130144
145+ var results = new List < Result > ( ) ;
146+
147+ results . AddRange ( queryResponseModel . Result ) ;
148+
131149 return results ;
132150 }
133151
@@ -217,16 +235,42 @@ protected string Execute(ProcessStartInfo startInfo)
217235
218236 protected async Task < Stream > ExecuteAsync ( ProcessStartInfo startInfo , CancellationToken token = default )
219237 {
238+ Process process = null ;
239+ bool disposed = false ;
220240 try
221241 {
222- using var process = Process . Start ( startInfo ) ;
242+ process = Process . Start ( startInfo ) ;
223243 if ( process == null )
224244 {
225245 Log . Error ( "|JsonRPCPlugin.ExecuteAsync|Can't start new process" ) ;
226246 return Stream . Null ;
227247 }
228248
229- var result = process . StandardOutput . BaseStream ;
249+ await using var source = process . StandardOutput . BaseStream ;
250+
251+ var buffer = BufferManager . GetStream ( ) ;
252+
253+ token . Register ( ( ) =>
254+ {
255+ // ReSharper disable once AccessToModifiedClosure
256+ // Manually Check whether disposed
257+ if ( ! disposed && ! process . HasExited )
258+ process . Kill ( ) ;
259+ } ) ;
260+
261+ try
262+ {
263+ // token expire won't instantly trigger the exception,
264+ // manually kill process at before
265+ await source . CopyToAsync ( buffer , token ) ;
266+ }
267+ catch ( OperationCanceledException )
268+ {
269+ await buffer . DisposeAsync ( ) ;
270+ return Stream . Null ;
271+ }
272+
273+ buffer . Seek ( 0 , SeekOrigin . Begin ) ;
230274
231275 token . ThrowIfCancellationRequested ( ) ;
232276
@@ -245,7 +289,7 @@ protected async Task<Stream> ExecuteAsync(ProcessStartInfo startInfo, Cancellati
245289 return Stream . Null ;
246290 }
247291
248- return result ;
292+ return buffer ;
249293 }
250294 catch ( Exception e )
251295 {
@@ -254,15 +298,24 @@ protected async Task<Stream> ExecuteAsync(ProcessStartInfo startInfo, Cancellati
254298 e ) ;
255299 return Stream . Null ;
256300 }
301+ finally
302+ {
303+ process ? . Dispose ( ) ;
304+ disposed = true ;
305+ }
257306 }
258307
259308 public async Task < List < Result > > QueryAsync ( Query query , CancellationToken token )
260309 {
261- var output = await ExecuteQueryAsync ( query , token ) ;
262310 try
263311 {
312+ var output = await ExecuteQueryAsync ( query , token ) ;
264313 return await DeserializedResultAsync ( output ) ;
265314 }
315+ catch ( OperationCanceledException )
316+ {
317+ return null ;
318+ }
266319 catch ( Exception e )
267320 {
268321 Log . Exception ( $ "|JsonRPCPlugin.Query|Exception when query <{ query } >", e ) ;
0 commit comments