feat(bot): implement sharded http cache lookup

This commit is contained in:
alyssa 2024-09-27 18:53:31 +09:00
parent 9ff824c37b
commit 8f9b6f1554
3 changed files with 20 additions and 14 deletions

View file

@ -103,7 +103,7 @@ public static class DiscordCacheExtensions
public static async Task<PermissionSet> BotPermissionsIn(this IDiscordCache cache, ulong guildId, ulong channelId) public static async Task<PermissionSet> BotPermissionsIn(this IDiscordCache cache, ulong guildId, ulong channelId)
{ {
if (cache is HttpDiscordCache) if (cache is HttpDiscordCache)
return await ((HttpDiscordCache)cache).BotPermissions(guildId, channelId); return await ((HttpDiscordCache)cache).BotChannelPermissions(guildId, channelId);
var channel = await cache.GetRootChannel(guildId, channelId); var channel = await cache.GetRootChannel(guildId, channelId);

View file

@ -11,16 +11,18 @@ public class HttpDiscordCache: IDiscordCache
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly HttpClient _client; private readonly HttpClient _client;
private readonly string _cacheEndpoint; private readonly Uri _cacheEndpoint;
private readonly int _shardCount;
private readonly ulong _ownUserId; private readonly ulong _ownUserId;
private readonly JsonSerializerOptions _jsonSerializerOptions; private readonly JsonSerializerOptions _jsonSerializerOptions;
public HttpDiscordCache(ILogger logger, HttpClient client, string cacheEndpoint, ulong ownUserId) public HttpDiscordCache(ILogger logger, HttpClient client, string cacheEndpoint, int shardCount, ulong ownUserId)
{ {
_logger = logger; _logger = logger;
_client = client; _client = client;
_cacheEndpoint = cacheEndpoint; _cacheEndpoint = new Uri(cacheEndpoint);
_shardCount = shardCount;
_ownUserId = ownUserId; _ownUserId = ownUserId;
_jsonSerializerOptions = new JsonSerializerOptions().ConfigureForMyriad(); _jsonSerializerOptions = new JsonSerializerOptions().ConfigureForMyriad();
} }
@ -38,10 +40,14 @@ public class HttpDiscordCache: IDiscordCache
public ulong GetOwnUser() => _ownUserId; public ulong GetOwnUser() => _ownUserId;
// todo: cluster private async Task<T?> QueryCache<T>(string endpoint, ulong guildId)
private async Task<T?> QueryCache<T>(string endpoint)
{ {
var response = await _client.GetAsync($"{_cacheEndpoint}{endpoint}"); var cluster = _cacheEndpoint.Authority;
if (cluster.Contains(".service.consul"))
// int(((guild_id >> 22) % shard_count) / 16)
cluster = $"cluster{(int)(((guildId >> 22) % (ulong)_shardCount) / 16)}.{cluster}";
var response = await _client.GetAsync($"{_cacheEndpoint.Scheme}://{cluster}{endpoint}");
if (response.StatusCode == HttpStatusCode.NotFound) if (response.StatusCode == HttpStatusCode.NotFound)
return default; return default;
@ -54,10 +60,10 @@ public class HttpDiscordCache: IDiscordCache
} }
public Task<Guild?> TryGetGuild(ulong guildId) public Task<Guild?> TryGetGuild(ulong guildId)
=> QueryCache<Guild?>($"/guilds/{guildId}"); => QueryCache<Guild?>($"/guilds/{guildId}", guildId);
public Task<Channel?> TryGetChannel(ulong guildId, ulong channelId) public Task<Channel?> TryGetChannel(ulong guildId, ulong channelId)
=> QueryCache<Channel?>($"/guilds/{guildId}/channels/{channelId}"); => QueryCache<Channel?>($"/guilds/{guildId}/channels/{channelId}", guildId);
// this should be a GetUserCached method on nirn-proxy (it's always called as GetOrFetchUser) // this should be a GetUserCached method on nirn-proxy (it's always called as GetOrFetchUser)
// so just return nothing // so just return nothing
@ -65,11 +71,11 @@ public class HttpDiscordCache: IDiscordCache
=> Task.FromResult<User?>(null); => Task.FromResult<User?>(null);
public Task<GuildMemberPartial?> TryGetSelfMember(ulong guildId) public Task<GuildMemberPartial?> TryGetSelfMember(ulong guildId)
=> QueryCache<GuildMemberPartial?>($"/guilds/{guildId}/members/@me"); => QueryCache<GuildMemberPartial?>($"/guilds/{guildId}/members/@me", guildId);
public Task<PermissionSet> BotPermissions(ulong guildId, ulong channelId) public Task<PermissionSet> BotChannelPermissions(ulong guildId, ulong channelId)
=> QueryCache<PermissionSet>($"/guilds/{guildId}/channels/{channelId}/permissions/@me"); => QueryCache<PermissionSet>($"/guilds/{guildId}/channels/{channelId}/permissions/@me", guildId);
public Task<IEnumerable<Channel>> GetGuildChannels(ulong guildId) public Task<IEnumerable<Channel>> GetGuildChannels(ulong guildId)
=> QueryCache<IEnumerable<Channel>>($"/guilds/{guildId}/channels"); => QueryCache<IEnumerable<Channel>>($"/guilds/{guildId}/channels", guildId);
} }

View file

@ -50,7 +50,7 @@ public class BotModule: Module
if (botConfig.HttpCacheUrl != null) if (botConfig.HttpCacheUrl != null)
return new HttpDiscordCache(c.Resolve<ILogger>(), return new HttpDiscordCache(c.Resolve<ILogger>(),
c.Resolve<HttpClient>(), botConfig.HttpCacheUrl, botConfig.ClientId); c.Resolve<HttpClient>(), botConfig.HttpCacheUrl, botConfig.Cluster?.TotalShards ?? 1, botConfig.ClientId);
return new MemoryDiscordCache(botConfig.ClientId); return new MemoryDiscordCache(botConfig.ClientId);
}).AsSelf().SingleInstance(); }).AsSelf().SingleInstance();