2024-08-07 16:30:03 -04:00
using Serilog ;
using TwitchChatTTS.Twitch.Socket.Messages ;
namespace TwitchChatTTS.Twitch.Socket.Handlers
{
public class ChannelRaidHandler : ITwitchSocketHandler
{
public string Name = > "channel.raid" ;
private readonly TwitchApiClient _api ;
private readonly User _user ;
private readonly ILogger _logger ;
private readonly object _lock ;
public ChannelRaidHandler ( TwitchApiClient api , User user , ILogger logger )
{
_api = api ;
_user = user ;
_logger = logger ;
_lock = new object ( ) ;
}
public async Task Execute ( TwitchWebsocketClient sender , object data )
{
if ( data is not ChannelRaidMessage message )
return ;
2024-08-07 18:01:04 -04:00
_logger . Information ( $"A raid has started. Starting raid spam prevention. [from: {message.FromBroadcasterUserLogin}][from id: {message.FromBroadcasterUserId}]." ) ;
2024-08-07 19:21:56 -04:00
EventResponse < ChatterMessage > ? chatters = null ;
if ( ! _user . Raids . ContainsKey ( message . ToBroadcasterUserId ) )
2024-08-07 16:30:03 -04:00
{
2024-08-14 16:35:35 -04:00
chatters = await _api . GetChatters ( message . ToBroadcasterUserId . ToString ( ) , _user . TwitchUserId . ToString ( ) ) ;
2024-08-07 19:21:56 -04:00
if ( chatters ? . Data = = null )
{
var extraErrorInfo = _user . TwitchUserId . ToString ( ) ! = message . ToBroadcasterUserId ? " Ensure you have moderator status in your joined channel(s) to prevent raid spam." : string . Empty ;
_logger . Error ( "Could not fetch the list of chatters in chat." + extraErrorInfo ) ;
return ;
}
2024-08-07 16:30:03 -04:00
}
2024-08-07 19:21:56 -04:00
var startDate = DateTime . Now ;
var endDate = startDate + TimeSpan . FromSeconds ( 30 ) ;
2024-08-07 16:30:03 -04:00
lock ( _lock )
{
2024-08-07 19:21:56 -04:00
if ( _user . Raids . TryGetValue ( message . ToBroadcasterUserId , out var raid ) )
raid . RaidSpamPreventionEndDate = endDate ;
else
2024-08-07 16:30:03 -04:00
{
2024-08-07 19:21:56 -04:00
var chatterIds = chatters ! . Data ! . Select ( c = > long . Parse ( c . UserId ) ) ;
_user . Raids . Add ( message . ToBroadcasterUserId , new RaidInfo ( endDate , new HashSet < long > ( chatterIds ) ) ) ;
2024-08-07 16:30:03 -04:00
}
}
2024-08-07 19:21:56 -04:00
Task . Run ( async ( ) = > await EndOfRaidSpamProtection ( message . ToBroadcasterUserId , endDate ) ) ;
2024-08-07 18:01:04 -04:00
}
2024-08-07 19:21:56 -04:00
private async Task EndOfRaidSpamProtection ( string raidedId , DateTime endDate )
2024-08-07 18:01:04 -04:00
{
2024-08-07 19:21:56 -04:00
await Task . Delay ( endDate - DateTime . Now ) ;
2024-08-07 16:30:03 -04:00
lock ( _lock )
{
2024-08-07 19:21:56 -04:00
if ( _user . Raids . TryGetValue ( raidedId , out var raid ) )
2024-08-07 16:30:03 -04:00
{
2024-08-07 19:21:56 -04:00
if ( raid . RaidSpamPreventionEndDate = = endDate )
{
_logger . Information ( "Raid message spam prevention ended." ) ;
_user . Raids . Remove ( raidedId ) ;
}
else
_logger . Debug ( "Raid spam prevention would have stopped now if it wasn't for the consecutive raid." ) ;
2024-08-07 16:30:03 -04:00
}
2024-08-07 19:21:56 -04:00
else
_logger . Error ( "Something went wrong ending a raid spam prevention." ) ;
2024-08-07 16:30:03 -04:00
}
}
}
2024-08-07 19:21:56 -04:00
public sealed class RaidInfo
{
public DateTime RaidSpamPreventionEndDate { get ; set ; }
public HashSet < long > Chatters { get ; set ; }
public RaidInfo ( DateTime raidEnd , HashSet < long > chatters )
{
RaidSpamPreventionEndDate = raidEnd ;
Chatters = chatters ;
}
}
2024-08-07 16:30:03 -04:00
}