/server/ChatNoir/Client.pm
use Class::Accessor 'moose-like';
use AnyEvent::XMPP::IM::Connection;
use ChatNoir::Util qw/pretty_presence short_jid/;
use strict;
use v5.10;
has app => ( is => 'ro' );
has controller => ( is => 'ro' );
has xmpp => ( is => 'ro' );
has jid => ( is => 'ro' );
has password => ( is => 'ro' );
has active => ( is => 'ro' );
{
my ($self, %params) = @_;
if ($self->controller) {
$self->controller->finish(1000 => "Reconnected");
}
$self->{ } = $params{ };
$self->attach_controller_events;
}
{
my ($self) = @_;
$self->controller->tx->on(json => sub {
my ($tx, $msg) = @_;
given ($msg->{ }) {
when ('login') {
my $password = $msg->{ };
if (!defined $password) {
$self->controller->finish(1015 => "Login must have password\n");
delete $self->{ };
return;
}
if ($self->xmpp && $self->xmpp->is_connected) {
# If we're reattaching, check that the new password matches the original
if ($password ne $self->password) {
$self->ws_send('login-failed', reason => 'unauthorized');
return;
}
$self->{ } = 1;
$self->ws_send('login-successful');
$self->app->log->debug("reattaching " . $self->jid);
} else {
# Otherwise, attempt a new connection with the given password
$self->app->log->debug("Creating new XMPP connection for " . $self->jid);
$self->{ } = $password;
$self->{ } = AnyEvent::XMPP::IM::Connection->new(
jid => $self->jid,
password => $password,
);
$self->attach_xmpp_events;
$self->xmpp->connect;
}
}
when ('logout') {
$self->active || return;
$self->guard_connected || return;
$self->xmpp->disconnect;
delete $self->{ };
$self->ws_send('login-failed', reason => 'user requested');
$self->app->log->debug($self->jid . " logged out");
}
when ('message') {
$self->active || return;
$self->guard_connected || return;
AnyEvent::XMPP::IM::Message->new(
from => $self->jid,
to => $msg->{ },
body => $msg->{ },
)->send($self->xmpp);
}
when ('get-roster') {
$self->active || return;
$self->guard_connected || return;
$self->ws_send_roster;
}
when (undef) {
$self->app->log->debug("Empty message?");
}
default {
$self->app->log->debug("Unknown message type $msg->{type}");
}
}
});
$self->controller->tx->on(finish => sub {
delete $self->{ };
$self->{ } = undef;
$self->app->log->debug($self->jid . " detached");
});
}
{
my ($self) = @_;
$self->xmpp->reg_cb(
session_ready => sub {
$self->ws_send('login-successful');
$self->{ } = 1;
$self->app->log->debug("Session ready for " . $self->xmpp->jid);
},
session_error => sub {
my ($err) = @_;
$self->ws_send('login-failed', reason => 'error', error => $err->string);
$self->{ } = undef;
$self->app->log->error("Session error: " . $err->string);
},
sasl_error => sub {
my ($connection, $err) = @_;
$self->{ } = undef;
$self->app->log->error($err->string);
if ($err->string =~ /not-authorized/) {
$self->ws_send('login-failed', reason => 'unauthorized');
}
},
roster_update => sub {
my ($connection, $roster, $contacts) = @_;
},
presence_update => sub {
my ($connection, $roster, $contact, $old_presence, $new_presence) = @_;
$self->ws_send('presence',
jid => short_jid($new_presence->jid),
status => pretty_presence($new_presence),
priority => $new_presence->priority,
);
},
message => sub {
my ($connection, $msg) = @_;
$self->ws_send('message',
from => short_jid($msg->from),
body => $msg->body,
);
}
);
}
{
my ($self, $type, %params) = @_;
if ($self->controller) {
$self->controller->send({json => {
type => $type,
%params
}});
}
}
{
my ($self) = @_;
my @raw_contacts = map {
{
jid => $_->jid,
name => $_->name,
groups => [$_->groups],
presence => pretty_presence($_->get_priority_presence),
subscription => $_->subscription,
}
} $self->xmpp->get_roster->get_contacts;
$self->ws_send('roster', contacts => \@raw_contacts);
}
{
my ($self) = @_;
if (!$self->xmpp || !$self->xmpp->is_connected) {
$self->ws_send('error', message => 'not connected');
return;
}
return 1;
}
1;