mirror of
https://github.com/scratchfoundation/scratch-link.git
synced 2025-08-28 22:39:42 -04:00
send method response with a completion handler
This allows methods to perform work after sending a response
This commit is contained in:
parent
c85b67b0e5
commit
ddb6aa12a5
1 changed files with 41 additions and 23 deletions
|
@ -8,10 +8,20 @@ using ScratchLink.JsonRpc;
|
|||
using System.Net.WebSockets;
|
||||
using System.Text.Json;
|
||||
|
||||
// Helper to send the return value or error resulting from a JSON-RPC method call.
|
||||
// If the error is non-null, the result will be ignored.
|
||||
using ResponseSender = Func<
|
||||
JsonRpc.JsonRpc2Error, // error
|
||||
object, // result (return value) - must be null or JSON-serializable
|
||||
Task // returns `Task` to allow `await`
|
||||
>;
|
||||
|
||||
// Handler for a JSON-RPC method call.
|
||||
using JsonRpcMethodHandler = Func<
|
||||
string, // method name
|
||||
object, // params / args
|
||||
Task<object> // return value - must be JSON-serializable
|
||||
Func<JsonRpc.JsonRpc2Error, object, Task>, // response sender
|
||||
Task // returns `Task` to allow async operations
|
||||
>;
|
||||
|
||||
/// <summary>
|
||||
|
@ -30,10 +40,14 @@ internal class Session
|
|||
/// </summary>
|
||||
protected readonly Dictionary<string, JsonRpcMethodHandler> Handlers = new ();
|
||||
|
||||
/// <summary>
|
||||
/// Long-running method handlers should collect a cancellation token here and check it periodically.
|
||||
/// </summary>
|
||||
protected readonly CancellationTokenSource cancellationTokenSource = new ();
|
||||
|
||||
private const int MessageSizeLimit = 1024 * 1024; // 1 MiB
|
||||
|
||||
private readonly WebSocketContext context;
|
||||
private readonly CancellationTokenSource cancellationTokenSource = new ();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Session"/> class.
|
||||
|
@ -84,43 +98,47 @@ internal class Session
|
|||
/// </summary>
|
||||
/// <param name="methodName">The name of the method called (expected: "getVersion").</param>
|
||||
/// <param name="args">Any arguments passed to the method by the caller (expected: none).</param>
|
||||
/// <returns>A string representing the protocol version.</returns>
|
||||
protected Task<object> HandleGetVersion(string methodName, object args)
|
||||
/// <param name="sendResponse">The method to send the method result.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
protected async Task HandleGetVersion(string methodName, object args, ResponseSender sendResponse)
|
||||
{
|
||||
return Task.FromResult<object>(new Dictionary<string, string>
|
||||
await sendResponse(null, new Dictionary<string, string>
|
||||
{
|
||||
{ "protocol", NetworkProtocolVersion },
|
||||
});
|
||||
}
|
||||
|
||||
private Task<object> HandleUnrecognizedMethod(string methodName, object args)
|
||||
private async Task HandleUnrecognizedMethod(string methodName, object args, ResponseSender sendResponse)
|
||||
{
|
||||
throw new JsonRpc2Exception(JsonRpc2Error.MethodNotFound(methodName));
|
||||
await sendResponse(JsonRpc2Error.MethodNotFound(methodName), null);
|
||||
}
|
||||
|
||||
private async Task HandleRequest(JsonRpc.JsonRpc2Request request, CancellationToken cancellationToken)
|
||||
{
|
||||
var handler = this.Handlers.GetValueOrDefault(request.Method, this.HandleUnrecognizedMethod);
|
||||
|
||||
object result = null;
|
||||
JsonRpc2Error error = null;
|
||||
|
||||
try
|
||||
{
|
||||
result = await handler(request.Method, request.Params);
|
||||
}
|
||||
catch (JsonRpc2Exception e)
|
||||
{
|
||||
error = e.Error;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
error = JsonRpc2Error.ApplicationError($"Unhandled error encountered during call: {e}");
|
||||
}
|
||||
ResponseSender sendResponse;
|
||||
|
||||
if (request.Id is JsonElement requestId)
|
||||
{
|
||||
await this.SendResponse(requestId, result, error, cancellationToken);
|
||||
sendResponse = (err, res) => this.SendResponse(requestId, res, err, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendResponse = (err, res) => Task.CompletedTask;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await handler(request.Method, request.Params, sendResponse);
|
||||
}
|
||||
catch (JsonRpc2Exception e)
|
||||
{
|
||||
await sendResponse(e.Error, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await sendResponse(JsonRpc2Error.ApplicationError($"Unhandled error encountered during call: {e}"), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue