package Morris::Connection;
use Moose;
use AnyEvent::IRC::Client;
use Morris::Message;
use namespace::clean -except => qw(meta);
has hooks => (
traits => ['Hash'],
is => 'ro',
isa => 'HashRef',
lazy_build => 1,
handles => {
get_hook => 'get',
}
);
has irc => (
is => 'rw',
isa => 'AnyEvent::IRC::Client',
handles => {
send_srv => 'send_srv',
}
);
has nickname => (
is => 'ro',
isa => 'Str',
required => 1
);
has password => (
is => 'ro',
isa => 'Str',
);
has plugins => (
is => 'ro',
isa => 'ArrayRef',
writer => 'set_plugins'
);
has port => (
is => 'ro',
isa => 'Str',
default => 6667,
required => 1
);
has server => (
is => 'ro',
isa => 'Str',
required => 1
);
has username => (
is => 'ro',
isa => 'Str',
lazy_build => 1,
);
sub _build_hooks { {} }
sub _build_username { $_[0]->nickname }
sub new_from_config {
my ($class, $config) = @_;
my $plugins = delete $config->{plugin};
my $self = $class->new(%$config);
my @plugins;
while ( my ($class, $p) = each %$plugins ) {
if ($class !~ s/^\+//) {
$class = "Morris::Plugin::$class";
}
if (! Class::MOP::is_class_loaded( $class) ) {
Class::MOP::load_class( $class );
}
my $plugin = $class->new_from_config( $p );
$plugin->register( $self );
push @plugins, $plugin;
}
$self->set_plugins(\@plugins) if @plugins;
return $self;
}
sub call_hook {
my ($self, $name, @args) = @_;
warn "Calling hooks for $name" if Morris::DEBUG();
my $hooks = $self->get_hook( $name );
return unless $hooks;
foreach my $hook (@$hooks) {
$hook->( @args );
}
}
sub register_hook {
my ($self, $name, $code) = @_;
$self->hooks->{$name} ||= [];
my $list = $self->hooks->{$name};
push @$list, $code;
}
sub run {
my $self = shift;
my $irc = AnyEvent::IRC::Client->new();
$self->irc($irc);
$irc->connect( $self->server, $self->port, {
nick => $self->nickname,
user => $self->username,
password => $self->password,
timeout => 1,
} );
$irc->reg_cb(
connect => sub { $self->call_hook( 'server.connected', @_ ) },
disconnect => sub { $self->call_hook( 'server.disconnect', @_ ) },
irc_privmsg => sub {
my ($nick, $raw) = @_;
my $message = Morris::Message->new(
channel => $raw->{params}->[0],
message => $raw->{params}->[1],
from => $raw->{prefix},
);
$self->call_hook( 'chat.privmsg', $message )
},
# XXX - we want the /full/ details of this user, not his nick
# so we override the original irc_join callback
irc_join => sub {
my $object = shift;
$object->AnyEvent::IRC::Client::join_cb(@_);
# and /THEN/ call our callback
# fix the param thing to be just a simple 'channel' parameter
my $channel = $_[0]->{params}->[0];
my $addr = Morris::Message::Address->new( $_[0]->{prefix} );
$self->call_hook( 'channel.joined', $channel, $addr );
},
registered => sub { $self->call_hook( 'server.registered', @_ ) },
);
}
sub irc_notice {
my ($self, $args) = @_;
$self->send_srv(NOTICE => $args->{channel} => $args->{message});
}
sub irc_privmsg {
my ($self, $args) = @_;
$self->send_srv(PRIVMSG => $args->{channel} => $args->{message});
}
sub irc_mode {
my ($self, $args) = @_;
$self->send_srv(MODE => $args->{channel} => $args->{mode}, $args->{who});
}
__PACKAGE__->meta->make_immutable();
1;
__END__
=head1 NAME
Morris::Connection - Single IRC Connection
=head1 SYNOPSIS
use Morris::Connection;
my $conn = Morris::Connection->new(
nickname => $nickname,
port => $port_number,
password => $optional_password,
server => $server_name,
username => $username,
);
# to receive events
$conn->register_hook( $hook_name => $code );
# to send events
$conn->irc_notice( { channel => $channel, message => $message } );
$conn->irc_privmsg( { channel => $channel, message => $message } );
$conn->irc_mode( { channel => $channel, mode => $new_mode, who => $target } );
=cut