refactor: cache own user ID in IDiscordCache
- remove Cluster.User - remove Cluster.Application (it was only being used as an alternative to Cluster.User for some reason) - move Bot.PermissionsIn to DiscordCacheExtensions
This commit is contained in:
		| @@ -1,7 +1,9 @@ | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| using Myriad.Extensions; | ||||
| using Myriad.Gateway; | ||||
| using Myriad.Types; | ||||
|  | ||||
| namespace Myriad.Cache | ||||
| { | ||||
| @@ -11,6 +13,8 @@ namespace Myriad.Cache | ||||
|         { | ||||
|             switch (evt) | ||||
|             { | ||||
|                 case ReadyEvent ready: | ||||
|                     return cache.SaveOwnUser(ready.User.Id); | ||||
|                 case GuildCreateEvent gc: | ||||
|                     return cache.SaveGuildCreate(gc); | ||||
|                 case GuildUpdateEvent gu: | ||||
| @@ -102,5 +106,20 @@ namespace Myriad.Cache | ||||
|             foreach (var thread in evt.Threads) | ||||
|                 await cache.SaveChannel(thread); | ||||
|         } | ||||
|  | ||||
|         public static async Task<PermissionSet> PermissionsIn(this IDiscordCache cache, ulong channelId) | ||||
|         { | ||||
|             var channel = await cache.GetRootChannel(channelId); | ||||
|  | ||||
|             if (channel.GuildId != null) | ||||
|             { | ||||
|                 var userId = await cache.GetOwnUser(); | ||||
|                 var member = await cache.TryGetSelfMember(channel.GuildId.Value); | ||||
|                 return await cache.PermissionsFor(channelId, userId, member); | ||||
|             } | ||||
|  | ||||
|             return PermissionSet.Dm; | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -7,6 +7,7 @@ namespace Myriad.Cache | ||||
| { | ||||
|     public interface IDiscordCache | ||||
|     { | ||||
|         public ValueTask SaveOwnUser(ulong userId); | ||||
|         public ValueTask SaveGuild(Guild guild); | ||||
|         public ValueTask SaveChannel(Channel channel); | ||||
|         public ValueTask SaveUser(User user); | ||||
| @@ -19,6 +20,7 @@ namespace Myriad.Cache | ||||
|         public ValueTask RemoveUser(ulong userId); | ||||
|         public ValueTask RemoveRole(ulong guildId, ulong roleId); | ||||
|  | ||||
|         public Task<ulong> GetOwnUser(); | ||||
|         public Task<Guild?> TryGetGuild(ulong guildId); | ||||
|         public Task<Channel?> TryGetChannel(ulong channelId); | ||||
|         public Task<Channel?> TryGetDmChannel(ulong userId); | ||||
|   | ||||
| @@ -16,6 +16,7 @@ namespace Myriad.Cache | ||||
|         private readonly ConcurrentDictionary<ulong, Role> _roles = new(); | ||||
|         private readonly ConcurrentDictionary<ulong, User> _users = new(); | ||||
|         private readonly ConcurrentDictionary<ulong, GuildMemberPartial> _guildMembers = new(); | ||||
|         private ulong? _ownUserId { get; set; } | ||||
|  | ||||
|         public ValueTask SaveGuild(Guild guild) | ||||
|         { | ||||
| @@ -46,6 +47,15 @@ namespace Myriad.Cache | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public ValueTask SaveOwnUser(ulong userId) | ||||
|         { | ||||
|             // this (hopefully) never changes at runtime, so we skip out on re-assigning it | ||||
|             if (_ownUserId == null) | ||||
|                 _ownUserId = userId; | ||||
|  | ||||
|             return default; | ||||
|         } | ||||
|  | ||||
|         public ValueTask SaveUser(User user) | ||||
|         { | ||||
|             _users[user.Id] = user; | ||||
| @@ -125,6 +135,8 @@ namespace Myriad.Cache | ||||
|             return default; | ||||
|         } | ||||
|  | ||||
|         public Task<ulong> GetOwnUser() => Task.FromResult(_ownUserId!.Value); | ||||
|  | ||||
|         public ValueTask RemoveRole(ulong guildId, ulong roleId) | ||||
|         { | ||||
|             _roles.TryRemove(roleId, out _); | ||||
|   | ||||
| @@ -28,8 +28,6 @@ namespace Myriad.Gateway | ||||
|         public event Action<Shard>? ShardCreated; | ||||
|  | ||||
|         public IReadOnlyDictionary<int, Shard> Shards => _shards; | ||||
|         public User? User => _shards.Values.Select(s => s.User).FirstOrDefault(s => s != null); | ||||
|         public ApplicationPartial? Application => _shards.Values.Select(s => s.Application).FirstOrDefault(s => s != null); | ||||
|  | ||||
|         public async Task Start(GatewayInfo.Bot info) | ||||
|         { | ||||
|   | ||||
| @@ -77,19 +77,6 @@ namespace PluralKit.Bot | ||||
|             }, null, timeTillNextWholeMinute, TimeSpan.FromMinutes(1)); | ||||
|         } | ||||
|  | ||||
|         public async Task<PermissionSet> PermissionsIn(ulong channelId) | ||||
|         { | ||||
|             var channel = await _cache.GetRootChannel(channelId); | ||||
|  | ||||
|             if (channel.GuildId != null) | ||||
|             { | ||||
|                 var member = await _cache.TryGetSelfMember(channel.GuildId.Value); | ||||
|                 return await _cache.PermissionsFor(channelId, _cluster.User?.Id ?? default, member); | ||||
|             } | ||||
|  | ||||
|             return PermissionSet.Dm; | ||||
|         } | ||||
|  | ||||
|         private async Task OnEventReceived(Shard shard, IGatewayEvent evt) | ||||
|         { | ||||
|             await _cache.TryUpdateSelfMember(shard, evt); | ||||
| @@ -249,7 +236,7 @@ namespace PluralKit.Bot | ||||
|                 if (reportChannel == null) | ||||
|                     return; | ||||
|  | ||||
|                 var botPerms = await PermissionsIn(reportChannel.Value); | ||||
|                 var botPerms = await _cache.PermissionsIn(reportChannel.Value); | ||||
|                 if (botPerms.HasFlag(PermissionSet.SendMessages | PermissionSet.EmbedLinks)) | ||||
|                     await _errorMessageService.SendErrorMessage(reportChannel.Value, sentryEvent.EventId.ToString()); | ||||
|             } | ||||
|   | ||||
| @@ -71,7 +71,7 @@ namespace PluralKit.Bot | ||||
|         public Cluster Cluster => _cluster; | ||||
|         public MessageContext MessageContext => _messageContext; | ||||
|  | ||||
|         public Task<PermissionSet> BotPermissions => _provider.Resolve<Bot>().PermissionsIn(_channel.Id); | ||||
|         public Task<PermissionSet> BotPermissions => _provider.Resolve<IDiscordCache>().PermissionsIn(_channel.Id); | ||||
|         public Task<PermissionSet> UserPermissions => _cache.PermissionsFor(_message); | ||||
|  | ||||
|         public DiscordApiClient Rest => _rest; | ||||
|   | ||||
| @@ -87,7 +87,7 @@ namespace PluralKit.Bot | ||||
|             var missingEmojiPermissions = false; | ||||
|             foreach (var channel in await _rest.GetGuildChannels(guild.Id)) | ||||
|             { | ||||
|                 var botPermissions = await _bot.PermissionsIn(channel.Id); | ||||
|                 var botPermissions = await _cache.PermissionsIn(channel.Id); | ||||
|                 var webhookPermissions = await _cache.EveryonePermissions(channel); | ||||
|                 var userPermissions = PermissionExtensions.PermissionsFor(guild, channel, ctx.Author.Id, senderGuildUser); | ||||
|  | ||||
| @@ -176,7 +176,7 @@ namespace PluralKit.Bot | ||||
|             if (!await ctx.CheckPermissionsInGuildChannel(channel, PermissionSet.ViewChannel)) | ||||
|                 throw new PKError(error); | ||||
|  | ||||
|             var botPermissions = await _bot.PermissionsIn(channel.Id); | ||||
|             var botPermissions = await _cache.PermissionsIn(channel.Id); | ||||
|             var webhookPermissions = await _cache.EveryonePermissions(channel); | ||||
|  | ||||
|             // We use a bitfield so we can set individual permission bits | ||||
|   | ||||
| @@ -61,7 +61,7 @@ namespace PluralKit.Bot | ||||
|                 p.IncludeLastSwitch = true; | ||||
|             if (ctx.MatchFlag("with-last-message", "with-last-proxy", "wlm", "wlp")) | ||||
|                 throw new PKError("Sorting by last message is temporarily disabled due to database issues, sorry."); | ||||
|                 // p.IncludeLastMessage = true; | ||||
|             // p.IncludeLastMessage = true; | ||||
|             if (ctx.MatchFlag("with-message-count", "wmc")) | ||||
|                 p.IncludeMessageCount = true; | ||||
|             if (ctx.MatchFlag("with-created", "wc")) | ||||
|   | ||||
| @@ -59,7 +59,7 @@ namespace PluralKit.Bot | ||||
|  | ||||
|         public async Task Invite(Context ctx) | ||||
|         { | ||||
|             var clientId = _botConfig.ClientId ?? _cluster.Application?.Id; | ||||
|             var clientId = _botConfig.ClientId ?? await _cache.GetOwnUser(); | ||||
|  | ||||
|             var permissions = | ||||
|                 PermissionSet.AddReactions | | ||||
|   | ||||
| @@ -59,7 +59,7 @@ namespace PluralKit.Bot | ||||
|             if (channel.Type != Channel.ChannelType.GuildText) | ||||
|                 throw new PKError("PluralKit cannot log messages to this type of channel."); | ||||
|  | ||||
|             var perms = await _bot.PermissionsIn(channel.Id); | ||||
|             var perms = await _cache.PermissionsIn(channel.Id); | ||||
|             if (!perms.HasFlag(PermissionSet.SendMessages)) | ||||
|                 throw new PKError("PluralKit is missing **Send Messages** permissions in the new log channel."); | ||||
|             if (!perms.HasFlag(PermissionSet.EmbedLinks)) | ||||
|   | ||||
| @@ -54,7 +54,9 @@ namespace PluralKit.Bot | ||||
|         // for now, only return error messages for explicit commands | ||||
|         public ulong? ErrorChannelFor(MessageCreateEvent evt) | ||||
|         { | ||||
|             if (!HasCommandPrefix(evt.Content, _cluster.User?.Id ?? default, out var cmdStart) || cmdStart == evt.Content.Length) | ||||
|             // todo: fix @mention prefix | ||||
|             // it only breaks error reporting so I'm not *too* worried about it, but should be fixed eventually | ||||
|             if (!HasCommandPrefix(evt.Content, default, out var cmdStart) || cmdStart == evt.Content.Length) | ||||
|                 return null; | ||||
|  | ||||
|             return evt.ChannelId; | ||||
| @@ -156,7 +158,7 @@ namespace PluralKit.Bot | ||||
|  | ||||
|         private async ValueTask<bool> TryHandleProxy(Shard shard, MessageCreateEvent evt, Guild guild, Channel channel, MessageContext ctx) | ||||
|         { | ||||
|             var botPermissions = await _bot.PermissionsIn(channel.Id); | ||||
|             var botPermissions = await _cache.PermissionsIn(channel.Id); | ||||
|  | ||||
|             try | ||||
|             { | ||||
|   | ||||
| @@ -45,7 +45,7 @@ namespace PluralKit.Bot | ||||
|  | ||||
|         public async Task Handle(Shard shard, MessageUpdateEvent evt) | ||||
|         { | ||||
|             if (evt.Author.Value?.Id == _client.User?.Id) return; | ||||
|             if (evt.Author.Value?.Id == await _cache.GetOwnUser()) return; | ||||
|  | ||||
|             // Edit message events sometimes arrive with missing data; double-check it's all there | ||||
|             if (!evt.Content.HasValue || !evt.Author.HasValue || !evt.Member.HasValue) | ||||
| @@ -67,7 +67,7 @@ namespace PluralKit.Bot | ||||
|                 ctx = await _repo.GetMessageContext(evt.Author.Value!.Id, channel.GuildId!.Value, evt.ChannelId); | ||||
|  | ||||
|             var equivalentEvt = await GetMessageCreateEvent(evt, lastMessage, channel); | ||||
|             var botPermissions = await _bot.PermissionsIn(channel.Id); | ||||
|             var botPermissions = await _cache.PermissionsIn(channel.Id); | ||||
|  | ||||
|             try | ||||
|             { | ||||
| @@ -112,7 +112,7 @@ namespace PluralKit.Bot | ||||
|             if (referencedMessageId == null) | ||||
|                 return null; | ||||
|  | ||||
|             var botPermissions = await _bot.PermissionsIn(channelId); | ||||
|             var botPermissions = await _cache.PermissionsIn(channelId); | ||||
|             if (!botPermissions.HasFlag(PermissionSet.ReadMessageHistory)) | ||||
|             { | ||||
|                 _logger.Warning("Tried to get referenced message in channel {ChannelId} to reply but bot does not have Read Message History", | ||||
|   | ||||
| @@ -54,7 +54,7 @@ namespace PluralKit.Bot | ||||
|                 return; | ||||
|  | ||||
|             // ignore any reactions added by *us* | ||||
|             if (evt.UserId == _cluster.User?.Id) | ||||
|             if (evt.UserId == await _cache.GetOwnUser()) | ||||
|                 return; | ||||
|  | ||||
|             // Ignore reactions from bots (we can't DM them anyway) | ||||
| @@ -121,7 +121,7 @@ namespace PluralKit.Bot | ||||
|  | ||||
|         private async ValueTask HandleProxyDeleteReaction(MessageReactionAddEvent evt, FullMessage msg) | ||||
|         { | ||||
|             if (!(await _bot.PermissionsIn(evt.ChannelId)).HasFlag(PermissionSet.ManageMessages)) | ||||
|             if (!(await _cache.PermissionsIn(evt.ChannelId)).HasFlag(PermissionSet.ManageMessages)) | ||||
|                 return; | ||||
|  | ||||
|             var system = await _repo.GetSystemByAccount(evt.UserId); | ||||
| @@ -185,7 +185,7 @@ namespace PluralKit.Bot | ||||
|  | ||||
|         private async ValueTask HandlePingReaction(MessageReactionAddEvent evt, FullMessage msg) | ||||
|         { | ||||
|             if (!(await _bot.PermissionsIn(evt.ChannelId)).HasFlag(PermissionSet.ManageMessages)) | ||||
|             if (!(await _cache.PermissionsIn(evt.ChannelId)).HasFlag(PermissionSet.ManageMessages)) | ||||
|                 return; | ||||
|  | ||||
|             // Check if the "pinger" has permission to send messages in this channel | ||||
| @@ -240,7 +240,7 @@ namespace PluralKit.Bot | ||||
|  | ||||
|         private async Task TryRemoveOriginalReaction(MessageReactionAddEvent evt) | ||||
|         { | ||||
|             if ((await _bot.PermissionsIn(evt.ChannelId)).HasFlag(PermissionSet.ManageMessages)) | ||||
|             if ((await _cache.PermissionsIn(evt.ChannelId)).HasFlag(PermissionSet.ManageMessages)) | ||||
|                 await _rest.DeleteUserReaction(evt.ChannelId, evt.MessageId, evt.Emoji, evt.UserId); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -78,7 +78,7 @@ namespace PluralKit.Bot | ||||
|             if (logChannel == null || logChannel.Type != Channel.ChannelType.GuildText) return null; | ||||
|  | ||||
|             // Check bot permissions | ||||
|             var perms = await _bot.PermissionsIn(logChannel.Id); | ||||
|             var perms = await _cache.PermissionsIn(logChannel.Id); | ||||
|             if (!perms.HasFlag(PermissionSet.SendMessages | PermissionSet.EmbedLinks)) | ||||
|             { | ||||
|                 _logger.Information( | ||||
|   | ||||
| @@ -89,7 +89,7 @@ namespace PluralKit.Bot | ||||
|             var channel = await _cache.GetChannel(msg.ChannelId); | ||||
|  | ||||
|             if (channel.Type != Channel.ChannelType.GuildText) return; | ||||
|             if (!(await _bot.PermissionsIn(channel.Id)).HasFlag(PermissionSet.ManageMessages)) return; | ||||
|             if (!(await _cache.PermissionsIn(channel.Id)).HasFlag(PermissionSet.ManageMessages)) return; | ||||
|  | ||||
|             // If this message is from a *webhook*, check if the name matches one of the bots we know | ||||
|             // TODO: do we need to do a deeper webhook origin check, or would that be too hard on the rate limit? | ||||
|   | ||||
| @@ -6,7 +6,7 @@ using System.Threading.Tasks; | ||||
|  | ||||
| using App.Metrics; | ||||
|  | ||||
| using Myriad.Gateway; | ||||
| using Myriad.Cache; | ||||
| using Myriad.Rest; | ||||
| using Myriad.Rest.Types.Requests; | ||||
| using Myriad.Types; | ||||
| @@ -24,13 +24,13 @@ namespace PluralKit.Bot | ||||
|  | ||||
|         private readonly IMetrics _metrics; | ||||
|         private readonly ILogger _logger; | ||||
|         private readonly Cluster _cluster; | ||||
|         private readonly IDiscordCache _cache; | ||||
|  | ||||
|         public WebhookCacheService(ILogger logger, IMetrics metrics, DiscordApiClient rest, Cluster cluster) | ||||
|         public WebhookCacheService(ILogger logger, IMetrics metrics, DiscordApiClient rest, IDiscordCache cache) | ||||
|         { | ||||
|             _metrics = metrics; | ||||
|             _rest = rest; | ||||
|             _cluster = cluster; | ||||
|             _cache = cache; | ||||
|             _logger = logger.ForContext<WebhookCacheService>(); | ||||
|             _webhooks = new ConcurrentDictionary<ulong, Lazy<Task<Webhook>>>(); | ||||
|         } | ||||
| @@ -86,7 +86,8 @@ namespace PluralKit.Bot | ||||
|             var webhooks = await FetchChannelWebhooks(channelId); | ||||
|  | ||||
|             // If the channel has a webhook created by PK, just return that one | ||||
|             var ourWebhook = webhooks.FirstOrDefault(IsWebhookMine); | ||||
|             var ourUserId = await _cache.GetOwnUser(); | ||||
|             var ourWebhook = webhooks.FirstOrDefault(hook => IsWebhookMine(ourUserId, hook)); | ||||
|             if (ourWebhook != null) | ||||
|                 return ourWebhook; | ||||
|  | ||||
| @@ -120,7 +121,7 @@ namespace PluralKit.Bot | ||||
|             return await _rest.CreateWebhook(channelId, new CreateWebhookRequest(WebhookName)); | ||||
|         } | ||||
|  | ||||
|         private bool IsWebhookMine(Webhook arg) => arg.User?.Id == _cluster.User?.Id && arg.Name == WebhookName; | ||||
|         private bool IsWebhookMine(ulong userId, Webhook arg) => arg.User?.Id == userId && arg.Name == WebhookName; | ||||
|  | ||||
|         public int CacheSize => _webhooks.Count; | ||||
|     } | ||||
|   | ||||
| @@ -42,7 +42,7 @@ namespace PluralKit.Bot | ||||
|  | ||||
|                 if (await _cache.TryGetChannel(channel.Value) != null) | ||||
|                 { | ||||
|                     var botPermissions = await _bot.PermissionsIn(channel.Value); | ||||
|                     var botPermissions = await _cache.PermissionsIn(channel.Value); | ||||
|                     props.Add(new("BotPermissions", new ScalarValue(botPermissions))); | ||||
|                 } | ||||
|             } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user