Exemple #1
0
        private ProcessSchedulerDelegate BuildRequestDelegate(IRequestDescriptor <IHandlerDescriptor?> descriptors, Request request, RequestInvocationHandle handle)
        {
            return(async(cancellationToken) =>
            {
                try
                {
                    var result = await InvokeRequestAsync(cancellationToken).ConfigureAwait(false);

                    _outputHandler.Send(result.Value);
                }
                finally
                {
                    handle.Dispose();
                }
            });

            async Task <ErrorResponse> InvokeRequestAsync(CancellationToken cancellationToken)
            {
                using var timeoutCts  = new CancellationTokenSource(_requestTimeout);
                using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(handle.CancellationTokenSource.Token, timeoutCts.Token, cancellationToken);

                using var timer = _logger.TimeDebug("Processing request {Method}:{Id}", request.Method, request.Id);
                try
                {
                    var result = await _requestRouter.RouteRequest(descriptors, request, combinedCts.Token).ConfigureAwait(false);

                    return(result);
                }
                catch (OperationCanceledException)
                {
                    if (timeoutCts.IsCancellationRequested)
                    {
                        _logger.LogTrace("Request {Method}:{Id} was cancelled, due to timeout", request.Method, request.Id);
                        return(new RequestCancelled(request.Id, request.Method));
                    }

                    _logger.LogTrace("Request {Method}:{Id} was cancelled", request.Method, request.Id);
                    return(new RequestCancelled(request.Id, request.Method));
                }
                catch (RpcErrorException e)
                {
                    _logger.LogCritical(Events.UnhandledRequest, e, "Failed to handle request {Method}:{Id}", request.Method, request.Id);
                    return(new RpcError(
                               request.Id,
                               request.Method,
                               new ErrorMessage(e.Code, e.Message, e.Error)));
                }
                catch (Exception e)
                {
                    _logger.LogCritical(Events.UnhandledRequest, e, "Failed to handle request {Method}:{Id}. Unhandled exception", request.Method, request.Id);
                    return(new InternalError(request.Id, request.Method, e.ToString()));
                }
            }
        }
Exemple #2
0
        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 SchedulerDelegate RouteRequest(
            IRequestDescriptor <IHandlerDescriptor?> descriptor,
            Request request,
            RequestInvocationHandle handle)
        {
            var cts = handle.CancellationTokenSource;

            return((contentModifiedToken, scheduler) =>
                   Observable.Create <ErrorResponse>(
                       observer => {
                // ITS A RACE!
                var sub = Observable.Amb(
                    contentModifiedToken.Select(
                        _ => {
                    _logger.LogTrace(
                        "Request {Id} was abandoned due to content be modified", request.Id
                        );
                    return new ErrorResponse(
                        new ContentModified(request.Id, request.Method)
                        );
                }
                        ),
                    Observable.Timer(_options.RequestTimeout, scheduler).Select(
                        _ => new ErrorResponse(new RequestCancelled(request.Id, request.Method))
                        ),
                    Observable.FromAsync(
                        async ct => {
                    using var timer = _logger.TimeDebug(
                              "Processing request {Method} {ResponseId}", request.Method,
                              request.Id
                              );
                    ct.Register(cts.Cancel);
                    // ObservableToToken(contentModifiedToken).Register(cts.Cancel);
                    try
                    {
                        var result = await _requestRouter.RouteRequest(
                            descriptor, request, cts.Token
                            ).ConfigureAwait(false);
                        return result;
                    }
                    catch (OperationCanceledException)
                    {
                        _logger.LogTrace("Request {Id} was cancelled", request.Id);
                        return new RequestCancelled(request.Id, request.Method);
                    }
                    catch (RpcErrorException e)
                    {
                        _logger.LogCritical(
                            Events.UnhandledRequest, e,
                            "Failed to handle request {Method} {RequestId}", request.Method,
                            request.Id
                            );
                        return new RpcError(
                            request.Id, request.Method,
                            new ErrorMessage(e.Code, e.Message, e.Error)
                            );
                    }
                    catch (Exception e)
                    {
                        _logger.LogCritical(
                            Events.UnhandledRequest, e,
                            "Failed to handle request {Method} {RequestId}", request.Method,
                            request.Id
                            );
                        return new InternalError(request.Id, request.Method, e.ToString());
                    }
                }
                        )
                    )
                          .Subscribe(observer);
                return new CompositeDisposable(sub, handle);
            }
                       )
                   .Select(
                       response => {
                _outputHandler.Send(response.Value);
                return Unit.Default;
            }
                       ));
        }
        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);
                }
            }
        }