mirror of
https://github.com/TeamOctolings/Octobot.git
synced 2025-04-20 00:43:36 +03:00
Add missing xmldocs for GuildUpdateService and UtilityService
Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com>
This commit is contained in:
parent
3cd2b672a1
commit
df00377b06
2 changed files with 63 additions and 7 deletions
|
@ -7,12 +7,16 @@ using Remora.Discord.API.Abstractions.Rest;
|
||||||
using Remora.Discord.API.Objects;
|
using Remora.Discord.API.Objects;
|
||||||
using Remora.Discord.Extensions.Embeds;
|
using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Extensions.Formatting;
|
using Remora.Discord.Extensions.Formatting;
|
||||||
|
using Remora.Discord.Gateway.Responders;
|
||||||
using Remora.Discord.Interactivity;
|
using Remora.Discord.Interactivity;
|
||||||
using Remora.Rest.Core;
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Boyfriend.Services;
|
namespace Boyfriend.Services;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles executing guild updates (also called "ticks") once per second.
|
||||||
|
/// </summary>
|
||||||
public class GuildUpdateService : BackgroundService {
|
public class GuildUpdateService : BackgroundService {
|
||||||
private readonly IDiscordRestChannelAPI _channelApi;
|
private readonly IDiscordRestChannelAPI _channelApi;
|
||||||
private readonly GuildDataService _dataService;
|
private readonly GuildDataService _dataService;
|
||||||
|
@ -35,6 +39,11 @@ public class GuildUpdateService : BackgroundService {
|
||||||
_utility = utility;
|
_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) {
|
protected override async Task ExecuteAsync(CancellationToken ct) {
|
||||||
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(1));
|
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(1));
|
||||||
var tasks = new List<Task>();
|
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) {
|
private async Task TickGuildAsync(Snowflake guildId, CancellationToken ct = default) {
|
||||||
var data = await _dataService.GetData(guildId, ct);
|
var data = await _dataService.GetData(guildId, ct);
|
||||||
Messages.Culture = data.Culture;
|
Messages.Culture = data.Culture;
|
||||||
|
@ -76,7 +107,7 @@ public class GuildUpdateService : BackgroundService {
|
||||||
if (DateTimeOffset.UtcNow
|
if (DateTimeOffset.UtcNow
|
||||||
>= scheduledEvent.ScheduledStartTime - data.Configuration.EventEarlyNotificationOffset
|
>= scheduledEvent.ScheduledStartTime - data.Configuration.EventEarlyNotificationOffset
|
||||||
&& !storedEvent.EarlyNotificationSent) {
|
&& !storedEvent.EarlyNotificationSent) {
|
||||||
var earlyResult = await SendScheduledEventStartedMessage(scheduledEvent, data, true, ct);
|
var earlyResult = await SendScheduledEventUpdatedMessage(scheduledEvent, data, true, ct);
|
||||||
if (earlyResult.IsSuccess)
|
if (earlyResult.IsSuccess)
|
||||||
storedEvent.EarlyNotificationSent = true;
|
storedEvent.EarlyNotificationSent = true;
|
||||||
else
|
else
|
||||||
|
@ -95,7 +126,7 @@ public class GuildUpdateService : BackgroundService {
|
||||||
GuildScheduledEventStatus.Scheduled =>
|
GuildScheduledEventStatus.Scheduled =>
|
||||||
await SendScheduledEventCreatedMessage(scheduledEvent, data.Configuration, ct),
|
await SendScheduledEventCreatedMessage(scheduledEvent, data.Configuration, ct),
|
||||||
GuildScheduledEventStatus.Active or GuildScheduledEventStatus.Completed =>
|
GuildScheduledEventStatus.Active or GuildScheduledEventStatus.Completed =>
|
||||||
await SendScheduledEventStartedMessage(scheduledEvent, data, false, ct),
|
await SendScheduledEventUpdatedMessage(scheduledEvent, data, false, ct),
|
||||||
_ => Result.FromError(new ArgumentOutOfRangeError(nameof(scheduledEvent.Status)))
|
_ => Result.FromError(new ArgumentOutOfRangeError(nameof(scheduledEvent.Status)))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -110,6 +141,10 @@ public class GuildUpdateService : BackgroundService {
|
||||||
/// when a scheduled event is created
|
/// when a scheduled event is created
|
||||||
/// in a guild's <see cref="GuildConfiguration.EventNotificationChannel" /> if one is set.
|
/// in a guild's <see cref="GuildConfiguration.EventNotificationChannel" /> if one is set.
|
||||||
/// </summary>
|
/// </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(
|
private async Task<Result> SendScheduledEventCreatedMessage(
|
||||||
IGuildScheduledEvent scheduledEvent, GuildConfiguration config, CancellationToken ct = default) {
|
IGuildScheduledEvent scheduledEvent, GuildConfiguration config, CancellationToken ct = default) {
|
||||||
var currentUserResult = await _userApi.GetCurrentUserAsync(ct);
|
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
|
/// when a scheduled event is about to start, has started or completed
|
||||||
/// in a guild's <see cref="GuildConfiguration.EventNotificationChannel" /> if one is set.
|
/// in a guild's <see cref="GuildConfiguration.EventNotificationChannel" /> if one is set.
|
||||||
/// </summary>
|
/// </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) {
|
IGuildScheduledEvent scheduledEvent, GuildData data, bool early, CancellationToken ct = default) {
|
||||||
var currentUserResult = await _userApi.GetCurrentUserAsync(ct);
|
var currentUserResult = await _userApi.GetCurrentUserAsync(ct);
|
||||||
if (!currentUserResult.IsDefined(out var currentUser)) return Result.FromError(currentUserResult);
|
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)));
|
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))
|
if (!contentResult.IsDefined(out content))
|
||||||
return Result.FromError(contentResult);
|
return Result.FromError(contentResult);
|
||||||
|
|
||||||
|
|
|
@ -102,11 +102,26 @@ public class UtilityService : IHostedService {
|
||||||
return Result<string?>.FromSuccess(null);
|
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(
|
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 builder = new StringBuilder();
|
||||||
var receivers = data.Configuration.EventStartedReceivers;
|
var receivers = config.EventStartedReceivers;
|
||||||
var role = data.Configuration.EventNotificationRole.ToDiscordSnowflake();
|
var role = config.EventNotificationRole.ToDiscordSnowflake();
|
||||||
var usersResult = await _eventApi.GetGuildScheduledEventUsersAsync(
|
var usersResult = await _eventApi.GetGuildScheduledEventUsersAsync(
|
||||||
scheduledEvent.GuildID, scheduledEvent.ID, withMember: true, ct: ct);
|
scheduledEvent.GuildID, scheduledEvent.ID, withMember: true, ct: ct);
|
||||||
if (!usersResult.IsDefined(out var users)) return Result<string>.FromError(usersResult);
|
if (!usersResult.IsDefined(out var users)) return Result<string>.FromError(usersResult);
|
||||||
|
|
Loading…
Add table
Reference in a new issue