Skip to content

Commit 829ada2

Browse files
nix/cdn work
1 parent 0784add commit 829ada2

17 files changed

Lines changed: 408 additions & 175 deletions

File tree

.idea/workspace.xml

Lines changed: 62 additions & 43 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extra/admin-api/Spacebar.Cdn/Controllers/GetImageController.cs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,17 @@
77
namespace Spacebar.Cdn.Controllers;
88

99
[ApiController]
10-
public class GetImageController(LruFileCache lfc, IFileSource fs, DiscordImageResizeService dirs) : ControllerBase {
11-
[HttpGet("/avatars/{_:required}")]
10+
public class GetImageController(LruFileCache lfc, IFileSource fs, DiscordImageResizeService dirs) : ImageController {
11+
// [HttpGet("/avatars/{_:required}")]
1212
[HttpGet("/emojis/{emoji_id:required}.{ext:required}")]
1313
[HttpGet("/stickers/{sticker_id:required}.{ext:required}")]
14-
[HttpGet("/avatars/{user_id:required}/{avatar_hash:required}.{ext:required}")]
14+
// [HttpGet("/avatars/{user_id:required}/{avatar_hash:required}.{ext:required}")]
1515
[HttpGet("/banners/{user_id:required}/{user_banner:required}.{ext:required}")]
1616
public async Task<IActionResult> GetImage(string? ext) {
1717
var originalKey = fs.BaseUrl + Request.Path;
1818
var cacheKey = Request.Path + Request.QueryString;
19-
20-
DiscordImageResizeParams resizeParams = new() {
21-
Size = Request.Query.ContainsKey("size") && uint.TryParse(Request.Query["size"], out uint size) ? size : null,
22-
Quality = Request.Query.ContainsKey("quality") && Enum.TryParse<DiscordImageResizeQuality>(Request.Query["quality"], true, out var quality) ? quality : DiscordImageResizeQuality.High,
23-
KeepAspectRatio = !Request.Query.ContainsKey("keepAspectRatio") || !bool.TryParse(Request.Query["keepAspectRatio"], out bool kar) || kar,
24-
Passthrough = Request.Query.ContainsKey("passthrough") && bool.TryParse(Request.Query["passthrough"], out bool pt) && pt,
25-
Animated = Request.Query.ContainsKey("animated") && bool.TryParse(Request.Query["animated"], out bool an) && an,
26-
SpacebarAllowUpscale = Request.Query.ContainsKey("allowUpscale") && bool.TryParse(Request.Query["allowUpscale"], out bool au) && au,
27-
SpacebarOptimiseGif = Request.Query.ContainsKey("optimiseGif") && bool.TryParse(Request.Query["optimiseGif"], out bool og) && og
28-
};
19+
20+
DiscordImageResizeParams resizeParams = GetResizeParams();
2921

3022
var entry = await lfc.GetOrAdd(cacheKey, async () => {
3123
var original = await fs.GetFile(Request.Path);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Collections.Immutable;
2+
using ArcaneLibs.Extensions.Streams;
3+
using Microsoft.AspNetCore.Mvc;
4+
using Spacebar.AdminApi.TestClient.Services.Services;
5+
using Spacebar.Cdn.Extensions;
6+
using Spacebar.Interop.Cdn.Abstractions;
7+
8+
namespace Spacebar.Cdn.Controllers;
9+
10+
[ApiController]
11+
public class StaticAssetController(LruFileCache lfc, IFileSource fs, DiscordImageResizeService dirs) : ImageController {
12+
private static readonly Dictionary<string, string> defaultAvatarHashMap = new() {
13+
{ "0", "4a8562cf00887030c416d3ec2d46385a" },
14+
{ "1", "9b0bb198936784c45c72833cc426cc55" },
15+
{ "2", "22341bdb500c7b63a93bbce957d1601e" },
16+
{ "3", "d9977836b82058bf2f74eebd50edc095" },
17+
{ "4", "9d6ddb4e4d899a533a8cc617011351c9" },
18+
{ "5", "7213ab6677377974697dfdfbaf5f6a6f" },
19+
};
20+
21+
private static readonly Dictionary<string, string> defaultGroupDMAvatarHashMap = new() {
22+
{ "0", "3b70bb66089c60f8be5e214bf8574c9d" },
23+
{ "1", "9581acd31832465bdeaa5385b0e919a3" },
24+
{ "2", "a8a4727cf2dc2939bd3c657fad4463fa" },
25+
{ "3", "2e46fe14586f8e95471c0917f56726b5" },
26+
{ "4", "fac7e78de9753d4a37083bba74c1d9ef" },
27+
{ "5", "4ab900144b0865430dc9be825c838faa" },
28+
{ "6", "1276374a404452756f3c9cc2601508a5" },
29+
{ "7", "904bf9f1b61f53ef4a3b7a893afeabe3" },
30+
};
31+
// [HttpGet("/embed/avatars/{userIndex}")]
32+
// public async Task<IActionResult> GetDefaultUserAvatar(string userIndex) {
33+
//
34+
// }
35+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using ArcaneLibs.Extensions.Streams;
2+
using Microsoft.AspNetCore.Mvc;
3+
using Spacebar.AdminApi.TestClient.Services.Services;
4+
using Spacebar.Cdn.Extensions;
5+
using Spacebar.Interop.Cdn.Abstractions;
6+
7+
namespace Spacebar.Cdn.Controllers;
8+
9+
[ApiController]
10+
public class UserController(LruFileCache lfc, IFileSource fs, DiscordImageResizeService dirs) : ImageController {
11+
[HttpGet("/avatars/{userId}/{hash}.{ext}")]
12+
public async Task<IActionResult> GetUserAvatar(string userId, string hash, string ext) {
13+
var originalKey = fs.BaseUrl + Request.Path;
14+
var cacheKey = Request.Path + Request.QueryString;
15+
16+
DiscordImageResizeParams resizeParams = GetResizeParams();
17+
18+
var entry = await lfc.GetOrAdd(cacheKey, async () => {
19+
var original = await fs.GetFile(Request.Path);
20+
21+
if (Request.Query.Any()) {
22+
using var img = await original.ToMagickImageCollectionAsync();
23+
dirs.Apply(img, resizeParams);
24+
25+
var outStream = new MemoryStream();
26+
await img.WriteAsync(outStream, img.First().Format);
27+
outStream.Position = 0;
28+
29+
return new LruFileCache.Entry() {
30+
Data = outStream.ReadToEnd().ToArray(),
31+
MimeType = original.MimeType
32+
};
33+
}
34+
35+
return new LruFileCache.Entry() {
36+
Data = original.Stream.ReadToEnd().ToArray(),
37+
MimeType = original.MimeType
38+
};
39+
});
40+
41+
// byte array with mime type result
42+
return new FileContentResult(entry.Data, entry.MimeType);
43+
}
44+
[HttpGet("/banners/{userId}/{hash}.{ext}")]
45+
public async Task<IActionResult> GetUserBanner(string userId, string hash, string ext) {
46+
var originalKey = fs.BaseUrl + Request.Path;
47+
var cacheKey = Request.Path + Request.QueryString;
48+
49+
DiscordImageResizeParams resizeParams = GetResizeParams();
50+
51+
var entry = await lfc.GetOrAdd(cacheKey, async () => {
52+
var original = await fs.GetFile(Request.Path);
53+
54+
if (Request.Query.Any()) {
55+
using var img = await original.ToMagickImageCollectionAsync();
56+
dirs.Apply(img, resizeParams);
57+
58+
var outStream = new MemoryStream();
59+
await img.WriteAsync(outStream, img.First().Format);
60+
outStream.Position = 0;
61+
62+
return new LruFileCache.Entry() {
63+
Data = outStream.ReadToEnd().ToArray(),
64+
MimeType = original.MimeType
65+
};
66+
}
67+
68+
return new LruFileCache.Entry() {
69+
Data = original.Stream.ReadToEnd().ToArray(),
70+
MimeType = original.MimeType
71+
};
72+
});
73+
74+
// byte array with mime type result
75+
return new FileContentResult(entry.Data, entry.MimeType);
76+
}
77+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using Spacebar.AdminApi.TestClient.Services.Services;
3+
4+
namespace Spacebar.Cdn.Extensions;
5+
6+
public class ImageController : ControllerBase {
7+
protected DiscordImageResizeParams GetResizeParams() {
8+
return new() {
9+
Size = Request.Query.ContainsKey("size") && uint.TryParse(Request.Query["size"], out uint size) ? size : null,
10+
Quality = Request.Query.ContainsKey("quality") && Enum.TryParse<DiscordImageResizeQuality>(Request.Query["quality"], true, out var quality)
11+
? quality
12+
: DiscordImageResizeQuality.High,
13+
KeepAspectRatio = !Request.Query.ContainsKey("keepAspectRatio") || !bool.TryParse(Request.Query["keepAspectRatio"], out bool kar) || kar,
14+
Passthrough = Request.Query.ContainsKey("passthrough") && bool.TryParse(Request.Query["passthrough"], out bool pt) && pt,
15+
Animated = Request.Query.ContainsKey("animated") && bool.TryParse(Request.Query["animated"], out bool an) && an,
16+
SpacebarAllowUpscale = Request.Query.ContainsKey("allowUpscale") && bool.TryParse(Request.Query["allowUpscale"], out bool au) && au,
17+
SpacebarOptimiseGif = Request.Query.ContainsKey("optimiseGif") && bool.TryParse(Request.Query["optimiseGif"], out bool og) && og
18+
};
19+
}
20+
21+
protected void SetSuccessCacheHeader() {
22+
int cacheDuration = (int)TimeSpan.FromHours(6).TotalSeconds;
23+
Response.Headers.CacheControl = $"public, max-age={cacheDuration}, s-maxage={cacheDuration}, immutable";
24+
}
25+
26+
protected void SetFailureCacheHeader() {
27+
int cacheDuration = (int)TimeSpan.FromMinutes(5).TotalSeconds;
28+
Response.Headers.CacheControl = $"public, max-age={cacheDuration}, s-maxage={cacheDuration}, immutable";
29+
}
30+
}

extra/admin-api/Spacebar.Cdn/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
builder.Configuration.AddJsonFile(Environment.GetEnvironmentVariable("APPSETTINGS_PATH")!);
1111

1212
// Add services to the container.
13-
builder.Services.AddSingleton<IFileSource>(new ProxyFileSource("http://cdn.old.server.spacebar.chat"));
13+
// builder.Services.AddSingleton<IFileSource>(new ProxyFileSource("http://cdn.old.server.spacebar.chat"));
14+
builder.Services.AddSingleton<IFileSource>(new FilesystemFileSource(Environment.GetEnvironmentVariable("STORAGE_PATH") ?? throw new InvalidOperationException("STORAGE_PATH not set!")));
1415
builder.Services.AddSingleton<LruFileCache>(new LruFileCache(1 * 1024 * 1024 * 1024));
1516
builder.Services.AddSingleton<PixelArtDetectionService>();
1617
builder.Services.AddSingleton<DiscordImageResizeService>();

extra/admin-api/Spacebar.UApi/Controllers/GuildStickerController.cs

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,31 @@ namespace Spacebar.UApi.Controllers;
1212
[Route("/api/v{_}/guilds/{guildId}/stickers/")]
1313
public class GuildStickerController(ILogger<MessagesController> logger, SpacebarDbContext db, SpacebarAspNetAuthenticationService authService, UApiConfiguration cfg, PermissionService permService, Config sbCfg) : ControllerBase {
1414
// TODO proper response type
15-
[HttpPost]
16-
public async Task<Sticker> UploadGuildSticker(string guildId, MultipartFormDataContent content) {
17-
18-
var sticker = new Sticker() {
19-
GuildId = guildId
20-
};
21-
22-
foreach (var item in content) {
23-
switch (item.Headers.ContentDisposition.Name.Trim('"')) {
24-
case "name":
25-
sticker.Name = await item.ReadAsStringAsync();
26-
break;
27-
case "description":
28-
sticker.Description = await item.ReadAsStringAsync();
29-
break;
30-
case "tags":
31-
sticker.Tags = await item.ReadAsStringAsync();
32-
break;
33-
case "file":
34-
var fileContent = await item.ReadAsStreamAsync();
35-
36-
break;
37-
}
38-
}
39-
40-
return sticker;
41-
}
15+
// [HttpPost]
16+
// public async Task<Sticker> UploadGuildSticker(string guildId, MultipartFormDataContent content) {
17+
//
18+
// var sticker = new Sticker() {
19+
// GuildId = guildId
20+
// };
21+
//
22+
// foreach (var item in content) {
23+
// switch (item.Headers.ContentDisposition.Name.Trim('"')) {
24+
// case "name":
25+
// sticker.Name = await item.ReadAsStringAsync();
26+
// break;
27+
// case "description":
28+
// sticker.Description = await item.ReadAsStringAsync();
29+
// break;
30+
// case "tags":
31+
// sticker.Tags = await item.ReadAsStringAsync();
32+
// break;
33+
// case "file":
34+
// var fileContent = await item.ReadAsStreamAsync();
35+
//
36+
// break;
37+
// }
38+
// }
39+
//
40+
// return sticker;
41+
// }
4242
}

0 commit comments

Comments
 (0)