From d713b977f04751d3a6982cebfafc517463ae2b2d Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Sat, 30 Sep 2023 20:36:55 +0500 Subject: [PATCH 1/2] Synchronize roles only on member data updates (#130) This PR makes it so that roles in MemberData are updated only in MemberUpdateService. This reduces possible points of failures, maintenance burden and reliance on gateway events --- .../GuildMemberRolesUpdatedResponder.cs | 33 ------------------- src/Services/GuildDataService.cs | 19 +---------- src/Services/Update/MemberUpdateService.cs | 5 +++ 3 files changed, 6 insertions(+), 51 deletions(-) delete mode 100644 src/Responders/GuildMemberRolesUpdatedResponder.cs diff --git a/src/Responders/GuildMemberRolesUpdatedResponder.cs b/src/Responders/GuildMemberRolesUpdatedResponder.cs deleted file mode 100644 index b883c89..0000000 --- a/src/Responders/GuildMemberRolesUpdatedResponder.cs +++ /dev/null @@ -1,33 +0,0 @@ -using JetBrains.Annotations; -using Octobot.Data; -using Octobot.Services; -using Remora.Discord.API.Abstractions.Gateway.Events; -using Remora.Discord.Gateway.Responders; -using Remora.Results; - -namespace Octobot.Responders; - -/// -/// Handles updating when a guild member is updated. -/// -[UsedImplicitly] -public class GuildMemberUpdateResponder : IResponder -{ - private readonly GuildDataService _guildData; - - public GuildMemberUpdateResponder(GuildDataService guildData) - { - _guildData = guildData; - } - - public async Task RespondAsync(IGuildMemberUpdate gatewayEvent, CancellationToken ct = default) - { - var memberData = await _guildData.GetMemberData(gatewayEvent.GuildID, gatewayEvent.User.ID, ct); - if (memberData.MutedUntil is null) - { - memberData.Roles = gatewayEvent.Roles.ToList().ConvertAll(r => r.Value); - } - - return Result.FromSuccess(); - } -} diff --git a/src/Services/GuildDataService.cs b/src/Services/GuildDataService.cs index 5d2b1b1..f5c7faa 100644 --- a/src/Services/GuildDataService.cs +++ b/src/Services/GuildDataService.cs @@ -4,7 +4,6 @@ using System.Text.Json.Nodes; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Octobot.Data; -using Remora.Discord.API.Abstractions.Rest; using Remora.Rest.Core; namespace Octobot.Services; @@ -15,14 +14,12 @@ namespace Octobot.Services; public sealed class GuildDataService : IHostedService { private readonly ConcurrentDictionary _datas = new(); - private readonly IDiscordRestGuildAPI _guildApi; private readonly ILogger _logger; // https://github.com/dotnet/aspnetcore/issues/39139 public GuildDataService( - IHostApplicationLifetime lifetime, IDiscordRestGuildAPI guildApi, ILogger logger) + IHostApplicationLifetime lifetime, ILogger logger) { - _guildApi = guildApi; _logger = logger; lifetime.ApplicationStopping.Register(ApplicationStopping); } @@ -110,15 +107,6 @@ public sealed class GuildDataService : IHostedService continue; } - if (data.MutedUntil is null) - { - var memberResult = await _guildApi.GetGuildMemberAsync(guildId, data.Id.ToSnowflake(), ct); - if (memberResult.IsSuccess) - { - data.Roles = memberResult.Entity.Roles.ToList().ConvertAll(r => r.Value); - } - } - memberData.Add(data.Id, data); } @@ -150,11 +138,6 @@ public sealed class GuildDataService : IHostedService return (await GetData(guildId, ct)).Settings; } - public async Task GetMemberData(Snowflake guildId, Snowflake userId, CancellationToken ct = default) - { - return (await GetData(guildId, ct)).GetOrCreateMemberData(userId); - } - public ICollection GetGuildIds() { return _datas.Keys; diff --git a/src/Services/Update/MemberUpdateService.cs b/src/Services/Update/MemberUpdateService.cs index 7cd13fe..1d2b7f6 100644 --- a/src/Services/Update/MemberUpdateService.cs +++ b/src/Services/Update/MemberUpdateService.cs @@ -89,6 +89,11 @@ public sealed partial class MemberUpdateService : BackgroundService return failedResults.AggregateErrors(); } + if (data.MutedUntil is null) + { + data.Roles = guildMember.Roles.ToList().ConvertAll(r => r.Value); + } + var autoUnmuteResult = await TryAutoUnmuteAsync(guildId, id, data, ct); failedResults.AddIfFailed(autoUnmuteResult); From e073c5a5720955fe2aa2a93ae2051f878be9a874 Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Sat, 30 Sep 2023 20:38:52 +0500 Subject: [PATCH 2/2] Synchronize events only on sch. event updates (#131) This PR moves all code related to synchronization of scheduled events to ScheduledEventUpdateService. Just like #130, this reduces possible points of failures, maintenance burden and reliance on gateway events --- src/Responders/GuildLoadedResponder.cs | 13 -------- .../ScheduledEventUpdatedResponder.cs | 30 ------------------- .../Update/ScheduledEventUpdateService.cs | 21 ++++++++----- 3 files changed, 14 insertions(+), 50 deletions(-) delete mode 100644 src/Responders/ScheduledEventUpdatedResponder.cs diff --git a/src/Responders/GuildLoadedResponder.cs b/src/Responders/GuildLoadedResponder.cs index cfc33fa..92fc009 100644 --- a/src/Responders/GuildLoadedResponder.cs +++ b/src/Responders/GuildLoadedResponder.cs @@ -50,19 +50,6 @@ public class GuildLoadedResponder : IResponder data.GetOrCreateMemberData(member.User.Value.ID); } - foreach (var schEvent in guild.GuildScheduledEvents) - { - if (!data.ScheduledEvents.TryGetValue(schEvent.ID.Value, out var eventData)) - { - continue; - } - - eventData.Name = schEvent.Name; - eventData.ScheduledStartTime = schEvent.ScheduledStartTime; - eventData.ScheduleOnStatusUpdated = eventData.Status != schEvent.Status; - eventData.Status = schEvent.Status; - } - if (!GuildSettings.ReceiveStartupMessages.Get(cfg)) { return Result.FromSuccess(); diff --git a/src/Responders/ScheduledEventUpdatedResponder.cs b/src/Responders/ScheduledEventUpdatedResponder.cs deleted file mode 100644 index 85162a4..0000000 --- a/src/Responders/ScheduledEventUpdatedResponder.cs +++ /dev/null @@ -1,30 +0,0 @@ -using JetBrains.Annotations; -using Octobot.Services; -using Remora.Discord.API.Abstractions.Gateway.Events; -using Remora.Discord.Gateway.Responders; -using Remora.Results; - -namespace Octobot.Responders; - -[UsedImplicitly] -public class ScheduledEventUpdatedResponder : IResponder -{ - private readonly GuildDataService _guildData; - - public ScheduledEventUpdatedResponder(GuildDataService guildData) - { - _guildData = guildData; - } - - public async Task RespondAsync(IGuildScheduledEventUpdate gatewayEvent, CancellationToken ct = default) - { - var data = await _guildData.GetData(gatewayEvent.GuildID, ct); - var eventData = data.ScheduledEvents[gatewayEvent.ID.Value]; - eventData.Name = gatewayEvent.Name; - eventData.ScheduledStartTime = gatewayEvent.ScheduledStartTime; - eventData.ScheduleOnStatusUpdated = eventData.Status != gatewayEvent.Status; - eventData.Status = gatewayEvent.Status; - - return Result.FromSuccess(); - } -} diff --git a/src/Services/Update/ScheduledEventUpdateService.cs b/src/Services/Update/ScheduledEventUpdateService.cs index 2a8beca..f83c1de 100644 --- a/src/Services/Update/ScheduledEventUpdateService.cs +++ b/src/Services/Update/ScheduledEventUpdateService.cs @@ -61,6 +61,8 @@ public sealed class ScheduledEventUpdateService : BackgroundService return Result.FromError(eventsResult); } + SyncScheduledEvents(data, events); + foreach (var storedEvent in data.ScheduledEvents.Values) { var scheduledEvent = TryGetScheduledEvent(events, storedEvent.Id); @@ -100,20 +102,25 @@ public sealed class ScheduledEventUpdateService : BackgroundService failedResults.AddIfFailed(statusUpdatedResponseResult); } - SyncScheduledEvents(data, events); - return failedResults.AggregateErrors(); } - private static void SyncScheduledEvents(GuildData data, IReadOnlyCollection events) + private static void SyncScheduledEvents(GuildData data, IEnumerable events) { - if (data.ScheduledEvents.Count < events.Count) + foreach (var @event in events) { - foreach (var @event in events.Where(@event => !data.ScheduledEvents.ContainsKey(@event.ID.Value))) + if (!data.ScheduledEvents.ContainsKey(@event.ID.Value)) { - data.ScheduledEvents.Add(@event.ID.Value, new ScheduledEventData(@event.ID.Value, - @event.Name, @event.ScheduledStartTime, @event.Status)); + data.ScheduledEvents.Add(@event.ID.Value, + new ScheduledEventData(@event.ID.Value, @event.Name, @event.ScheduledStartTime, @event.Status)); + continue; } + + var eventData = data.ScheduledEvents[@event.ID.Value]; + eventData.Name = @event.Name; + eventData.ScheduledStartTime = @event.ScheduledStartTime; + eventData.ScheduleOnStatusUpdated = eventData.Status != @event.Status; + eventData.Status = @event.Status; } }