Skip to content

Commit b362bc6

Browse files
authored
Merge pull request #3432 from Flow-Launcher/jsonrpc_connection_loss
Fix JsonRpc plugin connection loss exception
2 parents 0444141 + 983d53a commit b362bc6

File tree

3 files changed

+38
-36
lines changed

3 files changed

+38
-36
lines changed

Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
using Flow.Launcher.Core.Resource;
2-
using System;
1+
using System;
32
using System.Collections.Generic;
43
using System.Diagnostics;
54
using System.IO;
65
using System.Text;
76
using System.Text.Json;
87
using System.Threading;
98
using System.Threading.Tasks;
10-
using Flow.Launcher.Infrastructure.Logger;
9+
using Flow.Launcher.Core.Resource;
1110
using Flow.Launcher.Plugin;
1211
using Microsoft.IO;
13-
using System.Windows;
1412

1513
namespace Flow.Launcher.Core.Plugin
1614
{
@@ -20,7 +18,9 @@ namespace Flow.Launcher.Core.Plugin
2018
/// </summary>
2119
internal abstract class JsonRPCPlugin : JsonRPCPluginBase
2220
{
23-
public const string JsonRPC = "JsonRPC";
21+
public new const string JsonRPC = "JsonRPC";
22+
23+
private static readonly string ClassName = nameof(JsonRPCPlugin);
2424

2525
protected abstract Task<Stream> RequestAsync(JsonRPCRequestModel rpcRequest, CancellationToken token = default);
2626
protected abstract string Request(JsonRPCRequestModel rpcRequest, CancellationToken token = default);
@@ -29,9 +29,6 @@ internal abstract class JsonRPCPlugin : JsonRPCPluginBase
2929

3030
private int RequestId { get; set; }
3131

32-
private string SettingConfigurationPath => Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "SettingsTemplate.yaml");
33-
private string SettingPath => Path.Combine(Context.CurrentPluginMetadata.PluginSettingsDirectoryPath, "Settings.json");
34-
3532
public override List<Result> LoadContextMenus(Result selectedResult)
3633
{
3734
var request = new JsonRPCRequestModel(RequestId++,
@@ -57,13 +54,6 @@ public override List<Result> LoadContextMenus(Result selectedResult)
5754
}
5855
};
5956

60-
private static readonly JsonSerializerOptions settingSerializeOption = new()
61-
{
62-
WriteIndented = true
63-
};
64-
65-
private readonly Dictionary<string, FrameworkElement> _settingControls = new();
66-
6757
private async Task<List<Result>> DeserializedResultAsync(Stream output)
6858
{
6959
await using (output)
@@ -122,7 +112,6 @@ protected override async Task<bool> ExecuteResultAsync(JsonRPCResult result)
122112
return !result.JsonRPCAction.DontHideAfterAction;
123113
}
124114

125-
126115
/// <summary>
127116
/// Execute external program and return the output
128117
/// </summary>
@@ -160,20 +149,20 @@ protected string Execute(ProcessStartInfo startInfo)
160149
var error = standardError.ReadToEnd();
161150
if (!string.IsNullOrEmpty(error))
162151
{
163-
Log.Error($"|JsonRPCPlugin.Execute|{error}");
152+
Context.API.LogError(ClassName, error);
164153
return string.Empty;
165154
}
166155

167-
Log.Error("|JsonRPCPlugin.Execute|Empty standard output and standard error.");
156+
Context.API.LogError(ClassName, "Empty standard output and standard error.");
168157
return string.Empty;
169158
}
170159

171160
return result;
172161
}
173162
catch (Exception e)
174163
{
175-
Log.Exception(
176-
$"|JsonRPCPlugin.Execute|Exception for filename <{startInfo.FileName}> with argument <{startInfo.Arguments}>",
164+
Context.API.LogException(ClassName,
165+
$"Exception for filename <{startInfo.FileName}> with argument <{startInfo.Arguments}>",
177166
e);
178167
return string.Empty;
179168
}
@@ -184,7 +173,7 @@ protected async Task<Stream> ExecuteAsync(ProcessStartInfo startInfo, Cancellati
184173
using var process = Process.Start(startInfo);
185174
if (process == null)
186175
{
187-
Log.Error("|JsonRPCPlugin.ExecuteAsync|Can't start new process");
176+
Context.API.LogError(ClassName, "Can't start new process");
188177
return Stream.Null;
189178
}
190179

@@ -204,7 +193,7 @@ protected async Task<Stream> ExecuteAsync(ProcessStartInfo startInfo, Cancellati
204193
}
205194
catch (Exception e)
206195
{
207-
Log.Exception("|JsonRPCPlugin.ExecuteAsync|Exception when kill process", e);
196+
Context.API.LogException(ClassName, "Exception when kill process", e);
208197
}
209198
});
210199

