aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZoffix Znet <cpan@zoffix.com>2016-07-29 14:17:03 -0400
committerZoffix Znet <cpan@zoffix.com>2016-07-29 14:17:03 -0400
commitce4d8ae87d738e47058b97e288848a66d282da03 (patch)
tree5b205a6c372f9010dfbe41fe6ff76111c7822765
parentb0a57d2185632c0b8f3c33ca4b061bf9778d2cca (diff)
Blarg
-rw-r--r--docs/03-method-reference.md26
-rw-r--r--lib/IRC/Client.pm699
-rw-r--r--lib/IRC/Client/Message.pm612
3 files changed, 87 insertions, 50 deletions
diff --git a/docs/03-method-reference.md b/docs/03-method-reference.md
index 01f25b6..85e86e4 100644
--- a/docs/03-method-reference.md
+++ b/docs/03-method-reference.md
@@ -5,7 +5,7 @@
This document describes events available on various objects in use when working
with `IRC::Client`.
-## Message Objects
+## Message Objects (`IRC::Client::Message` and subclasses)
All event handlers (except for special `irc-started`) receive one positional
argument that does `IRC::Client::Message` role and is refered to as
@@ -66,6 +66,9 @@ with a safe-method-call operator (`.?`):
#### `IRC::Client::Message`
+Object is never sent to event handlers and merely provides commonality to
+its subclasses.
+
##### `.irc`
Contains the `IRC::Client` object.
@@ -379,32 +382,37 @@ The "real name" of our client.
Affects stringification of the object and makes it stringify to the value
of `.label` attribute.
-#### `.current-nick`
+#### Writable Non-Writable Attributes
+
+The following attributes are writable, however, they are written to by
+the internals and the behaviour when writing to them directly is undefined.
+
+##### `.current-nick`
Writable attribute. Our currently-used nick. Will be one of the nicks returned
-by `.nicks`. **Warning: this attribute is not meant to be used directly.**
+by `.nicks`.
-#### `.is-connected`
+##### `.is-connected`
Writable `Bool` attribute. Indicates whether we're currently in a state
where the server considers us connected. This defaults to `False`, then is set
to `True` when the server sends us `001` IRC command and set back to `False`
when the socket connection breaks.
-**Warning: this attribute is not meant to be used directly.**
-#### `.has-quit`
+##### `.has-quit`
Writable `Bool` attribute. Set to `True` when `.quit` method is called
on the Client Object and is used by the socket herder to determine whether
or not the socket connection was cut intentionally.
-**Warning: this attribute is not meant to be used directly.**
-#### `.has-quit`
+##### `.has-quit`
Writable `IO::Socket::Async` attribute. Contains an object representing
the socket connected to the server, although it may already be closed.
-**Warning: this attribute is not meant to be used directly.**
+---
+
+## Client Object (`IRC::Client`)
## Up Next
Read [the method reference](03-method-reference.md) next.
diff --git a/lib/IRC/Client.pm6 b/lib/IRC/Client.pm6
index 419a0f0..66f1cd1 100644
--- a/lib/IRC/Client.pm6
+++ b/lib/IRC/Client.pm6
@@ -1,9 +1,16 @@
unit class IRC::Client;
+use IRC::Client::Message;
use IRC::Client::Grammar;
use IRC::Client::Server;
use IRC::Client::Grammar::Actions;
+trusts IRC::Client::Message::Ping;
+trusts IRC::Client::Message::Privmsg::Channel;
+trusts IRC::Client::Message::Privmsg::Me;
+trusts IRC::Client::Message::Notice::Channel;
+trusts IRC::Client::Message::Notice::Me;
+
my class IRC_FLAG_NEXT {};
role IRC::Client::Plugin is export {
@@ -65,7 +72,7 @@ submethod BUILD (
}
method join (*@channels, :$server) {
- self.send-cmd: 'JOIN', $_, :$server for @channels;
+ self!send-cmd: 'JOIN', $_, :$server for @channels;
self;
}
@@ -73,19 +80,19 @@ method nick (*@nicks, :$server = '*') {
@nicks = @nicks.map: { $_ ~ '_' x $++ } if @nicks == 1;
self!set-server-attr($server, 'nick', @nicks);
self!set-server-attr($server, 'current-nick', @nicks[0]);
- self.send-cmd: 'NICK', @nicks[0], :$server;
+ self!send-cmd: 'NICK', @nicks[0], :$server;
self;
}
method part (*@channels, :$server) {
- self.send-cmd: 'PART', $_, :$server for @channels;
+ self!send-cmd: 'PART', $_, :$server for @channels;
self;
}
method quit (:$server = '*') {
if $server eq '*' { .has-quit = True for %!servers.values; }
else { self!get-server($server).has-quit = True; }
- self.send-cmd: 'QUIT', :$server;
+ self!send-cmd: 'QUIT', :$server;
self;
}
@@ -121,7 +128,7 @@ method run {
method send (:$where!, :$text!, :$server, :$notice) {
for $server || |%!servers.keys.sort {
if self!get-server($server).is-connected {
- self.send-cmd: $notice ?? 'NOTICE' !! 'PRIVMSG', $where, $text,
+ self!send-cmd: $notice ?? 'NOTICE' !! 'PRIVMSG', $where, $text,
:server($_);
}
else {
@@ -134,36 +141,6 @@ method send (:$where!, :$text!, :$server, :$notice) {
self;
}
-method send-cmd ($cmd, *@args is copy, :$prefix = '', :$server) {
- if $cmd eq 'NOTICE'|'PRIVMSG' {
- my ($where, $text) = @args;
- if @!filters
- and my @f = @!filters.grep({
- .signature.ACCEPTS: \($text)
- or .signature.ACCEPTS: \($text, :$where)
- })
- {
- start {
- CATCH { default { warn $_; warn .backtrace } }
- for @f -> $f {
- given $f.signature.params.elems {
- when 1 { $text = $f($text); }
- when 2 { ($text, $where) = $f($text, :$where) }
- }
- }
- self!ssay: :$server, join ' ', $cmd, $where, ":$prefix$text";
- }
- }
- else {
- self!ssay: :$server, join ' ', $cmd, $where, ":$prefix$text";
- }
- }
- else {
- @args[*-1] = ':' ~ @args[*-1] if @args;
- self!ssay: :$server, join ' ', $cmd, @args;
- }
-}
-
###############################################################################
###############################################################################
###############################################################################
@@ -171,6 +148,25 @@ method send-cmd ($cmd, *@args is copy, :$prefix = '', :$server) {
###############################################################################
###############################################################################
+method !change-nick ($server) {
+ my $idx = 0;
+ for $server.nick.kv -> $i, $n {
+ next unless $n eq $server.current-nick;
+ $idx = $i + 1;
+ $idx = 0 if $idx == $server.nick.elems;
+ };
+ if $idx == 0 {
+ Promise.in(10).then: {
+ $server.current-nick = $server.nick[$idx];
+ self!send-cmd: "NICK $server.current-nick()", :$server;
+ }
+ }
+ else {
+ $server.current-nick = $server.nick[$idx];
+ self!send-cmd: "NICK $server.current-nick()", :$server;
+ }
+}
+
method !connect-socket ($server) {
$!debug and debug-print 'Attempting to connect to server', :out, :$server;
IO::Socket::Async.connect($server.host, $server.port).then: sub ($prom) {
@@ -223,7 +219,8 @@ method !handle-event ($e) {
$s.current-nick = $e.args[0];
self!ssay: "JOIN $_", :server($s) for |$s.channels;
}
- when 'PING' { return $e.reply; }
+ when 'PING' { return $e.reply; }
+ when '433'|'432' { self!change-nick($s); }
}
my $event-name = 'irc-' ~ $e.^name.subst('IRC::Client::Message::', '')
@@ -310,6 +307,36 @@ method !get-server ($server is copy) {
return %!servers{$server};
}
+method !send-cmd ($cmd, *@args is copy, :$prefix = '', :$server) {
+ if $cmd eq 'NOTICE'|'PRIVMSG' {
+ my ($where, $text) = @args;
+ if @!filters
+ and my @f = @!filters.grep({
+ .signature.ACCEPTS: \($text)
+ or .signature.ACCEPTS: \($text, :$where)
+ })
+ {
+ start {
+ CATCH { default { warn $_; warn .backtrace } }
+ for @f -> $f {
+ given $f.signature.params.elems {
+ when 1 { $text = $f($text); }
+ when 2 { ($text, $where) = $f($text, :$where) }
+ }
+ }
+ self!ssay: :$server, join ' ', $cmd, $where, ":$prefix$text";
+ }
+ }
+ else {
+ self!ssay: :$server, join ' ', $cmd, $where, ":$prefix$text";
+ }
+ }
+ else {
+ @args[*-1] = ':' ~ @args[*-1] if @args;
+ self!ssay: :$server, join ' ', $cmd, @args;
+ }
+}
+
method !set-server-attr ($server, $method, $what) {
if $server ne '*' {
%!servers{$server}."$method"() = $what;
diff --git a/lib/IRC/Client/Message.pm6 b/lib/IRC/Client/Message.pm6
index 89295e3..a62972d 100644
--- a/lib/IRC/Client/Message.pm6
+++ b/lib/IRC/Client/Message.pm6
@@ -28,7 +28,7 @@ role Unknown does M {
}
role Ping does M {
- method reply { $.irc.send-cmd: 'PONG', $.args, :$.server; }
+ method reply { $.irc!IRC::Client::send-cmd: 'PONG', $.args, :$.server; }
}
role Privmsg does M {
@@ -39,13 +39,14 @@ role Privmsg does M {
role Privmsg::Channel does Privmsg {
has $.channel;
method reply ($text, :$where) {
- $.irc.send-cmd: 'PRIVMSG', $where // $.channel, $text,
+ $.irc!IRC::Client::send-cmd: 'PRIVMSG', $where // $.channel, $text,
:$.server, :prefix("$.nick, ");
}
}
role Privmsg::Me does Privmsg {
method reply ($text, :$where) {
- $.irc.send-cmd: 'PRIVMSG', $where // $.nick, $text, :$.server;
+ $.irc!IRC::Client::send-cmd: 'PRIVMSG', $where // $.nick, $text,
+ :$.server;
}
}
@@ -57,14 +58,15 @@ role Notice does M {
role Notice::Channel does Notice {
has $.channel;
method reply ($text, :$where) {
- $.irc.send-cmd: 'NOTICE', $where // $.channel, $text,
+ $.irc!IRC::Client::send-cmd: 'NOTICE', $where // $.channel, $text,
:$.server, :prefix("$.nick, ");
$.replied = True;
}
}
role Notice::Me does Notice {
method reply ($text, :$where) {
- $.irc.send-cmd: 'NOTICE', $where // $.nick, $text, :$.server;
+ $.irc!IRC::Client::send-cmd: 'NOTICE', $where // $.nick, $text,
+ :$.server;
$.replied = True;
}
}