Skip to content

Commit

Permalink
Make it more readable.
Browse files Browse the repository at this point in the history
  • Loading branch information
Crab Qiu committed Jun 11, 2012
1 parent f5db13e commit f150778
Showing 1 changed file with 153 additions and 150 deletions.
303 changes: 153 additions & 150 deletions lib/Net/IRC/Bot.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,155 +4,158 @@ use Net::IRC::Parser;
use Net::IRC::Event;

class Net::IRC::Bot {
has $conn is rw;

#Set some sensible defaults for the bot.
#These are not stored as state, they are just used for the bot's "start state"
#Changing things like $nick and @channels are tracked in %state
has $.nick = "Rakudobot";
has @.altnicks = $!nick X~ ("_","__",^10);
has $.username = "Clunky";
has $.realname = '$@%# yeah, perl 6!';

has $.server = "irc.perl.org";
has $.port = 6667;
has $.password;

has @.channels = [];

#Most important part of the bot.
has @.modules;
#Options
has $.debug = False;

#State variables.
#TODO: Make this an object for cleaner syntax.
has %state is rw;

#submethod BUILD {
# @!modules.push(Net::IRC::DefaultHandlers.new);
#}

method !resetstate() {
%state = (
nick => $.nick,
altnicks => @.altnicks,
autojoin => @.channels,
channels => %(),
loggedin => False,
connected => False,
)
}

method !connect(){
#Establish connection to server
self!resetstate;
say "Connecting to $.server on port $.port";
$conn = IO::Socket::INET.new(host => $.server, port => $.port)
but role {
method sendln(Str $string){self.send($string~"\c13\c10")}
};

#Send PASS if needed
$conn.sendln("PASS $.password") if $.password;

#Send NICK & USER.
#If the nick collides, we'll resend a new one when we recieve the error later.
#USER Parameters: <username> <hostname> <servername> <realname>
$conn.sendln("NICK $.nick");
$conn.sendln("USER $.username abc.xyz.net $.server :$.realname");
%state<connected> = True;
}

method !disconnect($quitmsg = "Leaving"){
if %state<connected> {
$conn.sendln("QUIT :$quitmsg");
$conn.close;
}
}


method run() {
self!disconnect;
self!connect;
loop {
#XXX: Support for timed events?
my $line = $conn.get
or die "Connection error.";

my $event = Net::IRC::Parser::RawEvent.parse($line)
or $*ERR.say("Could not parse the following IRC event: $line") and next;

say ~$event if $.debug;
self!dispatch($event);
}
}

method !dispatch($raw) {
#Make an event object and fill it as much as we can.
#XXX: Should I just use a single cached Event to save memory?
my $who = ($raw<user> || $raw<server> || "");
$who does role { method Str { self<nick>.Str || self<host>.Str } }

#XXX Stupid workaround.
my $l = $raw<params>.elems;

my $event = Net::IRC::Event.new(
:raw($raw),
:command(~$raw<command>),
:conn($conn),
:state(%state),
:who($who),
:where(~$raw<params>[0]),
:what(~$raw<params>[$l ?? $l-1 !! 0]),
);


# Dispatch to the raw event handlers.
@.modules>>.*"irc_{ lc $event.command }"($event);
given uc $event.command {
when "PRIVMSG" {
#Check to see if its a CTCP request.
if $event.what ~~ /^\c01 (.*) \c01$/ {
my $text = ~$0;
if $.debug {
say "Received CTCP $text from {$event.who}" ~
( $event.where eq $event.who ?? '.' !! " (to channel {$event.where})." );
}

$text ~~ /^ (.+?) [<.ws> (.*)]? $/;
$event.what = $1 && ~$1;
@.modules>>.*"ctcp_{ lc $0 }"($event);
#If its a CTCP ACTION then we also call 'emoted'
@.modules>>.*emoted($event) if uc $0 eq 'ACTION';
}
else {
@.modules>>.*said($event);
}
}

when "NOTICE" {
@.modules>>.*noticed($event);
}

when "KICK" {
$event.what = $raw<params>[1];
@.modules>>.*kicked($event);
}

when "JOIN" {
@.modules>>.*joined($event);
}

when "NICK" {
@.modules>>.*nickchange($event);
}

when "376"|"422" {
#End of motd / no motd. (Usually) The last thing a server sends the client on connect.
@.modules>>.*connected($event)
}
}
}
has $conn is rw;

#Set some sensible defaults for the bot.
#These are not stored as state, they are just used for the bot's "start state"
#Changing things like $nick and @channels are tracked in %state
has $.nick = "Rakudobot";
has @.altnicks = $!nick X~ ("_","__",^10);
has $.username = "Clunky";
has $.realname = '$@%# yeah, perl 6!';

has $.server = "irc.perl.org";
has $.port = 6667;
has $.password;

has @.channels = [];

#Most important part of the bot.
has @.modules;
#Options
has $.debug = False;

#State variables.
#TODO: Make this an object for cleaner syntax.
has %state is rw;

#submethod BUILD {
# @!modules.push(Net::IRC::DefaultHandlers.new);
#}

method !resetstate() {
%state = (
nick => $.nick,
altnicks => @.altnicks,
autojoin => @.channels,
channels => %(),
loggedin => False,
connected => False,
)
}

method !connect(){
#Establish connection to server
self!resetstate;
say "Connecting to $.server on port $.port";
$conn = IO::Socket::INET.new(host => $.server, port => $.port)
but role {
method sendln(Str $string) {
self.send($string~"\c13\c10")
}
};

#Send PASS if needed
$conn.sendln("PASS $.password") if $.password;

#Send NICK & USER.
#If the nick collides, we'll resend a new one when we recieve the error later.
#USER Parameters: <username> <hostname> <servername> <realname>
$conn.sendln("NICK $.nick");
$conn.sendln("USER $.username abc.xyz.net $.server :$.realname");
%state<connected> = True;
}

method !disconnect($quitmsg = "Leaving") {
if %state<connected> {
$conn.sendln("QUIT :$quitmsg");
$conn.close;
}
}


method run() {
self!disconnect;
self!connect;
loop {
#XXX: Support for timed events?
my $line = $conn.get
or die "Connection error.";

my $event = Net::IRC::Parser::RawEvent.parse($line)
or $*ERR.say("Could not parse the following IRC event: $line") and next;

say ~$event if $.debug;
self!dispatch($event);
}
}

method !dispatch($raw) {
#Make an event object and fill it as much as we can.
#XXX: Should I just use a single cached Event to save memory?
my $who = ($raw<user> || $raw<server> || "");
$who does role { method Str { self<nick>.Str || self<host>.Str } }

#XXX Stupid workaround.
my $l = $raw<params>.elems;

my $event = Net::IRC::Event.new(
:raw($raw),
:command(~$raw<command>),
:conn($conn),
:state(%state),
:who($who),
:where(~$raw<params>[0]),
:what(~$raw<params>[$l ?? $l-1 !! 0]),
);


# Dispatch to the raw event handlers.
@.modules>>.*"irc_{ lc $event.command }"($event);
given uc $event.command {
when "PRIVMSG" {
#Check to see if its a CTCP request.
if $event.what ~~ /^\c01 (.*) \c01$/ {
my $text = ~$0;
if $.debug {
say "Received CTCP $text from {$event.who}" ~
( $event.where eq $event.who ?? '.' !! " (to channel {$event.where})." );
}

$text ~~ /^ (.+?) [<.ws> (.*)]? $/;
$event.what = $1 && ~$1;
@.modules>>.*"ctcp_{ lc $0 }"($event);
#If its a CTCP ACTION then we also call 'emoted'
@.modules>>.*emoted($event) if uc $0 eq 'ACTION';
}
else {
@.modules>>.*said($event);
}
}

when "NOTICE" {
@.modules>>.*noticed($event);
}

when "KICK" {
$event.what = $raw<params>[1];
@.modules>>.*kicked($event);
}

when "JOIN" {
@.modules>>.*joined($event);
}

when "NICK" {
@.modules>>.*nickchange($event);
}

when "376"|"422" {
#End of motd / no motd. (Usually) The last thing a server sends the client on connect.
@.modules>>.*connected($event)
}
}
}
}

# vim: ft=perl6 sw=4 expandtab

0 comments on commit f150778

Please sign in to comment.