mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge pull request #3432 from Flow-Launcher/jsonrpc_connection_loss
Fix JsonRpc plugin connection loss exception
This commit is contained in:
commit
b362bc6cb1
3 changed files with 38 additions and 36 deletions
|
|
@ -1,5 +1,4 @@
|
|||
using Flow.Launcher.Core.Resource;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
|
@ -7,10 +6,9 @@ using System.Text;
|
|||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Microsoft.IO;
|
||||
using System.Windows;
|
||||
|
||||
namespace Flow.Launcher.Core.Plugin
|
||||
{
|
||||
|
|
@ -20,7 +18,9 @@ namespace Flow.Launcher.Core.Plugin
|
|||
/// </summary>
|
||||
internal abstract class JsonRPCPlugin : JsonRPCPluginBase
|
||||
{
|
||||
public const string JsonRPC = "JsonRPC";
|
||||
public new const string JsonRPC = "JsonRPC";
|
||||
|
||||
private static readonly string ClassName = nameof(JsonRPCPlugin);
|
||||
|
||||
protected abstract Task<Stream> RequestAsync(JsonRPCRequestModel rpcRequest, CancellationToken token = default);
|
||||
protected abstract string Request(JsonRPCRequestModel rpcRequest, CancellationToken token = default);
|
||||
|
|
@ -29,9 +29,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
private int RequestId { get; set; }
|
||||
|
||||
private string SettingConfigurationPath => Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "SettingsTemplate.yaml");
|
||||
private string SettingPath => Path.Combine(Context.CurrentPluginMetadata.PluginSettingsDirectoryPath, "Settings.json");
|
||||
|
||||
public override List<Result> LoadContextMenus(Result selectedResult)
|
||||
{
|
||||
var request = new JsonRPCRequestModel(RequestId++,
|
||||
|
|
@ -57,13 +54,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
};
|
||||
|
||||
private static readonly JsonSerializerOptions settingSerializeOption = new()
|
||||
{
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
private readonly Dictionary<string, FrameworkElement> _settingControls = new();
|
||||
|
||||
private async Task<List<Result>> DeserializedResultAsync(Stream output)
|
||||
{
|
||||
await using (output)
|
||||
|
|
@ -122,7 +112,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
return !result.JsonRPCAction.DontHideAfterAction;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Execute external program and return the output
|
||||
/// </summary>
|
||||
|
|
@ -160,11 +149,11 @@ namespace Flow.Launcher.Core.Plugin
|
|||
var error = standardError.ReadToEnd();
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
{
|
||||
Log.Error($"|JsonRPCPlugin.Execute|{error}");
|
||||
Context.API.LogError(ClassName, error);
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
Log.Error("|JsonRPCPlugin.Execute|Empty standard output and standard error.");
|
||||
Context.API.LogError(ClassName, "Empty standard output and standard error.");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
|
|
@ -172,8 +161,8 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Exception(
|
||||
$"|JsonRPCPlugin.Execute|Exception for filename <{startInfo.FileName}> with argument <{startInfo.Arguments}>",
|
||||
Context.API.LogException(ClassName,
|
||||
$"Exception for filename <{startInfo.FileName}> with argument <{startInfo.Arguments}>",
|
||||
e);
|
||||
return string.Empty;
|
||||
}
|
||||
|
|
@ -184,7 +173,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
using var process = Process.Start(startInfo);
|
||||
if (process == null)
|
||||
{
|
||||
Log.Error("|JsonRPCPlugin.ExecuteAsync|Can't start new process");
|
||||
Context.API.LogError(ClassName, "Can't start new process");
|
||||
return Stream.Null;
|
||||
}
|
||||
|
||||
|
|
@ -204,7 +193,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Exception("|JsonRPCPlugin.ExecuteAsync|Exception when kill process", e);
|
||||
Context.API.LogException(ClassName, "Exception when kill process", e);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -225,7 +214,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
case (0, 0):
|
||||
const string errorMessage = "Empty JSON-RPC Response.";
|
||||
Log.Warn($"|{nameof(JsonRPCPlugin)}.{nameof(ExecuteAsync)}|{errorMessage}");
|
||||
Context.API.LogWarn(ClassName, errorMessage);
|
||||
break;
|
||||
case (_, not 0):
|
||||
throw new InvalidDataException(Encoding.UTF8.GetString(errorBuffer.ToArray())); // The process has exited with an error message
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
using Flow.Launcher.Core.Resource;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Plugin;
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
|
|
@ -19,10 +19,9 @@ namespace Flow.Launcher.Core.Plugin
|
|||
/// </summary>
|
||||
public abstract class JsonRPCPluginBase : IAsyncPlugin, IContextMenu, ISettingProvider, ISavable
|
||||
{
|
||||
protected PluginInitContext Context;
|
||||
public const string JsonRPC = "JsonRPC";
|
||||
|
||||
private int RequestId { get; set; }
|
||||
protected PluginInitContext Context;
|
||||
|
||||
private string SettingConfigurationPath =>
|
||||
Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "SettingsTemplate.yaml");
|
||||
|
|
@ -107,7 +106,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
public abstract Task<List<Result>> QueryAsync(Query query, CancellationToken token);
|
||||
|
||||
|
||||
private async Task InitSettingAsync()
|
||||
{
|
||||
JsonRpcConfigurationModel configuration = null;
|
||||
|
|
@ -119,7 +117,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
await File.ReadAllTextAsync(SettingConfigurationPath));
|
||||
}
|
||||
|
||||
|
||||
Settings ??= new JsonRPCPluginSettings
|
||||
{
|
||||
Configuration = configuration, SettingPath = SettingPath, API = Context.API
|
||||
|
|
@ -130,7 +127,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
public virtual async Task InitAsync(PluginInitContext context)
|
||||
{
|
||||
this.Context = context;
|
||||
Context = context;
|
||||
await InitSettingAsync();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,20 +10,20 @@ using Microsoft.VisualStudio.Threading;
|
|||
using StreamJsonRpc;
|
||||
using IAsyncDisposable = System.IAsyncDisposable;
|
||||
|
||||
|
||||
namespace Flow.Launcher.Core.Plugin
|
||||
{
|
||||
internal abstract class JsonRPCPluginV2 : JsonRPCPluginBase, IAsyncDisposable, IAsyncReloadable, IResultUpdated
|
||||
{
|
||||
public const string JsonRpc = "JsonRPC";
|
||||
|
||||
private static readonly string ClassName = nameof(JsonRPCPluginV2);
|
||||
|
||||
protected abstract IDuplexPipe ClientPipe { get; set; }
|
||||
|
||||
protected StreamReader ErrorStream { get; set; }
|
||||
|
||||
private JsonRpc RPC { get; set; }
|
||||
|
||||
|
||||
protected override async Task<bool> ExecuteResultAsync(JsonRPCResult result)
|
||||
{
|
||||
var res = await RPC.InvokeAsync<JsonRPCExecuteResponse>(result.JsonRPCAction.Method,
|
||||
|
|
@ -55,7 +55,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
return results;
|
||||
}
|
||||
|
||||
|
||||
public override async Task InitAsync(PluginInitContext context)
|
||||
{
|
||||
await base.InitAsync(context);
|
||||
|
|
@ -88,7 +87,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
protected abstract MessageHandlerType MessageHandler { get; }
|
||||
|
||||
|
||||
private void SetupJsonRPC()
|
||||
{
|
||||
var formatter = new SystemTextJsonFormatter { JsonSerializerOptions = RequestSerializeOption };
|
||||
|
|
@ -118,8 +116,17 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
await RPC.InvokeAsync("reload_data", Context);
|
||||
}
|
||||
catch (RemoteMethodNotFoundException e)
|
||||
catch (RemoteMethodNotFoundException)
|
||||
{
|
||||
// Ignored
|
||||
}
|
||||
catch (ConnectionLostException)
|
||||
{
|
||||
// Ignored
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Context.API.LogException(ClassName, $"Failed to call reload_data for plugin {Context.CurrentPluginMetadata.Name}", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -129,8 +136,17 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
await RPC.InvokeAsync("close");
|
||||
}
|
||||
catch (RemoteMethodNotFoundException e)
|
||||
catch (RemoteMethodNotFoundException)
|
||||
{
|
||||
// Ignored
|
||||
}
|
||||
catch (ConnectionLostException)
|
||||
{
|
||||
// Ignored
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Context.API.LogException(ClassName, $"Failed to call close for plugin {Context.CurrentPluginMetadata.Name}", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue