public Task Init(INethermindApi api) { _api = api; _healthChecksConfig = _api.Config <IHealthChecksConfig>(); return(Task.CompletedTask); }
public Task Init(INethermindApi api) { _api = api; _healthChecksConfig = _api.Config <IHealthChecksConfig>(); _jsonRpcConfig = _api.Config <IJsonRpcConfig>(); _logger = api.LogManager.GetClassLogger(); return(Task.CompletedTask); }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IJsonRpcProcessor jsonRpcProcessor, IJsonRpcService jsonRpcService, IJsonRpcLocalStats jsonRpcLocalStats, IJsonSerializer jsonSerializer) { long SerializeTimeoutException(IJsonRpcService service, Stream resultStream) { JsonRpcErrorResponse?error = service.GetErrorResponse(ErrorCodes.Timeout, "Request was canceled due to enabled timeout."); return(jsonSerializer.Serialize(resultStream, error)); } if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseCors("Cors"); app.UseRouting(); app.UseResponseCompression(); IConfigProvider? configProvider = app.ApplicationServices.GetService <IConfigProvider>(); IRpcAuthentication?rpcAuthentication = app.ApplicationServices.GetService <IRpcAuthentication>(); if (configProvider == null) { throw new ApplicationException($"{nameof(IConfigProvider)} has not been loaded properly"); } ILogManager? logManager = app.ApplicationServices.GetService <ILogManager>() ?? NullLogManager.Instance; ILogger logger = logManager.GetClassLogger(); IInitConfig initConfig = configProvider.GetConfig <IInitConfig>(); IJsonRpcConfig jsonRpcConfig = configProvider.GetConfig <IJsonRpcConfig>(); IJsonRpcUrlCollection jsonRpcUrlCollection = app.ApplicationServices.GetRequiredService <IJsonRpcUrlCollection>(); IHealthChecksConfig healthChecksConfig = configProvider.GetConfig <IHealthChecksConfig>(); if (initConfig.WebSocketsEnabled) { app.UseWebSockets(new WebSocketOptions()); app.UseWhen(ctx => ctx.WebSockets.IsWebSocketRequest && jsonRpcUrlCollection.TryGetValue(ctx.Connection.LocalPort, out JsonRpcUrl jsonRpcUrl) && jsonRpcUrl.RpcEndpoint.HasFlag(RpcEndpoint.Ws), builder => builder.UseWebSocketsModules()); } app.UseEndpoints(endpoints => { if (healthChecksConfig.Enabled) { try { endpoints.MapHealthChecks(healthChecksConfig.Slug, new HealthCheckOptions() { Predicate = _ => true, ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); if (healthChecksConfig.UIEnabled) { endpoints.MapHealthChecksUI(setup => setup.AddCustomStylesheet(Path.Combine(AppDomain.CurrentDomain.BaseDirectory !, "nethermind.css"))); } } catch (Exception e) { if (logger.IsError) { logger.Error("Unable to initialize health checks. Check if you have Nethermind.HealthChecks.dll in your plugins folder.", e); } } } }); app.Run(async(ctx) => { if (ctx.Request.Method == "GET") { await ctx.Response.WriteAsync("Nethermind JSON RPC"); } if (ctx.Request.Method == "POST" && jsonRpcUrlCollection.TryGetValue(ctx.Connection.LocalPort, out JsonRpcUrl jsonRpcUrl) && jsonRpcUrl.RpcEndpoint.HasFlag(RpcEndpoint.Http)) { if (jsonRpcUrl.IsAuthenticated && !rpcAuthentication !.Authenticate(ctx.Request.Headers["Authorization"])) { var response = jsonRpcService.GetErrorResponse(ErrorCodes.ParseError, "Authentication error"); ctx.Response.ContentType = "application/json"; ctx.Response.StatusCode = StatusCodes.Status200OK; jsonSerializer.Serialize(ctx.Response.Body, response); await ctx.Response.CompleteAsync(); return; } Stopwatch stopwatch = Stopwatch.StartNew(); using CountingTextReader request = new(new StreamReader(ctx.Request.Body, Encoding.UTF8)); try { await foreach (JsonRpcResult result in jsonRpcProcessor.ProcessAsync(request, JsonRpcContext.Http(jsonRpcUrl))) { using (result) { Stream resultStream = jsonRpcConfig.BufferResponses ? new MemoryStream() : ctx.Response.Body; long responseSize; try { ctx.Response.ContentType = "application/json"; ctx.Response.StatusCode = GetStatusCode(result); responseSize = result.IsCollection ? jsonSerializer.Serialize(resultStream, result.Responses) : jsonSerializer.Serialize(resultStream, result.Response); if (jsonRpcConfig.BufferResponses) { ctx.Response.ContentLength = responseSize = resultStream.Length; resultStream.Seek(0, SeekOrigin.Begin); await resultStream.CopyToAsync(ctx.Response.Body); } } catch (Exception e) when(e.InnerException is OperationCanceledException) { responseSize = SerializeTimeoutException(jsonRpcService, resultStream); } catch (OperationCanceledException) { responseSize = SerializeTimeoutException(jsonRpcService, resultStream); } finally { await ctx.Response.CompleteAsync(); if (jsonRpcConfig.BufferResponses) { await resultStream.DisposeAsync(); } } long handlingTimeMicroseconds = stopwatch.ElapsedMicroseconds(); if (result.IsCollection) { jsonRpcLocalStats.ReportCalls(result.Reports); jsonRpcLocalStats.ReportCall(new RpcReport("# collection serialization #", handlingTimeMicroseconds, true), handlingTimeMicroseconds, responseSize); } else { jsonRpcLocalStats.ReportCall(result.Report, handlingTimeMicroseconds, responseSize); } Interlocked.Add(ref Metrics.JsonRpcBytesSentHttp, responseSize); } // There should be only one response because we don't expect multiple JSON tokens in the request break; } } catch (Microsoft.AspNetCore.Http.BadHttpRequestException e) { if (logger.IsDebug) { logger.Debug($"Couldn't read request.{Environment.NewLine}{e}"); } } finally { Interlocked.Add(ref Metrics.JsonRpcBytesReceivedHttp, ctx.Request.ContentLength ?? request.Length); } } }); }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IJsonRpcProcessor jsonRpcProcessor, IJsonRpcService jsonRpcService, IJsonRpcLocalStats jsonRpcLocalStats) { void SerializeTimeoutException(IJsonRpcService service, Stream resultStream) { JsonRpcErrorResponse?error = service.GetErrorResponse(ErrorCodes.Timeout, "Request was canceled due to enabled timeout."); _jsonSerializer.Serialize(resultStream, error); } _jsonSerializer = CreateJsonSerializer(); foreach (JsonConverter converter in jsonRpcService.Converters) { _jsonSerializer.RegisterConverter(converter); } if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseCors("Cors"); app.UseRouting(); IConfigProvider configProvider = app.ApplicationServices.GetService <IConfigProvider>(); IInitConfig initConfig = configProvider.GetConfig <IInitConfig>(); IJsonRpcConfig jsonRpcConfig = configProvider.GetConfig <IJsonRpcConfig>(); IHealthChecksConfig healthChecksConfig = configProvider.GetConfig <IHealthChecksConfig>(); if (initConfig.WebSocketsEnabled) { app.UseWebSockets(); app.UseWhen(ctx => ctx.WebSockets.IsWebSocketRequest && ctx.Connection.LocalPort == jsonRpcConfig.WebSocketsPort, builder => builder.UseWebSocketsModules()); } app.UseEndpoints(endpoints => { if (healthChecksConfig.Enabled) { endpoints.MapHealthChecks("/health", new HealthCheckOptions() { Predicate = _ => true, ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); if (healthChecksConfig.UIEnabled) { endpoints.MapHealthChecksUI(setup => setup.AddCustomStylesheet(Path.Combine(AppDomain.CurrentDomain.BaseDirectory !, "nethermind.css"))); } } }); app.Use(async(ctx, next) => { if (ctx.Request.Method == "GET") { await ctx.Response.WriteAsync("Nethermind JSON RPC"); } if (ctx.Connection.LocalPort == jsonRpcConfig.Port && ctx.Request.Method == "POST") { Stopwatch stopwatch = Stopwatch.StartNew(); using StreamReader reader = new StreamReader(ctx.Request.Body, Encoding.UTF8); string request = await reader.ReadToEndAsync(); using JsonRpcResult result = await jsonRpcProcessor.ProcessAsync(request); ctx.Response.ContentType = "application/json"; Stream resultStream = jsonRpcConfig.BufferResponses ? new MemoryStream() : ctx.Response.Body; try { if (result.IsCollection) { _jsonSerializer.Serialize(resultStream, result.Responses); } else { _jsonSerializer.Serialize(resultStream, result.Response); } if (jsonRpcConfig.BufferResponses) { ctx.Response.ContentLength = resultStream.Length; resultStream.Seek(0, SeekOrigin.Begin); await resultStream.CopyToAsync(ctx.Response.Body); } } catch (Exception e) when(e.InnerException is OperationCanceledException) { SerializeTimeoutException(jsonRpcService, resultStream); } catch (OperationCanceledException) { SerializeTimeoutException(jsonRpcService, resultStream); } finally { await ctx.Response.CompleteAsync(); if (jsonRpcConfig.BufferResponses) { await resultStream.DisposeAsync(); } } if (result.IsCollection) { jsonRpcLocalStats.ReportCalls(result.Reports); jsonRpcLocalStats.ReportCall(new RpcReport("# collection serialization #", stopwatch.ElapsedMicroseconds(), true)); } else { jsonRpcLocalStats.ReportCall(result.Report, stopwatch.ElapsedMicroseconds()); } } }); }