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
{
public class CommandManager
{
private readonly User _user ;
private readonly ICommandSelector _commandSelector ;
private readonly HermesSocketClient _hermes ;
private readonly IGroupPermissionManager _permissionManager ;
private readonly ILogger _logger ;
private string CommandStartSign { get ; } = "!" ;
public CommandManager (
IEnumerable < IChatCommand > commands ,
ICommandBuilder commandBuilder ,
User user ,
[FromKeyedServices("hermes")] SocketClient < WebSocketMessage > socketClient ,
IGroupPermissionManager permissionManager ,
ILogger logger
)
{
_user = user ;
_hermes = ( socketClient as HermesSocketClient ) ! ;
_permissionManager = permissionManager ;
_logger = logger ;
foreach ( var command in commands )
{
_logger . Debug ( $"Creating command tree for '{command.Name}'." ) ;
command . Build ( commandBuilder ) ;
}
_commandSelector = commandBuilder . Build ( ) ;
}
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 ;
string [ ] parts = Regex . Matches ( arg . Substring ( CommandStartSign . Length ) , "(?<match>[^\"\\n\\s]+|\"[^\"\\n]*\")" )
. Cast < Match > ( )
. Select ( m = > m . Groups [ "match" ] . Value )
. 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 )
{
_logger . Warning ( $"Could not match '{arg}' to any command." ) ;
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-04 19:46:10 -04:00
bool executable = command . AcceptCustomPermission ? CanExecute ( chatterId , groups , $"tts.command.{com}" , selectorResult . Permissions ) : false ;
if ( ! executable )
2024-07-19 12:56:41 -04:00
{
_logger . Debug ( $"Denied permission to use command [chatter id: {chatterId}][command: {com}]" ) ;
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-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)}" ) ;
return _permissionManager . CheckIfAllowed ( groups , path ) ! = false & & ( additionalPaths = = null | | additionalPaths . All ( p = > _permissionManager . CheckIfAllowed ( groups , p ) ! = false ) ) ;
2024-07-19 12:56:41 -04:00
}
}
}