diff --git a/extra/admin-api/Interop/Spacebar.Interop.Cdn.Abstractions/FilesystemFileSource.cs b/extra/admin-api/Interop/Spacebar.Interop.Cdn.Abstractions/FilesystemFileSource.cs index 8a67dfe..8e0f2e7 100644 --- a/extra/admin-api/Interop/Spacebar.Interop.Cdn.Abstractions/FilesystemFileSource.cs +++ b/extra/admin-api/Interop/Spacebar.Interop.Cdn.Abstractions/FilesystemFileSource.cs @@ -24,6 +24,7 @@ await using var rs = File.OpenRead(GetPathSafe(path)); var ms = new MemoryStream(); await rs.CopyToAsync(ms); + ms.Seek(0, SeekOrigin.Begin); return new() { Stream = ms, MimeType = "MIME/TYPE" diff --git a/extra/admin-api/Interop/Spacebar.Interop.Cdn.Abstractions/LruFileCache.cs b/extra/admin-api/Interop/Spacebar.Interop.Cdn.Abstractions/LruFileCache.cs index 27b5540..23ea6d4 100644 --- a/extra/admin-api/Interop/Spacebar.Interop.Cdn.Abstractions/LruFileCache.cs +++ b/extra/admin-api/Interop/Spacebar.Interop.Cdn.Abstractions/LruFileCache.cs @@ -1,3 +1,5 @@ +using System.Collections.Frozen; +using System.Collections.Immutable; using ArcaneLibs; namespace Spacebar.Interop.Cdn.Abstractions; diff --git a/extra/admin-api/Spacebar.Cdn/Controllers/Internal/GetImageController.cs b/extra/admin-api/Spacebar.Cdn/Controllers/Internal/GetImageController.cs index 3b7df11..38e2717 100644 --- a/extra/admin-api/Spacebar.Cdn/Controllers/Internal/GetImageController.cs +++ b/extra/admin-api/Spacebar.Cdn/Controllers/Internal/GetImageController.cs @@ -1,9 +1,9 @@ +// #if DEBUG // using ArcaneLibs; // using ArcaneLibs.Collections; // using ImageMagick; // using Microsoft.AspNetCore.Mvc; // using Spacebar.AdminApi.TestClient.Services.Services; -// using Spacebar.Cdn.Extensions; // using Spacebar.Interop.Cdn.Abstractions; // // namespace Spacebar.Cdn.Controllers.Internal; @@ -156,7 +156,8 @@ // var img = new MagickImageCollection(); // // var ms = new MemoryStream(); -// +// // return new FileContentResult(ms.ToArray(), "image/gif"); // } -// } \ No newline at end of file +// } +// #endif \ No newline at end of file diff --git a/extra/admin-api/Spacebar.Cdn/Controllers/StaticAssetController.cs b/extra/admin-api/Spacebar.Cdn/Controllers/StaticAssetController.cs index ce64bc4..fcf5a6e 100644 --- a/extra/admin-api/Spacebar.Cdn/Controllers/StaticAssetController.cs +++ b/extra/admin-api/Spacebar.Cdn/Controllers/StaticAssetController.cs @@ -1,6 +1,5 @@ using ArcaneLibs.Extensions.Streams; using Microsoft.AspNetCore.Mvc; -using Microsoft.OpenApi; using Spacebar.AdminApi.TestClient.Services.Services; using Spacebar.Cdn.Extensions; using Spacebar.Cdn.Services; @@ -15,17 +14,15 @@ public async Task GetUserAvatar(string avatarIdx, string ext = "webp") { DiscordImageResizeParams resizeParams = Request.GetResizeParams(); var cacheKey = Request.Path + resizeParams.ToSerializedName(); - LruFileCache.Entry? entry; - entry = await lfc.GetOrAdd(cacheKey, async () => { - - var res = await cws.GetRawClient("q8").GetAsync(Request.Path + Request.QueryString); - var outStream = await res.Content.ReadAsStreamAsync(); + var entry = await lfc.GetOrAdd(cacheKey, async () => { + var res = await cws.GetRawClient("q8").GetAsync(Request.Path + Request.QueryString); + var outStream = await res.Content.ReadAsStreamAsync(); - return new LruFileCache.Entry() { - Data = outStream.ReadToEnd().ToArray(), - MimeType = res.Content.Headers.ContentType?.ToString() ?? Mimes.GetMime(Mimes.GetFormatForExtension(ext)) - }; - }); + return new LruFileCache.Entry() { + Data = outStream.ReadToEnd().ToArray(), + MimeType = res.Content.Headers.ContentType?.ToString() ?? Mimes.GetMime(Mimes.GetFormatForExtension(ext)) + }; + }); return new FileContentResult(entry.Data, entry.MimeType); } diff --git a/extra/admin-api/Spacebar.Cdn/Controllers/UserController.cs b/extra/admin-api/Spacebar.Cdn/Controllers/UserController.cs index eaf8feb..3777f84 100644 --- a/extra/admin-api/Spacebar.Cdn/Controllers/UserController.cs +++ b/extra/admin-api/Spacebar.Cdn/Controllers/UserController.cs @@ -8,12 +8,11 @@ namespace Spacebar.Cdn.Controllers; [ApiController] -public class UserController(LruFileCache lfc, IFileSource fs, CdnWorkerService cws) : ControllerBase { - [HttpGet("/avatars/{userId}/{hash}")] +public class UserController(LruFileCache lfc, IFileSource fs, CdnWorkerService cws) : ImageController(lfc, fs, cws) { + [HttpGet("/avatars/{userId}/{hash}")] // technically an invalid request? [HttpGet("/avatars/{userId}/{hash}.{ext}")] public async Task GetUserAvatar(string userId, string hash, string ext = "webp") { DiscordImageResizeParams resizeParams = Request.GetResizeParams(); - var originalKey = fs.BaseUrl + Request.Path; var cacheKey = Request.Path + resizeParams.ToSerializedName(); LruFileCache.Entry? entry; if (!Request.Query.Any() || resizeParams.Passthrough) { @@ -29,7 +28,7 @@ var res = await cws.GetRawClient("q8").GetAsync("/scale" + Request.Path + Request.QueryString); var outStream = await res.Content.ReadAsStreamAsync(); - return new LruFileCache.Entry() { + return new LruFileCache.Entry { Data = outStream.ReadToEnd().ToArray(), MimeType = res.Content.Headers.ContentType?.ToString() ?? original.MimeType }; diff --git a/extra/admin-api/Spacebar.Cdn/Extensions/HttpRequestExtensions.cs b/extra/admin-api/Spacebar.Cdn/Extensions/HttpRequestExtensions.cs new file mode 100644 index 0000000..f817854 --- /dev/null +++ b/extra/admin-api/Spacebar.Cdn/Extensions/HttpRequestExtensions.cs @@ -0,0 +1,35 @@ +using Microsoft.AspNetCore.Mvc; +using Spacebar.AdminApi.TestClient.Services.Services; + +namespace Spacebar.Cdn.Extensions; + + +public static class HttpRequestExtensions { + extension(HttpRequest request) { + public DiscordImageResizeParams GetResizeParams() { + return new() { + Size = request.Query.ContainsKey("size") && uint.TryParse(request.Query["size"], out uint size) ? size : null, + Quality = request.Query.ContainsKey("quality") && Enum.TryParse(request.Query["quality"], true, out var quality) + ? quality + : DiscordImageResizeQuality.High, + KeepAspectRatio = !request.Query.ContainsKey("keepAspectRatio") || !bool.TryParse(request.Query["keepAspectRatio"], out bool kar) || kar, + Passthrough = request.Query.ContainsKey("passthrough") && bool.TryParse(request.Query["passthrough"], out bool pt) && pt, + Animated = request.Query.ContainsKey("animated") && bool.TryParse(request.Query["animated"], out bool an) && an, + SpacebarAllowUpscale = request.Query.ContainsKey("allowUpscale") && bool.TryParse(request.Query["allowUpscale"], out bool au) && au, + SpacebarOptimiseGif = request.Query.ContainsKey("optimiseGif") && bool.TryParse(request.Query["optimiseGif"], out bool og) && og, + }; + } + } + + extension (HttpResponse response) { + public void SetSuccessCacheHeader() { + int cacheDuration = (int)TimeSpan.FromHours(6).TotalSeconds; + response.Headers.CacheControl = $"public, max-age={cacheDuration}, s-maxage={cacheDuration}, immutable"; + } + + public void SetFailureCacheHeader() { + int cacheDuration = (int)TimeSpan.FromMinutes(5).TotalSeconds; + response.Headers.CacheControl = $"public, max-age={cacheDuration}, s-maxage={cacheDuration}, immutable"; + } + } +} \ No newline at end of file diff --git a/extra/admin-api/Spacebar.Cdn/Extensions/ImageController.cs b/extra/admin-api/Spacebar.Cdn/Extensions/ImageController.cs index f817854..9a70fd0 100644 --- a/extra/admin-api/Spacebar.Cdn/Extensions/ImageController.cs +++ b/extra/admin-api/Spacebar.Cdn/Extensions/ImageController.cs @@ -1,35 +1,33 @@ +using ArcaneLibs.Extensions.Streams; using Microsoft.AspNetCore.Mvc; using Spacebar.AdminApi.TestClient.Services.Services; +using Spacebar.Cdn.Services; +using Spacebar.Interop.Cdn.Abstractions; namespace Spacebar.Cdn.Extensions; +[ApiController] +public class ImageController(LruFileCache lfc, IFileSource fs, CdnWorkerService cws) : ControllerBase { + public async Task GetImage(string path) { + DiscordImageResizeParams resizeParams = Request.GetResizeParams(); + var cacheKey = path + resizeParams.ToSerializedName(); + if (!Request.Query.Any() || resizeParams.Passthrough) { + await using var original = await fs.GetFile(path); + return new FileContentResult(original.Stream.ReadToEnd().ToArray(), original.MimeType); + } -public static class HttpRequestExtensions { - extension(HttpRequest request) { - public DiscordImageResizeParams GetResizeParams() { - return new() { - Size = request.Query.ContainsKey("size") && uint.TryParse(request.Query["size"], out uint size) ? size : null, - Quality = request.Query.ContainsKey("quality") && Enum.TryParse(request.Query["quality"], true, out var quality) - ? quality - : DiscordImageResizeQuality.High, - KeepAspectRatio = !request.Query.ContainsKey("keepAspectRatio") || !bool.TryParse(request.Query["keepAspectRatio"], out bool kar) || kar, - Passthrough = request.Query.ContainsKey("passthrough") && bool.TryParse(request.Query["passthrough"], out bool pt) && pt, - Animated = request.Query.ContainsKey("animated") && bool.TryParse(request.Query["animated"], out bool an) && an, - SpacebarAllowUpscale = request.Query.ContainsKey("allowUpscale") && bool.TryParse(request.Query["allowUpscale"], out bool au) && au, - SpacebarOptimiseGif = request.Query.ContainsKey("optimiseGif") && bool.TryParse(request.Query["optimiseGif"], out bool og) && og, + var entry = await lfc.GetOrAdd(cacheKey, async () => { + var original = await fs.GetFile(path); + var res = await cws.GetRawClient("q8").GetAsync("/scale" + path + Request.QueryString); + var outStream = await res.Content.ReadAsStreamAsync(); + + return new LruFileCache.Entry() { + Data = outStream.ReadToEnd().ToArray(), + MimeType = res.Content.Headers.ContentType?.ToString() ?? original.MimeType }; - } - } - - extension (HttpResponse response) { - public void SetSuccessCacheHeader() { - int cacheDuration = (int)TimeSpan.FromHours(6).TotalSeconds; - response.Headers.CacheControl = $"public, max-age={cacheDuration}, s-maxage={cacheDuration}, immutable"; - } + }); - public void SetFailureCacheHeader() { - int cacheDuration = (int)TimeSpan.FromMinutes(5).TotalSeconds; - response.Headers.CacheControl = $"public, max-age={cacheDuration}, s-maxage={cacheDuration}, immutable"; - } + // byte array with mime type result + return new FileContentResult(entry.Data, entry.MimeType); } } \ No newline at end of file diff --git a/extra/admin-api/Spacebar.Cdn/Services/SpacebarCdnWorkerConfiguration.cs b/extra/admin-api/Spacebar.Cdn/Services/SpacebarCdnWorkerConfiguration.cs index 68e9a30..0d3e102 100644 --- a/extra/admin-api/Spacebar.Cdn/Services/SpacebarCdnWorkerConfiguration.cs +++ b/extra/admin-api/Spacebar.Cdn/Services/SpacebarCdnWorkerConfiguration.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Spacebar.Cdn.Services; @@ -7,12 +7,12 @@ config.GetRequiredSection("Spacebar").GetRequiredSection("Cdn").GetRequiredSection("Workers").Bind(this); } - [JsonProperty("q8")] + [JsonPropertyName("q8")] public List Q8Workers { get; set; } = []; - [JsonProperty("q16")] + [JsonPropertyName("q16")] public List Q16Workers { get; set; } = []; - [JsonProperty("q16-hdri")] + [JsonPropertyName("q16-hdri")] public List Q16HdriWorkers { get; set; } = []; } \ No newline at end of file