From af07017fa1a743252d8983d522aca787b05ca342 Mon Sep 17 00:00:00 2001 From: dakkar Date: Mon, 31 May 2021 16:43:45 +0100 Subject: track who's an op --- boha.raku | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 5 deletions(-) diff --git a/boha.raku b/boha.raku index 725f00a..97240ba 100644 --- a/boha.raku +++ b/boha.raku @@ -7,15 +7,85 @@ my $config = from-toml( file => (%*ENV // $?FILE.IO.sibling('boha.toml').Str) ); +role TracksOps does IRC::Client::Plugin { + has %!nick-cache; + has $!waiting-for-names = False; + + method !check-op($e) { + return Promise.broken('not a channel message') unless $e.?channel; + # if we already know whether that's an op, the cache will + # contain a kept promise; if we don't, we have to wait for the + # next 353, so we set and return a planned promise + return %!nick-cache{$e.channel}{$e.nick} //= Promise.new(); + } + + # response to /NAMES + method irc-n353($e) { + my ($my-nick,$equal,$channel,$names) = $e.args(); + + for $names.split(/\s+/) -> $name-str { + my $user = $name-str ~~ / ^ $ = [ '@' | '+' ]? $ = [ .+ ] $ /; + + # I'm not sure what `+` means + my $is-op = $user eq '@'; + + my $value := %!nick-cache{$channel}{$user}; + if $value ~~ Promise && $value.status ~~ Planned { + # someone called check-op before we saw this nick: + # keep the promise + $value.keep($is-op); + } + else { + # either this nick changed state, or nobody asked + # about it before: set a kept promise + $value = Promise.kept($is-op); + } + } + + $!waiting-for-names = False; + + return $.NEXT; + } + + method irc-join($e) { + # someone (maybe us) joined the channel: update our ops map + # + # maybe we should do this every few seconds anyway… + Promise.in(5).then: { + unless ($!waiting-for-names) { + $e.irc.send-cmd('NAMES', $e.channel, :server($e.server)); + $!waiting-for-names = True; + } + }; + return $.NEXT; + } +} + +class Boha1 does TracksOps { + # irc-addressed for in-channel messages + # irc-privmsg-me for direct messages + + method irc-addressed($e) { + return self!check-op($e).then: sub ($promise) { + if ($promise.status ~~ Broken) { + # not a channel message? + return Nil; + } + if (so $promise.result) { + return "you're an op"; + } + else { + return "you're a normal user"; + } + }; + } +} + .run with IRC::Client.new( |($config), channels => $config.map(*.), :debug, :plugins( - class :: does IRC::Client::Plugin { - # irc-addressed for in-channel messages - # irc-privmsg-me for direct messages - method irc-to-me($e) { "Boo!" } - }, + Boha1.new, ), ); -- cgit v1.2.3