2024-07-19 12:56:41 -04:00
using System.Text.RegularExpressions ;
using CommonSocketLibrary.Abstract ;
using CommonSocketLibrary.Common ;
using Microsoft.Extensions.DependencyInjection ;
using Serilog ;
using TwitchChatTTS.Chat.Groups.Permissions ;
using TwitchChatTTS.Hermes.Socket ;
2024-08-04 19:46:10 -04:00
using TwitchChatTTS.Twitch.Socket.Messages ;
2024-07-19 12:56:41 -04:00
using static TwitchChatTTS . Chat . Commands . TTSCommands ;
namespace TwitchChatTTS.Chat.Commands
{
2024-08-06 15:29:29 -04:00
public class CommandManager : ICommandManager
2024-07-19 12:56:41 -04:00
{
private readonly User _user ;
2024-08-06 15:29:29 -04:00
private ICommandSelector _commandSelector ;
2024-07-19 12:56:41 -04:00
private readonly HermesSocketClient _hermes ;
2024-08-06 15:29:29 -04:00
//private readonly TwitchWebsocketClient _twitch;
2024-07-19 12:56:41 -04:00
private readonly IGroupPermissionManager _permissionManager ;
private readonly ILogger _logger ;
private string CommandStartSign { get ; } = "!" ;
public CommandManager (
User user ,
2024-08-06 15:29:29 -04:00
[FromKeyedServices("hermes")] SocketClient < WebSocketMessage > hermes ,
//[FromKeyedServices("twitch")] SocketClient<TwitchWebsocketMessage> twitch,
2024-07-19 12:56:41 -04:00
IGroupPermissionManager permissionManager ,
ILogger logger
)
{
_user = user ;
2024-08-06 15:29:29 -04:00
_hermes = ( hermes as HermesSocketClient ) ! ;
//_twitch = (twitch as TwitchWebsocketClient)!;
2024-07-19 12:56:41 -04:00
_permissionManager = permissionManager ;
_logger = logger ;
}
2024-08-04 19:46:10 -04:00
public async Task < ChatCommandResult > Execute ( string arg , ChannelChatMessage message , IEnumerable < string > groups )
2024-07-19 12:56:41 -04:00
{
if ( string . IsNullOrWhiteSpace ( arg ) )
return ChatCommandResult . Unknown ;
arg = arg . Trim ( ) ;
if ( ! arg . StartsWith ( CommandStartSign ) )
return ChatCommandResult . Unknown ;
2024-08-06 15:29:29 -04:00
if ( message . BroadcasterUserId ! = _user . TwitchUserId . ToString ( ) )
return ChatCommandResult . OtherRoom ;
2024-07-19 12:56:41 -04:00
string [ ] parts = Regex . Matches ( arg . Substring ( CommandStartSign . Length ) , "(?<match>[^\"\\n\\s]+|\"[^\"\\n]*\")" )
. Cast < Match > ( )
. Select ( m = > m . Groups [ "match" ] . Value )
2024-08-06 15:29:29 -04:00
. Where ( m = > ! string . IsNullOrEmpty ( m ) )
2024-07-19 12:56:41 -04:00
. Select ( m = > m . StartsWith ( '"' ) & & m . EndsWith ( '"' ) ? m . Substring ( 1 , m . Length - 2 ) : m )
. ToArray ( ) ;
string [ ] args = parts . ToArray ( ) ;
string com = args . First ( ) . ToLower ( ) ;
2024-08-04 19:46:10 -04:00
CommandSelectorResult selectorResult = _commandSelector . GetBestMatch ( args , message ) ;
2024-07-19 12:56:41 -04:00
if ( selectorResult . Command = = null )
{
2024-08-06 15:29:29 -04:00
_logger . Warning ( $"Could not match '{arg}' to any command [chatter: {message.ChatterUserLogin}][chatter id: {message.ChatterUserId}]" ) ;
2024-07-19 12:56:41 -04:00
return ChatCommandResult . Missing ;
}
// Check if command can be executed by this chatter.
var command = selectorResult . Command ;
2024-08-04 19:46:10 -04:00
long chatterId = long . Parse ( message . ChatterUserId ) ;
2024-07-19 12:56:41 -04:00
if ( chatterId ! = _user . OwnerId )
{
2024-08-06 16:32:02 -04:00
bool executable = command . AcceptCustomPermission ? CanExecute ( chatterId , groups , $"tts.commands.{com}" , selectorResult . Permissions ) : false ;
2024-08-04 19:46:10 -04:00
if ( ! executable )
2024-07-19 12:56:41 -04:00
{
2024-08-06 16:32:02 -04:00
_logger . Warning ( $"Denied permission to use command [chatter id: {chatterId}][args: {arg}][command type: {command.GetType().Name}]" ) ;
2024-07-19 12:56:41 -04:00
return ChatCommandResult . Permission ;
}
}
2024-08-04 19:46:10 -04:00
// Check if the arguments are valid.
2024-07-19 12:56:41 -04:00
var arguments = _commandSelector . GetNonStaticArguments ( args , selectorResult . Path ) ;
foreach ( var entry in arguments )
{
var parameter = entry . Value ;
var argument = entry . Key ;
2024-08-04 19:46:10 -04:00
// Optional parameters were validated while fetching this command.
if ( ! parameter . Optional & & ! parameter . Validate ( argument , message ) )
2024-07-19 12:56:41 -04:00
{
2024-08-04 19:46:10 -04:00
_logger . Warning ( $"Command failed due to an argument being invalid [argument name: {parameter.Name}][argument value: {argument}][arguments: {arg}][command type: {command.GetType().Name}][chatter: {message.ChatterUserLogin}][chatter id: {message.ChatterUserId}]" ) ;
2024-07-19 12:56:41 -04:00
return ChatCommandResult . Syntax ;
}
}
var values = arguments . ToDictionary ( d = > d . Value . Name , d = > d . Key ) ;
try
{
await command . Execute ( values , message , _hermes ) ;
}
catch ( Exception e )
{
2024-08-04 19:46:10 -04:00
_logger . Error ( e , $"Command '{arg}' failed [args: {arg}][command type: {command.GetType().Name}][chatter: {message.ChatterUserLogin}][chatter id: {message.ChatterUserId}]" ) ;
2024-07-19 12:56:41 -04:00
return ChatCommandResult . Fail ;
}
2024-08-04 19:46:10 -04:00
_logger . Information ( $"Executed the {com} command [args: {arg}][command type: {command.GetType().Name}][chatter: {message.ChatterUserLogin}][chatter id: {message.ChatterUserId}]" ) ;
2024-07-19 12:56:41 -04:00
return ChatCommandResult . Success ;
}
2024-08-06 15:29:29 -04:00
public void Update ( ICommandFactory factory )
{
_commandSelector = factory . Build ( ) ;
}
2024-08-04 19:46:10 -04:00
private bool CanExecute ( long chatterId , IEnumerable < string > groups , string path , string [ ] ? additionalPaths )
2024-07-19 12:56:41 -04:00
{
2024-08-04 19:46:10 -04:00
_logger . Debug ( $"Checking for permission [chatter id: {chatterId}][group: {string.Join(" , ", groups)}][path: {path}]{(additionalPaths != null ? " [ paths : " + string.Join('|', additionalPaths) + " ] " : string.Empty)}" ) ;
2024-08-06 16:32:02 -04:00
if ( _permissionManager . CheckIfAllowed ( groups , path ) = = true )
2024-08-06 15:29:29 -04:00
{
if ( additionalPaths = = null )
return true ;
// All direct allow must not be false and at least one of them must be true.
if ( additionalPaths . All ( p = > _permissionManager . CheckIfDirectAllowed ( groups , p ) ! = false ) & & additionalPaths . Any ( p = > _permissionManager . CheckIfDirectAllowed ( groups , p ) = = true ) )
return true ;
}
return false ;
2024-07-19 12:56:41 -04:00
}
}
}