private ProcessSchedulerDelegate BuildNotificationDelegate(IRequestDescriptor <IHandlerDescriptor?> descriptors, Notification notification) { return(async(cancellationToken) => { using var timeoutCts = new CancellationTokenSource(_requestTimeout); using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, cancellationToken); using var timer = _logger.TimeDebug("Processing notification {Method}", notification.Method); try { await _requestRouter.RouteNotification(descriptors, notification, combinedCts.Token).ConfigureAwait(false); } catch (OperationCanceledException) { if (timeoutCts.IsCancellationRequested) { _logger.LogTrace("Notification {Method} was cancelled due to timeout", notification.Method); return; } _logger.LogTrace("Notification {Method} was cancelled", notification.Method); } catch (Exception e) { _logger.LogCritical(Events.UnhandledRequest, e, "Failed to handle notification {Method}", notification.Method); } }); }
private void HandleRequest(string request) { JToken payload; try { payload = JToken.Parse(request); } catch { _outputHandler.Send(new ParseError()); return; } if (!_receiver.IsValid(payload)) { _outputHandler.Send(new InvalidRequest()); return; } var(requests, hasResponse) = _receiver.GetRequests(payload); if (hasResponse) { foreach (var response in requests.Where(x => x.IsResponse).Select(x => x.Response)) { var id = response.Id is string s?long.Parse(s) : response.Id is long l ? l : -1; if (id < 0) { continue; } var tcs = _responseRouter.GetRequest(id); if (tcs is null) { continue; } if (response is ServerResponse serverResponse) { tcs.SetResult(serverResponse.Result); } else if (response is ServerError serverError) { tcs.SetException(new JsonRpcException(serverError)); } } return; } foreach (var item in requests) { if (item.IsRequest) { var descriptor = _requestRouter.GetDescriptor(item.Request); if (descriptor is null) { continue; } var type = _requestProcessIdentifier.Identify(descriptor); _requestRouter.StartRequest(item.Request.Id); _scheduler.Add( type, item.Request.Method, async() => { try { var result = await _requestRouter.RouteRequest(descriptor, item.Request, CancellationToken.None); if (result.IsError && result.Error is RequestCancelled) { return; } _outputHandler.Send(result.Value); } catch (Exception e) { _logger.LogCritical(Events.UnhandledRequest, e, "Unhandled exception executing request {Method}@{Id}", item.Request.Method, item.Request.Id); // TODO: Should we rethrow or swallow? // If an exception happens... the whole system could be in a bad state, hence this throwing currently. throw; } } ); } if (item.IsNotification) { var descriptor = _requestRouter.GetDescriptor(item.Notification); if (descriptor is null) { continue; } // We need to special case cancellation so that we can cancel any request that is currently in flight. if (descriptor.Method == JsonRpcNames.CancelRequest) { var cancelParams = item.Notification.Params?.ToObject <CancelParams>(); if (cancelParams == null) { continue; } _requestRouter.CancelRequest(cancelParams.Id); continue; } var type = _requestProcessIdentifier.Identify(descriptor); _scheduler.Add( type, item.Notification.Method, DoNotification(descriptor, item.Notification) ); } if (item.IsError) { // TODO: _outputHandler.Send(item.Error); } } Func <Task> DoNotification(IHandlerDescriptor descriptor, Notification notification) { return(async() => { try { await _requestRouter.RouteNotification(descriptor, notification, CancellationToken.None); } catch (Exception e) { _logger.LogCritical(Events.UnhandledNotification, e, "Unhandled exception executing notification {Method}", notification.Method); // TODO: Should we rethrow or swallow? // If an exception happens... the whole system could be in a bad state, hence this throwing currently. throw; } }); } }
private void HandleRequest(string request) { JToken payload; try { payload = JToken.Parse(request); } catch { _outputHandler.Send(new ParseError()); return; } if (!_reciever.IsValid(payload)) { _outputHandler.Send(new InvalidRequest()); return; } var(requests, hasResponse) = _reciever.GetRequests(payload); if (hasResponse) { foreach (var response in requests.Where(x => x.IsResponse).Select(x => x.Response)) { var id = response.Id is string s?long.Parse(s) : response.Id is long l ? l : -1; if (id < 0) { continue; } var tcs = _responseRouter.GetRequest(id); if (tcs is null) { continue; } if (response is ServerResponse serverResponse) { tcs.SetResult(serverResponse.Result); } else if (response is ServerError serverError) { tcs.SetException(new Exception(JsonConvert.SerializeObject(serverError.Error))); } } return; } foreach (var item in requests) { if (item.IsRequest) { var descriptor = _requestRouter.GetDescriptor(item.Request); if (descriptor is null) { continue; } var type = _requestProcessIdentifier.Identify(descriptor); _scheduler.Add( type, item.Request.Method, async() => { try { var result = await _requestRouter.RouteRequest(descriptor, item.Request); _outputHandler.Send(result.Value); } catch (Exception e) { _logger.LogCritical(Events.UnhandledRequest, e, "Unhandled exception executing request {Method}@{Id}", item.Request.Method, item.Request.Id); // TODO: Should we rethrow or swallow? // If an exception happens... the whole system could be in a bad state, hence this throwing currently. throw; } } ); } else if (item.IsNotification) { var descriptor = _requestRouter.GetDescriptor(item.Notification); if (descriptor is null) { continue; } var type = _requestProcessIdentifier.Identify(descriptor); _scheduler.Add( type, item.Notification.Method, async() => { try { await _requestRouter.RouteNotification(descriptor, item.Notification); } catch (Exception e) { _logger.LogCritical(Events.UnhandledNotification, e, "Unhandled exception executing notification {Method}", item.Notification.Method); // TODO: Should we rethrow or swallow? // If an exception happens... the whole system could be in a bad state, hence this throwing currently. throw; } } ); } else if (item.IsError) { // TODO: _outputHandler.Send(item.Error); } } }