1
0
Fork 1
mirror of https://github.com/TeamOctolings/Octobot.git synced 2025-04-19 16:33:36 +03:00

Add missing xmldocs for GuildUpdateService and UtilityService

Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com>
This commit is contained in:
Octol1ttle 2023-06-11 23:19:28 +05:00
parent 3cd2b672a1
commit df00377b06
Signed by: Octol1ttle
GPG key ID: B77C34313AEE1FFF
2 changed files with 63 additions and 7 deletions

View file

@ -7,12 +7,16 @@ using Remora.Discord.API.Abstractions.Rest;
using Remora.Discord.API.Objects;
using Remora.Discord.Extensions.Embeds;
using Remora.Discord.Extensions.Formatting;
using Remora.Discord.Gateway.Responders;
using Remora.Discord.Interactivity;
using Remora.Rest.Core;
using Remora.Results;
namespace Boyfriend.Services;
/// <summary>
/// Handles executing guild updates (also called "ticks") once per second.
/// </summary>
public class GuildUpdateService : BackgroundService {
private readonly IDiscordRestChannelAPI _channelApi;
private readonly GuildDataService _dataService;
@ -35,6 +39,11 @@ public class GuildUpdateService : BackgroundService {
_utility = utility;
}
/// <summary>
/// Activates a periodic timer with a 1 second interval and adds guild update tasks on each timer tick.
/// </summary>
/// <remarks>If update tasks take longer than 1 second, the next timer tick will be skipped.</remarks>
/// <param name="ct">The cancellation token for this operation.</param>
protected override async Task ExecuteAsync(CancellationToken ct) {
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(1));
var tasks = new List<Task>();
@ -47,6 +56,28 @@ public class GuildUpdateService : BackgroundService {
}
}
/// <summary>
/// Runs an update ("tick") for a guild with the provided <paramref name="guildId" />.
/// </summary>
/// <remarks>
/// This method does the following:
/// <list type="bullet">
/// <item>Automatically unbans users once their ban period has expired.</item>
/// <item>Sends reminders about an upcoming scheduled event.</item>
/// <item>Sends scheduled event start notifications.</item>
/// <item>Sends scheduled event completion notifications.</item>
/// </list>
/// This is done here and not in a <see cref="IResponder{TGatewayEvent}" /> for the following reasons:
/// <list type="bullet">
/// <item>
/// Downtime would affect the reliability of notifications and automatic unbans if this logic were to be in a
/// <see cref="IResponder{TGatewayEvent}" />.
/// </item>
/// <item>The Discord API doesn't provide necessary about scheduled event updates.</item>
/// </list>
/// </remarks>
/// <param name="guildId">The ID of the guild to update.</param>
/// <param name="ct">The cancellation token for this operation.</param>
private async Task TickGuildAsync(Snowflake guildId, CancellationToken ct = default) {
var data = await _dataService.GetData(guildId, ct);
Messages.Culture = data.Culture;
@ -76,7 +107,7 @@ public class GuildUpdateService : BackgroundService {
if (DateTimeOffset.UtcNow
>= scheduledEvent.ScheduledStartTime - data.Configuration.EventEarlyNotificationOffset
&& !storedEvent.EarlyNotificationSent) {
var earlyResult = await SendScheduledEventStartedMessage(scheduledEvent, data, true, ct);
var earlyResult = await SendScheduledEventUpdatedMessage(scheduledEvent, data, true, ct);
if (earlyResult.IsSuccess)
storedEvent.EarlyNotificationSent = true;
else
@ -95,7 +126,7 @@ public class GuildUpdateService : BackgroundService {
GuildScheduledEventStatus.Scheduled =>
await SendScheduledEventCreatedMessage(scheduledEvent, data.Configuration, ct),
GuildScheduledEventStatus.Active or GuildScheduledEventStatus.Completed =>
await SendScheduledEventStartedMessage(scheduledEvent, data, false, ct),
await SendScheduledEventUpdatedMessage(scheduledEvent, data, false, ct),
_ => Result.FromError(new ArgumentOutOfRangeError(nameof(scheduledEvent.Status)))
};
@ -110,6 +141,10 @@ public class GuildUpdateService : BackgroundService {
/// when a scheduled event is created
/// in a guild's <see cref="GuildConfiguration.EventNotificationChannel" /> if one is set.
/// </summary>
/// <param name="scheduledEvent">The scheduled event that has just been created.</param>
/// <param name="config">The configuration of the guild containing the scheduled event.</param>
/// <param name="ct">The cancellation token for this operation.</param>
/// <returns>A notification sending result which may or may not have succeeded.</returns>
private async Task<Result> SendScheduledEventCreatedMessage(
IGuildScheduledEvent scheduledEvent, GuildConfiguration config, CancellationToken ct = default) {
var currentUserResult = await _userApi.GetCurrentUserAsync(ct);
@ -189,7 +224,12 @@ public class GuildUpdateService : BackgroundService {
/// when a scheduled event is about to start, has started or completed
/// in a guild's <see cref="GuildConfiguration.EventNotificationChannel" /> if one is set.
/// </summary>
private async Task<Result> SendScheduledEventStartedMessage(
/// <param name="scheduledEvent">The scheduled event that is about to start, has started or completed.</param>
/// <param name="data">The data for the guild containing the scheduled event.</param>
/// <param name="early">Controls whether or not a reminder for the scheduled event should be sent instead of the event started/completed notification</param>
/// <param name="ct">The cancellation token for this operation</param>
/// <returns>A reminder/notification sending result which may or may not have succeeded.</returns>
private async Task<Result> SendScheduledEventUpdatedMessage(
IGuildScheduledEvent scheduledEvent, GuildData data, bool early, CancellationToken ct = default) {
var currentUserResult = await _userApi.GetCurrentUserAsync(ct);
if (!currentUserResult.IsDefined(out var currentUser)) return Result.FromError(currentUserResult);
@ -233,7 +273,8 @@ public class GuildUpdateService : BackgroundService {
return Result.FromError(new ArgumentOutOfRangeError(nameof(scheduledEvent.EntityType)));
}
var contentResult = await _utility.GetEventNotificationMentions(data, scheduledEvent, ct);
var contentResult = await _utility.GetEventNotificationMentions(
scheduledEvent, data.Configuration, ct);
if (!contentResult.IsDefined(out content))
return Result.FromError(contentResult);

View file

@ -102,11 +102,26 @@ public class UtilityService : IHostedService {
return Result<string?>.FromSuccess(null);
}
/// <summary>
/// Gets the string mentioning all <see cref="GuildConfiguration.NotificationReceiver" />s related to a scheduled
/// event.
/// </summary>
/// <remarks>
/// If the guild configuration enables <see cref="GuildConfiguration.NotificationReceiver.Role" />, then the
/// <see cref="GuildConfiguration.EventNotificationRole" /> will also be mentioned.
/// </remarks>
/// <param name="scheduledEvent">
/// The scheduled event whose subscribers will be mentioned if the guild configuration enables
/// <see cref="GuildConfiguration.NotificationReceiver.Interested" />.
/// </param>
/// <param name="config">The configuration of the guild containing the scheduled event</param>
/// <param name="ct">The cancellation token for this operation.</param>
/// <returns>A result containing the string which may or may not have succeeded.</returns>
public async Task<Result<string>> GetEventNotificationMentions(
GuildData data, IGuildScheduledEvent scheduledEvent, CancellationToken ct = default) {
IGuildScheduledEvent scheduledEvent, GuildConfiguration config, CancellationToken ct = default) {
var builder = new StringBuilder();
var receivers = data.Configuration.EventStartedReceivers;
var role = data.Configuration.EventNotificationRole.ToDiscordSnowflake();
var receivers = config.EventStartedReceivers;
var role = config.EventNotificationRole.ToDiscordSnowflake();
var usersResult = await _eventApi.GetGuildScheduledEventUsersAsync(
scheduledEvent.GuildID, scheduledEvent.ID, withMember: true, ct: ct);
if (!usersResult.IsDefined(out var users)) return Result<string>.FromError(usersResult);