#! /usr/bin/env false use v6.d; use IRC::Client::Message; use IRC::Client::Plugin; use Log; #| This class handles incoming messages, formats a context from them and #| dispatches it on to any registered plugin that can handle it. unit class IRC::Client::Handler; #| Handle numeric commands. multi method handle ( $event where { $_.command ~~ / \d ** 3/ }, ) { my @events; # Special cases for IRC::Client @events.append('irc-connected' => $event.irc) if $event.command eq '001'; @events.append('irc-ready' => $event.irc) if $event.command eq '376'; @events.append('irc-ready' => $event.irc) if $event.command eq '422'; # Regular events, handles in the regular way @events.append("irc-n{$event.command}" => $event); @events.append('irc-numeric' => $event); @events.append('irc-all' => $event); self.dispatch(@events, $event.irc); } #| Handle PRIVMSG and NOTICE commands. multi method handle ( $event where { $_.command ∈ } ) { my @events; my $stripped; # If the message starts with the name of the client, it should dispatch # an irc-addressed event. if ($event.params[*-1] ~~ / ^ ( "{$event.irc.nick}" <[:;,]> <.ws> ) /) { $stripped = $event.set-param(*-1, $event.params[*-1].substr($0.chars)); } # A private message to the client should dispatch an irc-to-me event, # optionally stripping away the client's current nickname from the # start. if ($event.params[0] eq $event.irc.nick) { @events.append('irc-to-me' => $stripped // $event); } # A message to a public channel prefixed with the client's current # nickname is both an irc-to-me event, and an irc-addressed event. if ($event.params[0] ne $event.irc.nick && $stripped) { @events.append('irc-to-me' => $stripped); @events.append('irc-addressed' => $stripped); } @events.append("irc-{$event.command.fc}-me" => $event) if $event.params[0] eq $event.irc.nick; @events.append('irc-mentioned' => $event) if $event.params[*-1].words ∋ $event.irc.nick; @events.append("irc-{$event.command.fc}-channel" => $event) if $event.params[0] ~~ / ^ <[#&]> /; @events.append("irc-{$event.command.fc}" => $event); @events.append('irc-all' => $event); self.dispatch(@events, $event.irc); } #| Handle MODE commands. multi method handle ( $event where { $_.command eq 'MODE' } ) { my @events; @events.append('irc-mode-me' => $event) if $event.params[0] eq $event.irc.nick; @events.append('irc-mode-channel' => $event) if $event.params[0] ~~ / ^ <[#&]> /; @events.append('irc-mode' => $event); @events.append('irc-all' => $event); self.dispatch(@events, $event.irc); } #| Handle all IRC commands. Note that the order in which events are appended #| does matter, the most "narrow" event should always come first, getting #| broader as we go down the list. multi method handle ( $event, ) { my @events; @events.append("irc-{$event.command.fc}" => $event); @events.append('irc-all' => $event); self.dispatch(@events, $event.irc); } #| Dispatch the message to all plugins. method dispatch ( @events, $client, #= IRC::Client, but can't `use` this due to circular references ) { my @plugins = $client.plugins; # Loop over all the plugins, and dispatch to each of them on a seperate # thread. This allows plugins to take their sweet time, while not being # in any other plugins' way. for $client.plugins -> $plugin { start { CATCH { default { my $exception = $_; .emergency($exception.gist.lines.map(*.trim-trailing).join("\n")) with $Log::instance; } } self.dispatch-plugin(@events, $plugin) } } } #| Dispatch the message to all plugin methods that can handle them. method dispatch-plugin ( @events, IRC::Client::Plugin $plugin, ) { for @events -> $event { my $method = $event.key; my $payload = $event.value; # Check for available methods to handle this payload. my @methods = $plugin.^can($method) .map(*.candidates) .flat .grep(*.cando(\($plugin, $payload))) ; # Nothing to do if nothing was found. next unless @methods; .debug("Dispatching to {$plugin.^name}.$method") with $Log::instance; my $response = $plugin."$method"($payload); next unless $payload ~~ IRC::Client::Message; # Depending on the return value of the method, something can be # done. given ($response) { when Str { $payload.reply($response); last; } } } } =begin pod =NAME IRC::Client::Handler =AUTHOR Patrick Spek <~tyil/raku-devel@lists.sr.ht> =VERSION 0.0.0 =head1 Synopsis =head1 Description =head1 Examples =head1 See also =end pod # vim: ft=perl6 noet