@@ -225,7 +214,7 @@ protected async Task<Stream> ExecuteAsync(ProcessStartInfo startInfo, Cancellati
225214
{
226215
case (0, 0):
227216
const string errorMessage = "Empty JSON-RPC Response.";
228-
Log.Warn($"|{nameof(JsonRPCPlugin)}.{nameof(ExecuteAsync)}|{errorMessage}");
217+
Context.API.LogWarn(ClassName, errorMessage);
229218
break;
230219
case (_, not 0):
231220
throw new InvalidDataException(Encoding.UTF8.GetString(errorBuffer.ToArray())); // The process has exited with an error message

Flow.Launcher.Core/Plugin/JsonRPCPluginBase.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
using Flow.Launcher.Core.Resource;
2-
using System;
1+
using System;
32
using System.Collections.Generic;
43
using System.IO;
54
using System.Linq;
65
using System.Text.Json;
76
using System.Threading;
87
using System.Threading.Tasks;
8+
using Flow.Launcher.Core.Resource;
99
using Flow.Launcher.Plugin;
1010
using YamlDotNet.Serialization;
1111
using YamlDotNet.Serialization.NamingConventions;
@@ -19,10 +19,9 @@ namespace Flow.Launcher.Core.Plugin
1919
/// </summary>
2020
public abstract class JsonRPCPluginBase : IAsyncPlugin, IContextMenu, ISettingProvider, ISavable
2121
{
22-
protected PluginInitContext Context;
2322
public const string JsonRPC = "JsonRPC";
2423

25-
private int RequestId { get; set; }
24+
protected PluginInitContext Context;
2625

2726
private string SettingConfigurationPath =>
2827
Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "SettingsTemplate.yaml");
@@ -107,7 +106,6 @@ protected void ExecuteFlowLauncherAPI(string method, object[] parameters)
107106

108107
public abstract Task<List<Result>> QueryAsync(Query query, CancellationToken token);
109108

110-
111109
private async Task InitSettingAsync()
112110
{
113111
JsonRpcConfigurationModel configuration = null;
@@ -119,7 +117,6 @@ private async Task InitSettingAsync()
119117
await File.ReadAllTextAsync(SettingConfigurationPath));
120118
}
121119

122-
123120
Settings ??= new JsonRPCPluginSettings
124121
{
125122
Configuration = configuration, SettingPath = SettingPath, API = Context.API
@@ -130,7 +127,7 @@ private async Task InitSettingAsync()
130127

131128
public virtual async Task InitAsync(PluginInitContext context)
132129
{
133-
this.Context = context;
130+
Context = context;
134131
await InitSettingAsync();
135132
}
136133

Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,20 @@
1010
using StreamJsonRpc;
1111
using IAsyncDisposable = System.IAsyncDisposable;
1212

13-
1413
namespace Flow.Launcher.Core.Plugin
1514
{
1615
internal abstract class JsonRPCPluginV2 : JsonRPCPluginBase, IAsyncDisposable, IAsyncReloadable, IResultUpdated
1716
{
1817
public const string JsonRpc = "JsonRPC";
1918

19+
private static readonly string ClassName = nameof(JsonRPCPluginV2);
20+
2021
protected abstract IDuplexPipe ClientPipe { get; set; }
2122

2223
protected StreamReader ErrorStream { get; set; }
2324

2425
private JsonRpc RPC { get; set; }
2526

26-
2727
protected override async Task<bool> ExecuteResultAsync(JsonRPCResult result)
2828
{
2929
var res = await RPC.InvokeAsync<JsonRPCExecuteResponse>(result.JsonRPCAction.Method,
@@ -55,7 +55,6 @@ public override async Task<List<Result>> QueryAsync(Query query, CancellationTok
5555
return results;
5656
}
5757

58-
5958
public override async Task InitAsync(PluginInitContext context)
6059
{
6160
await base.InitAsync(context);
@@ -88,7 +87,6 @@ protected enum MessageHandlerType
8887

8988
protected abstract MessageHandlerType MessageHandler { get; }
9089

91-
9290
private void SetupJsonRPC()
9391
{
9492
var formatter = new SystemTextJsonFormatter { JsonSerializerOptions = RequestSerializeOption };
@@ -118,8 +116,17 @@ public virtual async Task ReloadDataAsync()
118116
{
119117
await RPC.InvokeAsync("reload_data", Context);
120118
}
121-
catch (RemoteMethodNotFoundException e)
119+
catch (RemoteMethodNotFoundException)
120+
{
121+
// Ignored
122+
}
123+
catch (ConnectionLostException)
122124
{
125+
// Ignored
126+
}
127+
catch (Exception e)
128+
{
129+
Context.API.LogException(ClassName, $"Failed to call reload_data for plugin {Context.CurrentPluginMetadata.Name}", e);
123130
}
124131
}
125132

@@ -129,8 +136,17 @@ public virtual async ValueTask DisposeAsync()
129136
{
130137
await RPC.InvokeAsync("close");
131138
}
132-
catch (RemoteMethodNotFoundException e)
139+
catch (RemoteMethodNotFoundException)
140+
{
141+
// Ignored
142+
}
143+
catch (ConnectionLostException)
144+
{
145+
// Ignored
146+
}
147+
catch (Exception e)
133148
{
149+
Context.API.LogException(ClassName, $"Failed to call close for plugin {Context.CurrentPluginMetadata.Name}", e);
134150
}
135151
finally
136152
{

0 commit comments

Comments
 (0)