SquadBot/StateMangers/VoiceStateManager.cs

101 lines
4.0 KiB
C#

using Microsoft.Extensions.Caching.Memory;
using NetCord;
using NetCord.Gateway;
using NetCord.Hosting.Gateway;
using NetCord.Rest;
using SquadBot.Providers;
namespace SquadBot.StateMangers;
public class VoiceStateManager
{
// Key: GuildId Value: List of UserId for users in voice channel
// TODO: We probably want to persist this somewhere else (Redis/Valkey)
private Dictionary<ulong, ISet<ulong>> _guildVoiceStates;
private IMemoryCache _yapperNotificationTimeoutCache;
private RestClient _restClient;
private ILogger<VoiceStateManager> _logger;
public VoiceStateManager(ILogger<VoiceStateManager> logger, RestClient restClient, IMemoryCache yapperNotificationTimeoutCache)
{
_guildVoiceStates = new Dictionary<ulong, ISet<ulong>>();
_yapperNotificationTimeoutCache = yapperNotificationTimeoutCache;
_restClient = restClient ?? throw new System.ArgumentNullException(nameof(restClient));
_logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
}
public async Task HandleVoiceStateChange(VoiceState voice_state)
{
if (voice_state.ChannelId is not null)
{
// Joining channel
_logger.LogInformation($"New yapper detected: {voice_state.User.Username}");
if (!_guildVoiceStates.TryGetValue(voice_state.GuildId, out var yappers) || yappers.Count == 0)
{
yappers ??= new HashSet<ulong>();
var channels = await _restClient.GetGuildChannelsAsync(voice_state.GuildId);
var alertChannelId = channels.FirstOrDefault(channel => channel.Name == "bot-tinkering")?.Id;
var guildRoles = await _restClient.GetGuildRolesAsync(voice_state.GuildId,
new RestRequestProperties() { AuditLogReason = "Role lookup" });
var yapperRoleId = guildRoles.FirstOrDefault(role => role.Name.ToLower() == "yapper")?.Id;
if (alertChannelId is null || yapperRoleId is null)
{
_logger.LogError($"Found incorrect state, alert channel or yapper role does not exist.");
return;
}
if (!CheckIfTimeoutExpired(voice_state.GuildId)) return;
// Notify that new yapper has arrived
await SendYapperNotification(yapperRoleId.GetValueOrDefault(), alertChannelId.GetValueOrDefault());
}
yappers.Add(voice_state.UserId);
_guildVoiceStates[voice_state.GuildId] = yappers;
}
else
{
// Leaving channel
_logger.LogInformation($"Yapper leaving: {voice_state.User.Username}");
if (_guildVoiceStates.TryGetValue(voice_state.GuildId, out var yappers))
{
yappers.Remove(voice_state.UserId);
_guildVoiceStates[voice_state.GuildId] = yappers;
if (yappers.Count == 0) SetGuildTimeout(voice_state.GuildId);
}
}
return;
}
private void SetGuildTimeout(ulong guild_id)
{
#if DEBUG
var expiration = DateTimeOffset.UtcNow.AddMinutes(1);
#else
var expiration = DateTimeOffset.UtcNow.AddHours(2);
#endif
_yapperNotificationTimeoutCache.Set(guild_id, expiration, expiration);
}
private bool CheckIfTimeoutExpired(ulong guild_id)
{
var timeOutCached =
_yapperNotificationTimeoutCache.TryGetValue(guild_id, out DateTimeOffset timeout);
if (timeOutCached == false) return true;
if (timeout < DateTimeOffset.UtcNow) return true;
return false;
}
private async Task SendYapperNotification(ulong yapperRoleId, ulong alertChannelId)
{
await _restClient.SendMessageAsync(
alertChannelId,
new MessageProperties()
{
AllowedMentions = new AllowedMentionsProperties() {AllowedRoles = [yapperRoleId]},
Content = $"<@&{yapperRoleId}> " + PhraseProvider.GetYapperPhrase()
});
}
}