From 119d525eb5f55523815996d71a2858b6581b16a7 Mon Sep 17 00:00:00 2001 From: Mirko Da Corte Date: Mon, 14 Oct 2024 17:38:54 +0200 Subject: [PATCH] implement chunk handling --- src/BeeTurbo/Handlers/BzzHandler.cs | 24 +++---- src/BeeTurbo/Handlers/ChunksHandler.cs | 72 +++++++++++++++++++ src/BeeTurbo/Handlers/IBzzHandler.cs | 3 +- src/BeeTurbo/Handlers/IChunksHandler.cs | 24 +++++++ src/BeeTurbo/Options/ForwarderOptions.cs | 24 +++++++ src/BeeTurbo/Program.cs | 20 ++++-- ...epositoryChunkStore.cs => DbChunkStore.cs} | 2 +- 7 files changed, 150 insertions(+), 19 deletions(-) create mode 100644 src/BeeTurbo/Handlers/ChunksHandler.cs create mode 100644 src/BeeTurbo/Handlers/IChunksHandler.cs create mode 100644 src/BeeTurbo/Options/ForwarderOptions.cs rename src/BeeTurbo/Tools/{DbRepositoryChunkStore.cs => DbChunkStore.cs} (97%) diff --git a/src/BeeTurbo/Handlers/BzzHandler.cs b/src/BeeTurbo/Handlers/BzzHandler.cs index 96af9ac..08a288e 100644 --- a/src/BeeTurbo/Handlers/BzzHandler.cs +++ b/src/BeeTurbo/Handlers/BzzHandler.cs @@ -15,8 +15,9 @@ using Etherna.BeeNet.Hashing.Store; using Etherna.BeeNet.Manifest; using Etherna.BeeNet.Models; -using Etherna.BeeTurbo.Tools; +using Etherna.BeeTurbo.Options; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; using System.Diagnostics.CodeAnalysis; using System.Net.Http; using System.Threading; @@ -26,15 +27,17 @@ namespace Etherna.BeeTurbo.Handlers { internal sealed class BzzHandler( - DbRepositoryChunkStore chunkStore, - IHttpForwarder forwarder) + IChunkStore chunkStore, + IHttpForwarder forwarder, + IOptions options) : IBzzHandler { + // Fields. + private readonly ForwarderOptions options = options.Value; + + // Methods. [SuppressMessage("Design", "CA1031:Do not catch general exception types")] - public async Task HandleAsync( - HttpContext httpContext, - string address, - string beeUrl) + public async Task HandleAsync(HttpContext httpContext, string address) { if (httpContext.Request.Method == "GET") { @@ -62,17 +65,14 @@ public async Task HandleAsync( return Results.File(dataStream, contentType, fileName); } - // catch (KeyNotFoundException) - catch //proceed with forward on any error - { - } + catch { } //proceed with forward on any error } using var socketsHttpHandler = new SocketsHttpHandler(); using var httpClient = new HttpMessageInvoker(socketsHttpHandler); var error = await forwarder.SendAsync( httpContext, - beeUrl, + options.BeeUrl, httpClient); if (error != ForwarderError.None) diff --git a/src/BeeTurbo/Handlers/ChunksHandler.cs b/src/BeeTurbo/Handlers/ChunksHandler.cs new file mode 100644 index 0000000..c7e225d --- /dev/null +++ b/src/BeeTurbo/Handlers/ChunksHandler.cs @@ -0,0 +1,72 @@ +// Copyright 2024-present Etherna SA +// This file is part of BeeTurbo. +// +// BeeTurbo is free software: you can redistribute it and/or modify it under the terms of the +// GNU Affero General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BeeTurbo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License along with BeeTurbo. +// If not, see . + +using Etherna.BeeNet.Hashing.Store; +using Etherna.BeeNet.Models; +using Etherna.BeeTurbo.Options; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Threading.Tasks; +using Yarp.ReverseProxy.Forwarder; + +namespace Etherna.BeeTurbo.Handlers +{ + internal sealed class ChunksHandler( + IChunkStore chunkStore, + IHttpForwarder forwarder, + IOptions options) + : IChunksHandler + { + // Fields. + private readonly ForwarderOptions options = options.Value; + + // Methods. + [SuppressMessage("Design", "CA1031:Do not catch general exception types")] + public async Task HandleAsync(HttpContext httpContext, string hash) + { + if (httpContext.Request.Method == "GET") + { + try + { + var swarmHash = SwarmHash.FromString(hash); + var chunk = await chunkStore.GetAsync(swarmHash, null); + + return Results.File( + chunk.GetSpanAndData(), + "application/octet-stream", + hash); + } + catch { } //proceed with forward on any error + } + + using var socketsHttpHandler = new SocketsHttpHandler(); + using var httpClient = new HttpMessageInvoker(socketsHttpHandler); + var error = await forwarder.SendAsync( + httpContext, + options.BeeUrl, + httpClient); + + if (error != ForwarderError.None) + { + httpContext.Response.StatusCode = StatusCodes.Status502BadGateway; + await httpContext.Response.WriteAsync("An error occurred while forwarding the request."); + return Results.StatusCode(StatusCodes.Status502BadGateway); + } + + return null!; + } + } +} \ No newline at end of file diff --git a/src/BeeTurbo/Handlers/IBzzHandler.cs b/src/BeeTurbo/Handlers/IBzzHandler.cs index f4b2c8a..7dd08de 100644 --- a/src/BeeTurbo/Handlers/IBzzHandler.cs +++ b/src/BeeTurbo/Handlers/IBzzHandler.cs @@ -21,7 +21,6 @@ namespace Etherna.BeeTurbo.Handlers [SuppressMessage("Design", "CA1054:URI-like parameters should not be strings")] public interface IBzzHandler { - Task HandleAsync(HttpContext httpContext, string address, - string beeUrl); + Task HandleAsync(HttpContext httpContext, string address); } } \ No newline at end of file diff --git a/src/BeeTurbo/Handlers/IChunksHandler.cs b/src/BeeTurbo/Handlers/IChunksHandler.cs new file mode 100644 index 0000000..a7c80af --- /dev/null +++ b/src/BeeTurbo/Handlers/IChunksHandler.cs @@ -0,0 +1,24 @@ +// Copyright 2024-present Etherna SA +// This file is part of BeeTurbo. +// +// BeeTurbo is free software: you can redistribute it and/or modify it under the terms of the +// GNU Affero General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BeeTurbo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License along with BeeTurbo. +// If not, see . + +using Microsoft.AspNetCore.Http; +using System.Threading.Tasks; + +namespace Etherna.BeeTurbo.Handlers +{ + public interface IChunksHandler + { + Task HandleAsync(HttpContext httpContext, string hash); + } +} \ No newline at end of file diff --git a/src/BeeTurbo/Options/ForwarderOptions.cs b/src/BeeTurbo/Options/ForwarderOptions.cs new file mode 100644 index 0000000..62b69f3 --- /dev/null +++ b/src/BeeTurbo/Options/ForwarderOptions.cs @@ -0,0 +1,24 @@ +// Copyright 2024-present Etherna SA +// This file is part of BeeTurbo. +// +// BeeTurbo is free software: you can redistribute it and/or modify it under the terms of the +// GNU Affero General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BeeTurbo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License along with BeeTurbo. +// If not, see . + +using System.Diagnostics.CodeAnalysis; + +namespace Etherna.BeeTurbo.Options +{ + public class ForwarderOptions + { + [SuppressMessage("Design", "CA1056:URI-like properties should not be strings")] + public string BeeUrl { get; set; } = default!; + } +} \ No newline at end of file diff --git a/src/BeeTurbo/Program.cs b/src/BeeTurbo/Program.cs index 92b8d10..0b84588 100644 --- a/src/BeeTurbo/Program.cs +++ b/src/BeeTurbo/Program.cs @@ -13,8 +13,10 @@ // If not, see . using Etherna.BeeNet; +using Etherna.BeeNet.Hashing.Store; using Etherna.BeeTurbo.Domain; using Etherna.BeeTurbo.Handlers; +using Etherna.BeeTurbo.Options; using Etherna.BeeTurbo.Persistence; using Etherna.BeeTurbo.Tools; using Etherna.MongODM; @@ -116,8 +118,15 @@ private static void ConfigureServices(WebApplicationBuilder builder, string beeU services.AddHttpForwarder(); // Add request handlers. - services.AddSingleton(); - services.AddSingleton(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + // Configure options. + services.Configure(options => + { + options.BeeUrl = beeUrl; + }); // Configure persistence. services.AddMongODMWithHangfire(configureHangfireOptions: options => @@ -143,7 +152,7 @@ private static void ConfigureServices(WebApplicationBuilder builder, string beeU // Singleton services. services.AddSingleton(_ => new BeeClient(new Uri(beeUrl, UriKind.Absolute))); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); } [SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")] @@ -157,7 +166,10 @@ private static void ConfigureApplication(WebApplication app, string beeUrl) // Configure endpoint mapping app.Map("/bzz/{*address}", (HttpContext httpContext, string address, IBzzHandler handler) => - handler.HandleAsync(httpContext, address, beeUrl)); + handler.HandleAsync(httpContext, address)); + + app.Map("/chunks/{*hash}", (HttpContext httpContext, string hash, IChunksHandler handler) => + handler.HandleAsync(httpContext, hash)); app.Map("/chunks/stream-turbo", (HttpContext httpContext, IStreamTurboHandler handler) => handler.HandleAsync(httpContext)); diff --git a/src/BeeTurbo/Tools/DbRepositoryChunkStore.cs b/src/BeeTurbo/Tools/DbChunkStore.cs similarity index 97% rename from src/BeeTurbo/Tools/DbRepositoryChunkStore.cs rename to src/BeeTurbo/Tools/DbChunkStore.cs index 442bfc6..5dd7d50 100644 --- a/src/BeeTurbo/Tools/DbRepositoryChunkStore.cs +++ b/src/BeeTurbo/Tools/DbChunkStore.cs @@ -22,7 +22,7 @@ namespace Etherna.BeeTurbo.Tools { [SuppressMessage("Design", "CA1031:Do not catch general exception types")] - internal sealed class DbRepositoryChunkStore( + internal sealed class DbChunkStore( IChunkDbContext dbContext) : IChunkStore {