/// <param name="compressor">Component that compresses Rpc responses</param> /// <param name="logger">Component that logs actions from the router</param> /// <param name="routeProvider">Provider that allows the retrieval of all configured routes</param> public RpcRouter(ILogger <RpcRouter> logger, IRpcCompressor compressor, IRpcRouteProvider routeProvider, IRpcRequestHandler routeHandler) { this.logger = logger; this.compressor = compressor ?? throw new ArgumentNullException(nameof(compressor)); this.routeProvider = routeProvider ?? throw new ArgumentNullException(nameof(routeProvider)); this.routeHandler = routeHandler ?? throw new ArgumentNullException(nameof(routeHandler)); }
public RpcRequestChannelMessageHandler( IRpcRequestHandler rpcRequestHandler, IRpcMessageEncoder messageEncoder, IRpcMessageWriter rpcMessageWriter) { m_RpcRequestHandler = rpcRequestHandler; m_MessageEncoder = messageEncoder; m_RpcMessageWriter = rpcMessageWriter; }
/// <summary> /// Takes a route/http contexts and attempts to parse, invoke, respond to an Rpc request /// </summary> /// <param name="context">Route context</param> /// <returns>Task for async routing</returns> public async Task RouteAsync(RouteContext context) { ILogger <RpcHttpRouter> logger = context.HttpContext.RequestServices.GetService <ILogger <RpcHttpRouter> >(); try { RpcPath?requestPath; if (!context.HttpContext.Request.Path.HasValue) { requestPath = null; } else { if (!RpcPath.TryParse(context.HttpContext.Request.Path.Value.AsSpan(), out requestPath)) { logger?.LogInformation($"Could not parse the path '{context.HttpContext.Request.Path.Value}' for the " + $"request into an rpc path. Skipping rpc router middleware."); return; } } logger?.LogInformation($"Rpc request with route '{requestPath}' started."); IRpcRequestHandler requestHandler = context.HttpContext.RequestServices.GetRequiredService <IRpcRequestHandler>(); var routeContext = DefaultRpcContext.Build(context.HttpContext.RequestServices, requestPath); context.HttpContext.RequestServices.GetRequiredService <IRpcContextAccessor>().Value = routeContext; Stream writableStream = this.BuildWritableResponseStream(context.HttpContext); using (var requestBody = new MemoryStream()) { await context.HttpContext.Request.Body.CopyToAsync(requestBody); requestBody.Position = 0; bool hasResponse = await requestHandler.HandleRequestAsync(requestBody, writableStream); if (!hasResponse) { //No response required, but status code must be 204 context.HttpContext.Response.StatusCode = 204; context.MarkAsHandled(); return; } } context.MarkAsHandled(); logger?.LogInformation("Rpc request complete"); } catch (Exception ex) { string errorMessage = "Unknown exception occurred when trying to process Rpc request. Marking route unhandled"; logger?.LogException(ex, errorMessage); context.MarkAsHandled(); } }
public static async Task HandleJsonRpcWebSocketRequest(this WebSocket webSocket, HttpContext context, IRpcRequestHandler rpcRequestHandler, IRpcRouteProvider rpcRouteProvider) { byte[] buffer = new byte[1024 * 4]; IRouteContext routeContext = DefaultRouteContext.FromHttpContext(context, rpcRouteProvider); while (webSocket.State == WebSocketState.Open) { WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment <byte>(buffer), CancellationToken.None); if (result.MessageType != WebSocketMessageType.Text) { continue; } string requestBody = Encoding.ASCII.GetString(buffer); string response = await rpcRequestHandler.HandleRequestAsync(RpcPath.Parse(context.Request.Path), requestBody, routeContext); await webSocket.SendAsync( new ArraySegment <byte>(Encoding.ASCII.GetBytes(response), 0, response.Length), WebSocketMessageType.Text, true, CancellationToken.None ); } }
/// <summary> /// Takes a route/http contexts and attempts to parse, invoke, respond to an Rpc request /// </summary> /// <param name="context">Route context</param> /// <returns>Task for async routing</returns> public async Task RouteAsync(RouteContext context) { ILogger <RpcHttpRouter> logger = context.HttpContext.RequestServices.GetService <ILogger <RpcHttpRouter> >(); try { RpcPath requestPath; if (!context.HttpContext.Request.Path.HasValue) { requestPath = RpcPath.Default; } else { if (!RpcPath.TryParse(context.HttpContext.Request.Path.Value, out requestPath)) { logger?.LogInformation($"Could not parse the path '{context.HttpContext.Request.Path.Value}' for the " + $"request into an rpc path. Skipping rpc router middleware."); return; } } if (!requestPath.TryRemoveBasePath(this.routeProvider.BaseRequestPath, out requestPath)) { logger?.LogTrace("Request did not match the base request path. Skipping rpc router."); return; } logger?.LogInformation($"Rpc request with route '{requestPath}' started."); string jsonString; if (context.HttpContext.Request.Body == null) { jsonString = null; } else { using (StreamReader streamReader = new StreamReader(context.HttpContext.Request.Body, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { try { jsonString = await streamReader.ReadToEndAsync(); } catch (TaskCanceledException ex) { throw new RpcCanceledRequestException("Cancelled while reading the request.", ex); } jsonString = jsonString.Trim(); } } IRpcRequestHandler requestHandler = context.HttpContext.RequestServices.GetRequiredService <IRpcRequestHandler>(); var routeContext = DefaultRouteContext.FromHttpContext(context.HttpContext, this.routeProvider); string responseJson = await requestHandler.HandleRequestAsync(requestPath, jsonString, routeContext); if (responseJson == null) { //No response required, but status code must be 204 context.HttpContext.Response.StatusCode = 204; context.MarkAsHandled(); return; } context.HttpContext.Response.ContentType = "application/json"; bool responseSet = false; string acceptEncoding = context.HttpContext.Request.Headers["Accept-Encoding"]; if (!string.IsNullOrWhiteSpace(acceptEncoding)) { IStreamCompressor compressor = context.HttpContext.RequestServices.GetService <IStreamCompressor>(); if (compressor != null) { string[] encodings = acceptEncoding.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); foreach (string encoding in encodings) { bool haveType = Enum.TryParse(encoding, true, out CompressionType compressionType); if (!haveType) { continue; } context.HttpContext.Response.Headers.Add("Content-Encoding", new[] { encoding }); using (Stream responseStream = new MemoryStream(Encoding.UTF8.GetBytes(responseJson))) { compressor.Compress(responseStream, context.HttpContext.Response.Body, compressionType); } responseSet = true; break; } } } if (!responseSet) { await context.HttpContext.Response.WriteAsync(responseJson); } context.MarkAsHandled(); logger?.LogInformation("Rpc request complete"); } catch (Exception ex) { string errorMessage = "Unknown exception occurred when trying to process Rpc request. Marking route unhandled"; logger?.LogException(ex, errorMessage); context.MarkAsHandled(); } }