diff --git a/Components/Layout/NavMenu.razor b/Components/Layout/NavMenu.razor index 33d63a2..c37a619 100644 --- a/Components/Layout/NavMenu.razor +++ b/Components/Layout/NavMenu.razor @@ -6,7 +6,7 @@ Weather Test - Storage + diff --git a/Components/Pages/Storage.razor b/Components/Pages/Storage.razor deleted file mode 100644 index e2e64a5..0000000 --- a/Components/Pages/Storage.razor +++ /dev/null @@ -1,116 +0,0 @@ - -@page "/storage" -@inject HttpClient Http -@using System.Net.Http.Json -@using Pldpro.Web.Models - -Storage - -S3 Storage - - - - Buckets - - - Erstellen - - - - @if (buckets is null) - { - (lädt...) - } - else if (!buckets.Any()) - { - (keine Buckets) - } - else - { - @foreach (var b in buckets) - { - - - @b.Name - - } - } - - - -@if (!string.IsNullOrEmpty(selectedBucket)) -{ - - - Objekte in '@selectedBucket' - - - - - - - Key - Größe - Geändert - - - @context.Key - @context.Size - @context.LastModified - - - -} - -@code { - private record BucketVm(string Name, DateTime? CreationDate); - private record ObjectVm(string Key, long? Size, DateTime? LastModified); - - private List? buckets; - private List? objects; - private string? selectedBucket; - private string newBucketName = ""; - private const long StreamLimit = 512L * 1024 * 1024; // 512 MB (Program.cs erhöht Multipart-Limit) - - protected override async Task OnInitializedAsync() - => await LoadBuckets(); - - private async Task LoadBuckets() - { - var data = await Http.GetFromJsonAsync>("/api/storage/buckets"); - buckets = data ?? new(); - StateHasChanged(); - } - - private async Task SelectBucket(string name) - { - selectedBucket = name; - objects = await Http.GetFromJsonAsync>($"/api/storage/buckets/{name}/objects") ?? new(); - } - - private async Task CreateBucket() - { - if (string.IsNullOrWhiteSpace(newBucketName)) return; - await Http.PostAsJsonAsync("/api/storage/buckets", new S3CreateBucketDto { BucketName = newBucketName! }); - newBucketName = ""; - await LoadBuckets(); - } - - private async Task OnFilesSelected(InputFileChangeEventArgs e) - { - if (string.IsNullOrEmpty(selectedBucket)) return; - - foreach (var file in e.GetMultipleFiles()) - { - using var stream = file.OpenReadStream(StreamLimit); - using var content = new MultipartFormDataContent(); - content.Add(new StreamContent(stream), "file", file.Name); - - var resp = await Http.PostAsync($"/api/storage/buckets/{selectedBucket}/upload", content); - resp.EnsureSuccessStatusCode(); - } - // Refresh list - objects = await Http.GetFromJsonAsync>($"/api/storage/buckets/{selectedBucket}/objects") ?? new(); - } -} diff --git a/Components/_Imports.razor b/Components/_Imports.razor index 38ad5b7..8fdb8b6 100644 --- a/Components/_Imports.razor +++ b/Components/_Imports.razor @@ -10,4 +10,3 @@ @using MudBlazor.Services @using Pldpro.Web @using Pldpro.Web.Components -@using Amazon.S3 \ No newline at end of file diff --git a/Models/S3Settings.cs b/Models/S3Settings.cs deleted file mode 100644 index 0362d49..0000000 --- a/Models/S3Settings.cs +++ /dev/null @@ -1,12 +0,0 @@ - -namespace Pldpro.Web.Models; - -public sealed class S3Settings -{ - public string ServiceURL { get; set; } = string.Empty; - public string AccessKey { get; set; } = string.Empty; - public string SecretKey { get; set; } = string.Empty; - public bool UseHttp { get; set; } = true; - public bool ForcePathStyle { get; set; } = true; - public string? DefaultBucketPrefix { get; set; } -} diff --git a/Pldpro.Web.csproj b/Pldpro.Web.csproj index 039cf14..20b9f68 100644 --- a/Pldpro.Web.csproj +++ b/Pldpro.Web.csproj @@ -1,4 +1,4 @@ - + net10.0 @@ -8,8 +8,6 @@ - - diff --git a/Program.cs b/Program.cs index 963b664..092c59c 100644 --- a/Program.cs +++ b/Program.cs @@ -1,17 +1,5 @@ -using Amazon.Runtime; -using Amazon.S3; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.Extensions.Options; using MudBlazor.Services; using Pldpro.Web.Components; -using Pldpro.Web.Components.Pages; -using Pldpro.Web.Models; -using Pldpro.Web.Services; -using System.Net.NetworkInformation; -using System.Runtime.Intrinsics.Arm; -using static MudBlazor.CategoryTypes; -using static MudBlazor.Colors; - var builder = WebApplication.CreateBuilder(args); @@ -22,32 +10,6 @@ builder.Services.AddMudServices(); builder.Services.AddRazorComponents() .AddInteractiveServerComponents(); - -// --- S3 / RustFS Settings binding --- -builder.Services.Configure(builder.Configuration.GetSection("S3")); - -// Optional: größere Uploads erlauben (z. B. 512MB) -builder.Services.Configure(o => { o.MultipartBodyLengthLimit = 512L * 1024 * 1024; }); - -// IAmazonS3 via DI (lokaler S3-kompatibler Endpoint) -builder.Services.AddSingleton(sp => -{ - var s = sp.GetRequiredService>().Value; - var cfg = new Amazon.S3.AmazonS3Config - { - ServiceURL = s.ServiceURL, - ForcePathStyle = s.ForcePathStyle, - UseHttp = s.UseHttp - // AuthenticationRegion ist bei Custom-S3 i. d. R. egal - } - ; - var creds = new BasicAWSCredentials(s.AccessKey, s.SecretKey); - return new AmazonS3Client(creds, cfg); - }); - -// Domain-Service -builder.Services.AddScoped(); - var app = builder.Build(); // Configure the HTTP request pipeline. @@ -67,45 +29,4 @@ app.MapStaticAssets(); app.MapRazorComponents() .AddInteractiveServerRenderMode(); - -// --- Minimal APIs für Storage --- -var storage = app.MapGroup("/api/storage"); - -// Buckets auflisten -storage.MapGet("/buckets", async (IStorageService svc) => -{ - var result = await svc.ListBucketsAsync(); - return Results.Ok(result); - }); - -// Bucket erstellen -storage.MapPost("/buckets", async (IStorageService svc, S3CreateBucketDto dto) => -{ - if (string.IsNullOrWhiteSpace(dto.BucketName)) return Results.BadRequest("BucketName required"); - await svc.CreateBucketAsync(dto.BucketName); - return Results.Ok(); - }).DisableAntiforgery(); // für XHR-POST ohne Token - -// Objekte eines Buckets auflisten -storage.MapGet("/buckets/{bucket}/objects", async (IStorageService svc, string bucket) => -{ - var objects = await svc.ListObjectsAsync(bucket); - return Results.Ok(objects); - }); - -// Datei in Bucket hochladen (Form-Data: file) -storage.MapPost("/buckets/{bucket}/upload", async (HttpRequest req, IStorageService svc, string bucket) => -{ - if (!req.HasFormContentType) return Results.BadRequest("Multipart/form-data expected"); - var form = await req.ReadFormAsync(); - var file = form.Files["file"]; - if (file is null) return Results.BadRequest("'file' missing"); - - await using var stream = file.OpenReadStream(); // Streamlimit über FormOptions konfiguriert - await svc.UploadObjectAsync(bucket, file.FileName, stream, file.ContentType ?? "application/octet-stream"); - return Results.Ok(); - }).DisableAntiforgery(); // für Blazor XHR Upload - - - app.Run(); diff --git a/Program.txt b/Program.txt deleted file mode 100644 index 4175989..0000000 Binary files a/Program.txt and /dev/null differ diff --git a/Services/IStorageService.cs b/Services/IStorageService.cs deleted file mode 100644 index 8640212..0000000 --- a/Services/IStorageService.cs +++ /dev/null @@ -1,12 +0,0 @@ - -using Pldpro.Web.Services.Models; - -namespace Pldpro.Web.Services; - -public interface IStorageService -{ - Task> ListBucketsAsync(CancellationToken ct = default); - Task CreateBucketAsync(string bucketName, CancellationToken ct = default); - Task> ListObjectsAsync(string bucket, CancellationToken ct = default); - Task UploadObjectAsync(string bucket, string key, Stream content, string contentType, CancellationToken ct = default); -} diff --git a/Services/Models/BucketItem.cs b/Services/Models/BucketItem.cs deleted file mode 100644 index 3521aaf..0000000 --- a/Services/Models/BucketItem.cs +++ /dev/null @@ -1,4 +0,0 @@ - -namespace Pldpro.Web.Services.Models; - -public sealed record BucketItem(string Name, DateTime? CreationDate); diff --git a/Services/Models/ObjectItem.cs b/Services/Models/ObjectItem.cs deleted file mode 100644 index 50b3981..0000000 --- a/Services/Models/ObjectItem.cs +++ /dev/null @@ -1,4 +0,0 @@ - -namespace Pldpro.Web.Services.Models; - -public sealed record ObjectItem(string Key, long? Size, DateTime? LastModified); diff --git a/Services/Models/S3CreateBucketDto.cs b/Services/Models/S3CreateBucketDto.cs deleted file mode 100644 index d83e30c..0000000 --- a/Services/Models/S3CreateBucketDto.cs +++ /dev/null @@ -1,7 +0,0 @@ - -namespace Pldpro.Web.Models; - -public sealed class S3CreateBucketDto -{ - public string BucketName { get; set; } = string.Empty; -} diff --git a/Services/S3StorageService.cs b/Services/S3StorageService.cs deleted file mode 100644 index dc27365..0000000 --- a/Services/S3StorageService.cs +++ /dev/null @@ -1,55 +0,0 @@ - -using Amazon.S3; -using Amazon.S3.Model; -using Pldpro.Web.Services.Models; - -namespace Pldpro.Web.Services; - -public sealed class S3StorageService(IAmazonS3 s3) : IStorageService -{ - private readonly IAmazonS3 _s3 = s3; - - public async Task> ListBucketsAsync(CancellationToken ct = default) - { - var resp = await _s3.ListBucketsAsync(ct); - return resp.Buckets.Select(b => new BucketItem(b.BucketName, b.CreationDate)); - } - - public async Task CreateBucketAsync(string bucketName, CancellationToken ct = default) - { - // Für S3-kompatible Endpoints reicht häufig nur der Name - var req = new PutBucketRequest { BucketName = bucketName }; - await _s3.PutBucketAsync(req, ct); - } - - public async Task> ListObjectsAsync(string bucket, CancellationToken ct = default) - { - var items = new List(); - string? token = null; - do - { - var resp = await _s3.ListObjectsV2Async(new ListObjectsV2Request - { - BucketName = bucket, - ContinuationToken = token - }, ct); - - items.AddRange(resp.S3Objects.Select(o => new ObjectItem(o.Key, o.Size, o.LastModified))); - token = resp.IsTruncated ? resp.NextContinuationToken : null; - } while (token is not null); - - return items; - } - - public async Task UploadObjectAsync(string bucket, string key, Stream content, string contentType, CancellationToken ct = default) - { - var req = new PutObjectRequest - { - BucketName = bucket, - Key = key, - InputStream = content, - ContentType = contentType - }; - await _s3.PutObjectAsync(req, ct); - } -} diff --git a/appsettings.json b/appsettings.json index 9c1866e..10f68b8 100644 --- a/appsettings.json +++ b/appsettings.json @@ -5,14 +5,5 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*", - "S3": { - "ServiceURL": "http://192.168.1.102:9000", - "AccessKey": "your-access-key", - "SecretKey": "your-secret-key", - "UseHttp": true, - "ForcePathStyle": true, - "DefaultBucketPrefix": "pld-" // optional - } - + "AllowedHosts": "*" }