3
0
mirror of https://github.com/pragma-/pbot.git synced 2025-02-18 14:30:40 +01:00

Progress on refactoring and polishing everything

This commit is contained in:
Pragmatic Software 2021-06-11 14:58:16 -07:00
parent 06d0951e2a
commit 6a4e14ef8d
8 changed files with 815 additions and 514 deletions

View File

@ -285,6 +285,7 @@ sub check_flood {
$account = delete $self->{changinghost}->{$nick}; $account = delete $self->{changinghost}->{$nick};
my $id = $self->{pbot}->{messagehistory}->{database}->get_message_account_id($mask); my $id = $self->{pbot}->{messagehistory}->{database}->get_message_account_id($mask);
if (defined $id) { if (defined $id) {
if ($id != $account) { if ($id != $account) {
$self->{pbot}->{logger}->log("Linking $mask [$id] to account $account\n"); $self->{pbot}->{logger}->log("Linking $mask [$id] to account $account\n");

View File

@ -182,11 +182,11 @@ sub register {
} }
# register subref # register subref
my $ref = $self->PBot::Registerable::register($subref); my $command = $self->PBot::Registerable::register($subref);
# update internal metadata # update internal metadata
$ref->{name} = lc $name; $command->{name} = lc $name;
$ref->{requires_cap} = $requires_cap // 0; $command->{requires_cap} = $requires_cap // 0;
# update command metadata # update command metadata
if (not $self->{metadata}->exists($name)) { if (not $self->{metadata}->exists($name)) {
@ -203,7 +203,7 @@ sub register {
$self->{pbot}->{capabilities}->add("can-$name", undef, 1); $self->{pbot}->{capabilities}->add("can-$name", undef, 1);
} }
return $ref; return $command;
} }
sub unregister { sub unregister {
@ -216,7 +216,7 @@ sub unregister {
sub exists { sub exists {
my ($self, $keyword) = @_; my ($self, $keyword) = @_;
$keyword = lc $keyword; $keyword = lc $keyword;
foreach my $ref (@{$self->{handlers}}) { return 1 if $ref->{name} eq $keyword; } foreach my $command (@{$self->{handlers}}) { return 1 if $command->{name} eq $keyword; }
return 0; return 0;
} }
@ -236,7 +236,6 @@ sub get_meta {
# see also PBot::Factoids::interpreter() for factoid commands # see also PBot::Factoids::interpreter() for factoid commands
sub interpreter { sub interpreter {
my ($self, $context) = @_; my ($self, $context) = @_;
my $result;
# debug flag to trace $context location and contents # debug flag to trace $context location and contents
if ($self->{pbot}->{registry}->get_value('general', 'debugcontext')) { if ($self->{pbot}->{registry}->get_value('general', 'debugcontext')) {
@ -246,25 +245,37 @@ sub interpreter {
$self->{pbot}->{logger}->log(Dumper $context); $self->{pbot}->{logger}->log(Dumper $context);
} }
# some convenient aliases
my $keyword = lc $context->{keyword}; my $keyword = lc $context->{keyword};
my $from = $context->{from}; my $from = $context->{from};
# set the channel the command is in reference to
my ($cmd_channel) = $context->{arguments} =~ m/\B(#[^ ]+)/; # assume command is invoked in regards to first channel-like argument my ($cmd_channel) = $context->{arguments} =~ m/\B(#[^ ]+)/; # assume command is invoked in regards to first channel-like argument
$cmd_channel = $from if not defined $cmd_channel; # otherwise command is invoked in regards to the channel the user is in $cmd_channel = $from if not defined $cmd_channel; # otherwise command is invoked in regards to the channel the user is in
$context->{channel} = $cmd_channel; $context->{channel} = $cmd_channel;
my $user = $self->{pbot}->{users}->find_user($cmd_channel, "$context->{nick}!$context->{user}\@$context->{host}"); # get the user's bot account
my $user = $self->{pbot}->{users}->find_user($cmd_channel, $context->{hostmask});
# check for a capability override
my $cap_override; my $cap_override;
if (exists $context->{'cap-override'}) { if (exists $context->{'cap-override'}) {
$self->{pbot}->{logger}->log("Override cap to $context->{'cap-override'}\n"); $self->{pbot}->{logger}->log("Override cap to $context->{'cap-override'}\n");
$cap_override = $context->{'cap-override'}; $cap_override = $context->{'cap-override'};
} }
foreach my $ref (@{$self->{handlers}}) { # go through all commands
if ($ref->{name} eq $keyword) { # TODO: maybe use a hash lookup
my $requires_cap = $self->get_meta($keyword, 'requires_cap') // $ref->{requires_cap}; foreach my $command (@{$self->{handlers}}) {
# is this the command
if ($command->{name} eq $keyword) {
# does this command require capabilities
my $requires_cap = $self->get_meta($keyword, 'requires_cap') // $command->{requires_cap};
if ($requires_cap) { if ($requires_cap) {
if (defined $cap_override) { if (defined $cap_override) {
if (not $self->{pbot}->{capabilities}->has($cap_override, "can-$keyword")) { if (not $self->{pbot}->{capabilities}->has($cap_override, "can-$keyword")) {
@ -272,9 +283,13 @@ sub interpreter {
} }
} else { } else {
if (not defined $user) { if (not defined $user) {
my ($found_chan, $found_mask) = $self->{pbot}->{users}->find_user_account($cmd_channel, "$context->{nick}!$context->{user}\@$context->{host}", 1); my ($found_chan, $found_mask) = $self->{pbot}->{users}->find_user_account($cmd_channel, $context->{hostmask}, 1);
if (not defined $found_chan) { return "/msg $context->{nick} You must have a user account to use $keyword. You may use the `my` command to create a personal user account. See `help my`."; }
else { return "/msg $context->{nick} You must have a user account in $cmd_channel to use $keyword. (You have an account in $found_chan.)"; } if (not defined $found_chan) {
return "/msg $context->{nick} You must have a user account to use $keyword. You may use the `my` command to create a personal user account. See `help my`.";
} else {
return "/msg $context->{nick} You must have a user account in $cmd_channel to use $keyword. (You have an account in $found_chan.)";
}
} elsif (not $user->{loggedin}) { } elsif (not $user->{loggedin}) {
return "/msg $context->{nick} You must be logged into your user account to use $keyword."; return "/msg $context->{nick} You must be logged into your user account to use $keyword.";
} }
@ -291,25 +306,43 @@ sub interpreter {
unless ($self->get_meta($keyword, 'dont-replace-pronouns')) { unless ($self->get_meta($keyword, 'dont-replace-pronouns')) {
$context->{arguments} = $self->{pbot}->{factoids}->expand_factoid_vars($context, $context->{arguments}); $context->{arguments} = $self->{pbot}->{factoids}->expand_factoid_vars($context, $context->{arguments});
$context->{arglist} = $self->{pbot}->{interpreter}->make_args($context->{arguments}); $context->{arglist} = $self->{pbot}->{interpreter}->make_args($context->{arguments});
} }
$context->{no_nickoverride} = 1; $self->{pbot}->{logger}->log("Disabling nickprefix\n");
$context->{nickprefix_disabled} = 1;
if ($self->get_meta($keyword, 'background-process')) { if ($self->get_meta($keyword, 'background-process')) {
my $timeout = $self->get_meta($keyword, 'process-timeout') // $self->{pbot}->{registry}->get_value('processmanager', 'default_timeout'); # execute this command as a backgrounded process
# set timeout to command metadata value
my $timeout = $self->get_meta($keyword, 'process-timeout');
# otherwise set timeout to default value
$timeout //= $self->{pbot}->{registry}->get_value('processmanager', 'default_timeout');
# execute command in background
$self->{pbot}->{process_manager}->execute_process( $self->{pbot}->{process_manager}->execute_process(
$context, $context,
sub { $context->{result} = $ref->{subref}->($context) }, sub { $context->{result} = $command->{subref}->($context) },
$timeout $timeout,
); );
return "";
# return no output since it will be handled by process manager
return '';
} else { } else {
my $result = $ref->{subref}->($context); # execute this command normally
my $result = $command->{subref}->($context);
# disregard undesired command output if command is embedded
return undef if $context->{referenced} and $result =~ m/(?:usage:|no results)/i; return undef if $context->{referenced} and $result =~ m/(?:usage:|no results)/i;
# return command output
return $result; return $result;
} }
} }
} }
return undef; return undef;
} }

View File

@ -1023,9 +1023,9 @@ sub execute_code_factoid_using_vm {
and $self->{factoids}->get_data($context->{channel}, $context->{keyword}, 'interpolate') eq '0') and $self->{factoids}->get_data($context->{channel}, $context->{keyword}, 'interpolate') eq '0')
{ {
if ($context->{code} =~ m/(?:\$\{?nick\b|\$\{?args\b|\$\{?arg\[)/ and length $context->{arguments}) { if ($context->{code} =~ m/(?:\$\{?nick\b|\$\{?args\b|\$\{?arg\[)/ and length $context->{arguments}) {
$context->{no_nickoverride} = 1; $context->{nickprefix_disabled} = 1;
} else { } else {
$context->{no_nickoverride} = 0; $context->{nickprefix_disabled} = 0;
} }
$context->{code} = $self->expand_factoid_vars($context, $context->{code}); $context->{code} = $self->expand_factoid_vars($context, $context->{code});
@ -1037,7 +1037,7 @@ sub execute_code_factoid_using_vm {
} }
} else { } else {
# otherwise allow nick overriding # otherwise allow nick overriding
$context->{no_nickoverride} = 0; $context->{nickprefix_disabled} = 0;
} }
# set up `compiler` module arguments # set up `compiler` module arguments
@ -1121,8 +1121,8 @@ sub interpreter {
if ($context->{arguments} =~ s/> ($nick_regex)$//) { if ($context->{arguments} =~ s/> ($nick_regex)$//) {
my $rcpt = $1; my $rcpt = $1;
if ($self->{pbot}->{nicklist}->is_present($context->{from}, $rcpt)) { if ($self->{pbot}->{nicklist}->is_present($context->{from}, $rcpt)) {
$context->{nickoverride} = $rcpt; $context->{nickprefix} = $rcpt;
$context->{force_nickoverride} = 1; $context->{nickprefix_forced} = 1;
} else { } else {
$context->{arguments} .= "> $rcpt"; $context->{arguments} .= "> $rcpt";
} }
@ -1327,10 +1327,8 @@ sub handle_action {
if ($action =~ m/\$\{?args/ or $action =~ m/\$\{?arg\[/) { if ($action =~ m/\$\{?args/ or $action =~ m/\$\{?arg\[/) {
unless (defined $self->{factoids}->get_data($channel, $keyword, 'interpolate') and $self->{factoids}->get_data($channel, $keyword, 'interpolate') eq '0') { unless (defined $self->{factoids}->get_data($channel, $keyword, 'interpolate') and $self->{factoids}->get_data($channel, $keyword, 'interpolate') eq '0') {
$action = $self->expand_action_arguments($action, $context->{arguments}, $context->{nick}); $action = $self->expand_action_arguments($action, $context->{arguments}, $context->{nick});
$context->{no_nickoverride} = 1;
} else {
$context->{no_nickoverride} = 0;
} }
$context->{arguments} = ""; $context->{arguments} = "";
$context->{original_arguments} = ""; $context->{original_arguments} = "";
} else { } else {
@ -1338,10 +1336,8 @@ sub handle_action {
my $target = $self->{pbot}->{nicklist}->is_present_similar($context->{from}, $context->{arguments}); my $target = $self->{pbot}->{nicklist}->is_present_similar($context->{from}, $context->{arguments});
if ($target and $action !~ /\$\{?(?:nick|args)\b/) { if ($target and $action !~ /\$\{?(?:nick|args)\b/) {
$context->{nickoverride} = $target unless $context->{force_nickoverride}; $context->{nickprefix} = $target unless $context->{nickprefix_forced};
$context->{no_nickoverride} = 0; $context->{nickprefix_disabled} = 0;
} else {
$context->{no_nickoverride} = 1;
} }
} }
} }
@ -1358,7 +1354,7 @@ sub handle_action {
$action = $self->expand_action_arguments($action, undef, $context->{nick}); $action = $self->expand_action_arguments($action, undef, $context->{nick});
} }
} }
$context->{no_nickoverride} = 0; $context->{nickprefix_disabled} = 0;
} }
# Check if it's an alias # Check if it's an alias

File diff suppressed because it is too large Load Diff

View File

@ -52,17 +52,27 @@ sub cmd_in_channel {
my ($self, $context) = @_; my ($self, $context) = @_;
my $usage = 'Usage: in <channel> <command>'; my $usage = 'Usage: in <channel> <command>';
return $usage if not length $context->{arguments};
if (not length $context->{arguments}) {
return $usage;
}
my ($channel, $command) = $self->{pbot}->{interpreter}->split_args($context->{arglist}, 2, 0, 1); my ($channel, $command) = $self->{pbot}->{interpreter}->split_args($context->{arglist}, 2, 0, 1);
return $usage if not defined $channel or not defined $command;
if (not defined $channel or not defined $command) {
return $usage;
}
# invoker must be present in that channel
if (not $self->{pbot}->{nicklist}->is_present($channel, $context->{nick})) { if (not $self->{pbot}->{nicklist}->is_present($channel, $context->{nick})) {
return "You must be present in $channel to do this."; return "You must be present in $channel to do this.";
} }
# update context with new channel and command
$context->{from} = $channel; $context->{from} = $channel;
$context->{command} = $command; $context->{command} = $command;
# perform the command and return the result
return $self->{pbot}->{interpreter}->interpret($context); return $self->{pbot}->{interpreter}->interpret($context);
} }

View File

@ -367,7 +367,7 @@ sub is_present {
} }
sub is_present_similar { sub is_present_similar {
my ($self, $channel, $nick, $similar) = @_; my ($self, $channel, $nick, $similarity) = @_;
$channel = lc $channel; $channel = lc $channel;
$nick = lc $nick; $nick = lc $nick;
@ -385,8 +385,8 @@ sub is_present_similar {
my $percentage; my $percentage;
if (defined $similar) { if (defined $similarity) {
$percentage = $similar; $percentage = $similarity;
} else { } else {
$percentage = $self->{pbot}->{registry}->get_value('interpreter', 'nick_similarity') // 0.20; $percentage = $self->{pbot}->{registry}->get_value('interpreter', 'nick_similarity') // 0.20;
} }

View File

@ -198,6 +198,7 @@ sub execute_process {
$timeout //= 30; # default timeout 30 seconds $timeout //= 30; # default timeout 30 seconds
# ensure contextual command history list is available for add_process()
if (not exists $context->{commands}) { if (not exists $context->{commands}) {
$context->{commands} = [$context->{command}]; $context->{commands} = [$context->{command}];
} }
@ -332,15 +333,16 @@ sub process_pipe_reader {
} }
# if nick isn't overridden yet, check for a potential nick prefix # if nick isn't overridden yet, check for a potential nick prefix
if (not defined $context->{nickoverride}) { # TODO: this stuff should be moved to Interpreter::output_result
if (not $context->{nickprefix}) {
# if add_nick is set on the factoid, set the nick override to the caller's nick # if add_nick is set on the factoid, set the nick override to the caller's nick
if (exists $context->{special} and $context->{special} ne 'code-factoid' if (exists $context->{special} and $context->{special} ne 'code-factoid'
and $self->{pbot}->{factoids}->{factoids}->exists($context->{channel}, $context->{trigger}, 'add_nick') and $self->{pbot}->{factoids}->{factoids}->exists($context->{channel}, $context->{trigger}, 'add_nick')
and $self->{pbot}->{factoids}->{factoids}->get_data($context->{channel}, $context->{trigger}, 'add_nick') != 0) and $self->{pbot}->{factoids}->{factoids}->get_data($context->{channel}, $context->{trigger}, 'add_nick') != 0)
{ {
$context->{nickoverride} = $context->{nick}; $context->{nickprefix} = $context->{nick};
$context->{no_nickoverride} = 0; $context->{nickprefix_disabled} = 0;
$context->{force_nickoverride} = 1; $context->{nickprefix_forced} = 1;
} else { } else {
# extract nick-like thing from process result # extract nick-like thing from process result
if ($context->{result} =~ s/^(\S+): //) { if ($context->{result} =~ s/^(\S+): //) {
@ -354,7 +356,7 @@ sub process_pipe_reader {
if ($present) { if ($present) {
# nick is present in channel # nick is present in channel
$context->{nickoverride} = $present; $context->{nickprefix} = $present;
} else { } else {
# nick not present, put it back on result # nick not present, put it back on result
$context->{result} = "$nick: $context->{result}"; $context->{result} = "$nick: $context->{result}";
@ -366,7 +368,7 @@ sub process_pipe_reader {
# send the result off to the bot to be handled # send the result off to the bot to be handled
$context->{checkflood} = 1; $context->{checkflood} = 1;
$self->{pbot}->{interpreter}->handle_result($context, $context->{result}); $self->{pbot}->{interpreter}->handle_result($context);
} }
1; 1;

View File

@ -68,6 +68,9 @@ sub initialize {
$self->add_default('text', 'irc', 'identify_password', $conf{identify_password} // ''); $self->add_default('text', 'irc', 'identify_password', $conf{identify_password} // '');
$self->add_default('text', 'irc', 'log_default_handler', 1); $self->add_default('text', 'irc', 'log_default_handler', 1);
# interpreter
$self->add_default('text', 'interpreter', 'max_embed', 3);
# make sensitive entries private # make sensitive entries private
$self->set_default('irc', 'SSL_ca_file', 'private', 1); $self->set_default('irc', 'SSL_ca_file', 'private', 1);
$self->set_default('irc', 'SSL_ca_path', 'private', 1); $self->set_default('irc', 'SSL_ca_path', 'private', 1);