using System.Globalization; using ImageMagick; using Spacebar.AdminApi.TestClient.Services.Helpers; using Spacebar.AdminApi.TestClient.Services.Services; using Spacebar.Cdn.Worker; using Spacebar.Interop.Cdn.Abstractions; var builder = WebApplication.CreateBuilder(args); // var sw = Stopwatch.StartNew(); Console.WriteLine("Pre-initializing Magick.NET..."); // OpenCL.IsEnabled = true; MagickNET.Initialize(); // Console.WriteLine("==> Rendering default avatars..."); // foreach (var (r, g, b) in DefaultAvatarRenderer.DefaultAvatarColors) { // var res = await DefaultAvatarRenderer.GetDefaultAvatar(r, g, b, size: 4096); // Console.WriteLine($" ==> #{r:X2}{g:X2}{b:X2} => {res.Length} bytes"); // res.Position = 0; // await using (var fs = File.OpenWrite($"default-{r:X2}{g:X2}{b:X2}.png")) { // await res.CopyToAsync(fs); // fs.Flush(); // fs.Close(); // } // } // byte skip = 8; // var re = new RainbowEnumerator(lengthFactor: 256, skip: skip); // var reFg = new RainbowEnumerator(lengthFactor: 512, skip: skip, offset: 128); // var magickCollection = new MagickImageCollection(); // for (int i = 0; i < 255; i += skip) { // var sw2 = Stopwatch.StartNew(); // var clr = re.Next(); // var clrFg = reFg.Next(); // var res = await DefaultAvatarRenderer.GetDefaultAvatarImage(clr.r, clr.g, clr.b, clrFg.r, clrFg.g, clrFg.b, size: 512); // Console.Write($" ==> #{clr.r:X2}{clr.g:X2}{clr.b:X2}/{clrFg.r:X2}{clrFg.g:X2}{clrFg.b:X2} ({i} => {magickCollection.Count + 1})... R"); // res.Flatten(); // Console.Write("F"); // res.First().AnimationDelay = 4; // Console.Write("A"); // magickCollection.Add(res.First()); // Console.WriteLine(" => " + sw2.Elapsed); // } // // Console.WriteLine(" ==> Optimizing (1/2)..."); // magickCollection.OptimizePlus(); // Console.WriteLine(" ==> Optimizing (2/2)..."); // magickCollection.OptimizeTransparency(); // Console.WriteLine(" ==> Writing..."); // await using (var fs = File.OpenWrite($"default-animated.gif")) { // await magickCollection.WriteAsync(fs, MagickFormat.Gif); // } // // Console.WriteLine(sw.Elapsed); // Environment.Exit(0); // builder.WebHost.ConfigureKestrel(opts => opts.ListenUnixSocket(Environment.GetEnvironmentVariable("SOCKET_PATH")!)); builder.WebHost.ConfigureKestrel(o => { o.UseSystemd(); // Socket activation if wanted }); builder.Services.AddSingleton(await new FilesystemFileSource(Environment.GetEnvironmentVariable("STORAGE_PATH") ?? throw new InvalidOperationException("STORAGE_PATH not set!")).Init()); builder.Services.AddSingleton(); builder.Services.AddControllers(); var app = builder.Build(); app.MapControllers(); app.MapGet("/embed/avatars/{idx:int}.{ext}", async (HttpContext ctx, int idx, string ext) => { var (r, g, b) = DefaultAvatarRenderer.DefaultAvatarColors[idx % DefaultAvatarRenderer.DefaultAvatarColors.Length]; var res = await DefaultAvatarRenderer.GetDefaultAvatar(r, g, b, size: ctx.Request.Query.ContainsKey("size") ? int.Parse(ctx.Request.Query["size"]!) : 4096, format: Mimes.GetFormatForExtension(ext)); return Results.File(res, Mimes.GetMime(Mimes.GetFormatForExtension(ext))); }); // small easter egg internal stuff, maybe used someday :) app.MapGet("/embed/avatars/_{bg:length(6)}.{ext}", async (HttpContext ctx, string bg, string ext) => { var (r, g, b) = (byte.Parse(bg[..2], NumberStyles.HexNumber), byte.Parse(bg[2..4], NumberStyles.HexNumber), byte.Parse(bg[4..6], NumberStyles.HexNumber)); var res = await DefaultAvatarRenderer.GetDefaultAvatar(r, g, b, size: ctx.Request.Query.ContainsKey("size") ? int.Parse(ctx.Request.Query["size"]!) : 4096, format: Mimes.GetFormatForExtension(ext)); return Results.File(res, Mimes.GetMime(Mimes.GetFormatForExtension(ext))); }); app.MapGet("/embed/avatars/_{bg:length(6)}_{fg:length(6)}.{ext}", async (HttpContext ctx, string bg, string fg, string ext) => { var (r, g, b) = (byte.Parse(bg[..2], NumberStyles.HexNumber), byte.Parse(bg[2..4], NumberStyles.HexNumber), byte.Parse(bg[4..6], NumberStyles.HexNumber)); var (rf, gf, bf) = (byte.Parse(fg[..2], NumberStyles.HexNumber), byte.Parse(fg[2..4], NumberStyles.HexNumber), byte.Parse(fg[4..6], NumberStyles.HexNumber)); var res = await DefaultAvatarRenderer.GetDefaultAvatar(r, g, b, rf, gf, bf, size: ctx.Request.Query.ContainsKey("size") ? int.Parse(ctx.Request.Query["size"]!) : 4096, format: Mimes.GetFormatForExtension(ext)); return Results.File(res, Mimes.GetMime(Mimes.GetFormatForExtension(ext))); }); app.MapGet("/scale/{*path}", async (HttpContext ctx, IFileSource ifs, DiscordImageResizeService dirs, string path) => { var f = await ifs.GetFile(path); f.Stream.Position = 0; var mig = new MagickImageCollection(); await mig.ReadAsync(f.Stream, ctx.RequestAborted); var res = await dirs.Apply(mig, ctx.Request.GetResizeParams()); await ctx.Response.StartAsync(); await res.WriteAsync(ctx.Response.Body); await ctx.Response.CompleteAsync(); }); app.Run();