3
0
mirror of https://github.com/pragma-/pbot.git synced 2024-11-20 02:49:49 +01:00

Factoids: Optimize find_factoid()

This commit is contained in:
Pragmatic Software 2020-02-26 02:32:22 -08:00
parent 91b2b1e7c7
commit 5d3dca94b9

View File

@ -282,6 +282,11 @@ sub find_factoid {
if ($debug) { if ($debug) {
use Data::Dumper; use Data::Dumper;
my $dump = Dumper \%opts; my $dump = Dumper \%opts;
$self->{pbot}->{logger}->log("+" x 32 . "\n");
use Devel::StackTrace;
my $trace = Devel::StackTrace->new(indent => 1, ignore_class => ['PBot::PBot', 'PBot::IRC']);
$self->{pbot}->{logger}->log("find_factoid stacktrace: " . $trace->as_string() . "\n");
$self->{pbot}->{logger}->log("find_factiod: from: $from, kw: $keyword, opts: $dump\n"); $self->{pbot}->{logger}->log("find_factiod: from: $from, kw: $keyword, opts: $dump\n");
} }
@ -289,31 +294,100 @@ sub find_factoid {
$from = lc $from; $from = lc $from;
$keyword = lc $keyword; $keyword = lc $keyword;
$self->{pbot}->{logger}->log("from: $from\n") if $debug;
my $arguments = $opts{arguments}; my $arguments = $opts{arguments};
my @result = eval { my @result = eval {
my @results; my @results;
for (my $depth = 0; $depth < 5; $depth++) { my ($channel, $trigger);
for (my $depth = 0; $depth < 15; $depth++) {
my $action;
my $string = $keyword . (length $arguments ? " $arguments" : ""); my $string = $keyword . (length $arguments ? " $arguments" : "");
$self->{pbot}->{logger}->log("string: $string\n") if $debug; $self->{pbot}->{logger}->log("string: $string\n") if $debug;
# check factoids if ($opts{exact_channel} and $opts{exact_trigger}) {
foreach my $channel (sort $self->{factoids}->get_keys) { if ($self->{factoids}->exists($from, $keyword)) {
if ($opts{exact_channel}) { ($channel, $trigger) = ($from, $keyword);
if ($opts{exact_trigger} == 1) { next unless $from eq lc $channel; } goto CHECK_ALIAS;
else { next unless $from eq lc $channel or $channel eq '.*'; }
} }
foreach my $trigger ($self->{factoids}->get_keys($channel)) { if ($opts{exact_trigger} > 1 and $self->{factoids}->exists('.*', $keyword)) {
if ($keyword eq $trigger) { ($channel, $trigger) = ('.*', $keyword);
$self->{pbot}->{logger}->log("return $channel: $trigger\n") if $debug; goto CHECK_ALIAS;
}
if ($opts{find_alias} && $self->{factoids}->get_data($channel, $trigger, 'action') =~ /^\/call\s+(.*)$/ms) { goto CHECK_REGEX;
my $command; }
if (length $arguments) { $command = "$1 $arguments"; }
else { $command = $1; } if ($opts{exact_channel} and not $opts{exact_trigger}) {
if (not $self->{factoids}->exists($from, $keyword)) {
goto CHECK_REGEX if $from eq '.*';
goto CHECK_REGEX if not $self->{factoids}->exists('.*', $keyword);
($channel, $trigger) = ('.*', $keyword);
goto CHECK_ALIAS;
}
($channel, $trigger) = ($from, $keyword);
goto CHECK_ALIAS;
}
if (not $opts{exact_channel}) {
my $factoids = $self->{factoids}->get_all_by_trigger($keyword);
foreach my $factoid (@$factoids) {
$channel = $factoid->{index1};
$trigger = $factoid->{index2};
$action = $factoid->{action};
if ($opts{find_alias} && $action =~ m{^/call\s+(.*)$}ms) {
goto CHECK_ALIAS;
}
push @results, [$channel, $trigger];
}
goto CHECK_REGEX;
}
CHECK_ALIAS:
if ($opts{find_alias}) {
$action = $self->{factoids}->get_data($channel, $trigger, 'action') if not defined $action;
if ($action =~ m{^/call\s+(.*)$}ms) {
my $command;
if (length $arguments) {
$command = "$1 $arguments";
} else {
$command = $1;
}
my $arglist = $self->{pbot}->{interpreter}->make_args($command);
($keyword, $arguments) = $self->{pbot}->{interpreter}->split_args($arglist, 2, 0, 1);
goto NEXT_DEPTH;
}
}
if ($opts{exact_channel} == 1) {
return ($channel, $trigger);
} else {
push @results, [$channel, $trigger];
}
CHECK_REGEX:
if (not $opts{exact_trigger} and defined $trigger) {
my $factoids;
if ($opts{exact_channel}) {
$factoids = $self->{factoids}->get_regex_by_channel($channel);
} else {
$factoids = $self->{factoids}->get_regex_by_channel(undef);
}
my $regex = qr/$trigger/i;
foreach my $factoid (@$factoids) {
if ($string =~ /$regex/) {
$channel = $factoid->{index1};
$trigger = $factoid->{index2};
$action = $factoid->{action};
if ($opts{find_alias}) {
my $command = $action;
my $arglist = $self->{pbot}->{interpreter}->make_args($command); my $arglist = $self->{pbot}->{interpreter}->make_args($command);
($keyword, $arguments) = $self->{pbot}->{interpreter}->split_args($arglist, 2, 0, 1); ($keyword, $arguments) = $self->{pbot}->{interpreter}->split_args($arglist, 2, 0, 1);
goto NEXT_DEPTH; goto NEXT_DEPTH;
@ -325,33 +399,8 @@ sub find_factoid {
} }
} }
# then check regex factoids # match not found
if (not $opts{exact_trigger}) { last;
foreach my $channel ($self->{factoids}->get_keys) {
if ($opts{exact_channel}) { next unless $from eq lc $channel or $channel eq '.*'; }
foreach my $trigger (sort $self->{factoids}->get_keys($channel)) {
next if $trigger eq '_name';
if ($self->{factoids}->get_data($channel, $trigger, 'type') eq 'regex') {
$self->{pbot}->{logger}->log("checking regex $string =~ m/$trigger/i\n") if $debug >= 2;
if ($string =~ m/$trigger/i) {
$self->{pbot}->{logger}->log("return regex $channel: $trigger\n") if $debug;
if ($opts{find_alias}) {
my $command = $self->{factoids}->get_data($channel, $trigger, 'action');
my $arglist = $self->{pbot}->{interpreter}->make_args($command);
($keyword, $arguments) = $self->{pbot}->{interpreter}->split_args($arglist, 2, 0, 1);
$string = $keyword . (length $arguments ? " $arguments" : "");
goto NEXT_DEPTH;
}
if ($opts{exact_channel} == 1) { return ($channel, $trigger); }
else { push @results, [$channel, $trigger]; }
}
}
}
}
}
NEXT_DEPTH: NEXT_DEPTH:
last if not $opts{find_alias}; last if not $opts{find_alias};
@ -367,7 +416,7 @@ sub find_factoid {
}; };
if ($@) { if ($@) {
$self->{pbot}->{logger}->log("find_factoid: bad regex: $@\n"); $self->{pbot}->{logger}->log("Error in find_factoid: $@\n");
return undef; return undef;
} }
@ -732,37 +781,27 @@ sub interpreter {
if (not defined $keyword) { if (not defined $keyword) {
my $string = "$original_keyword $stuff->{arguments}"; my $string = "$original_keyword $stuff->{arguments}";
my $lc_keyword = lc $original_keyword; my @chanlist = ();
my $comma = "";
my $found = 0;
my $chans = "";
my ($fwd_chan, $fwd_trig); my ($fwd_chan, $fwd_trig);
# build string of which channels contain the keyword, keeping track of the last one and count # build list of which channels contain the keyword, keeping track of the last one and count
foreach my $chan ($self->{factoids}->get_keys) { foreach my $factoid ($self->{factoids}->get(index2 => $original_keyword, index1 => undef, type => undef)) {
foreach my $trig ($self->{factoids}->get_keys($chan)) { next if $factoid->{type} ne 'text' and $factoid->{type} ne 'module';
my $type = $self->{factoids}->get_data($chan, $trig, 'type'); push @chanlist, $self->{factoids}->get_data($factoid->{index1}, '_name');
if (($type eq 'text' or $type eq 'module') and $trig eq $lc_keyword) { $fwd_chan = $factoid->{index1};
$chans .= $comma . $self->{factoids}->get_data($chan, '_name'); $fwd_trig = $original_keyword;
$comma = ", ";
$found++;
$fwd_chan = $chan;
$fwd_trig = $trig;
last;
}
}
} }
my $ref_from = $stuff->{ref_from} ? "[$stuff->{ref_from}] " : ""; my $ref_from = $stuff->{ref_from} ? "[$stuff->{ref_from}] " : "";
# if multiple channels have this keyword, then ask user to disambiguate # if multiple channels have this keyword, then ask user to disambiguate
if ($found > 1) { if (@chanlist> 1) {
return undef if $stuff->{referenced}; return undef if $stuff->{referenced};
return $ref_from . "Ambiguous keyword '$original_keyword' exists in multiple channels (use 'fact <channel> $original_keyword' to choose one): $chans"; return $ref_from . "Ambiguous keyword '$original_keyword' exists in multiple channels (use 'fact <channel> $original_keyword' to choose one): " . join(' ,', @chanlist);
} }
# if there's just one other channel that has this keyword, trigger that instance # if there's just one other channel that has this keyword, trigger that instance
elsif ($found == 1) { elsif (@chanlist == 1) {
$pbot->{logger}->log("Found '$original_keyword' as '$fwd_trig' in [$fwd_chan]\n"); $pbot->{logger}->log("Found '$original_keyword' as '$fwd_trig' in [$fwd_chan]\n");
$stuff->{keyword} = $fwd_trig; $stuff->{keyword} = $fwd_trig;
$stuff->{interpret_depth}++; $stuff->{interpret_depth}++;
@ -837,12 +876,14 @@ sub interpreter {
} }
} }
my $data = $self->{factoids}->get_data($channel, $keyword); my $ref_count = $self->{factoids}->get_data($channel, $keyword, 'ref_count');
$data->{ref_count}++; my $update_data = {
$data->{ref_user} = "$stuff->{nick}!$stuff->{user}\@$stuff->{host}"; ref_count => ++$ref_count,
$data->{last_referenced_on} = gettimeofday; ref_user => "$stuff->{nick}!$stuff->{user}\@$stuff->{host}",
$data->{last_referenced_in} = $stuff->{from} || "stdin"; last_referenced_on => scalar gettimeofday,
$self->{factoids}->add($channel, $keyword, $data, 1, 1); last_referenced_in => $stuff->{from} || 'stdin',
};
$self->{factoids}->add($channel, $keyword, $update_data, 1, 1);
my $action; my $action;