view release on metacpan or search on metacpan
lib/Convos.pm view on Meta::CPAN
# Using push() since I don't think it's a good idea for allowing the user
# to customize every template, at least not when the application is still
# unstable.
push @{$self->renderer->paths}, $ENV{CONVOS_TEMPLATES};
}
$self->defaults(full_page => 1, organization_name => $self->config('name'));
$self->hook(before_dispatch => \&_before_dispatch);
$self->_embed_backend if $ENV{CONVOS_BACKEND_EMBEDDED};
Scalar::Util::weaken($self);
Mojo::IOLoop->timer(0 => sub { $self->_set_secrets });
}
sub _assets {
my $self = shift;
$self->plugin('AssetPack');
$self->plugin('FontAwesome4', css => []);
$self->asset('c.css' => qw( /scss/font-awesome.scss /sass/convos.scss ));
$self->asset(
lib/Convos/Controller/Chat.pm view on Meta::CPAN
=cut
sub socket {
my $self = shift;
my $login = $self->session('login');
my $key = "convos:user:$login:out";
$self->_schedule_day_changed_event;
$self->inactivity_timeout(60);
Scalar::Util::weaken($self);
# from browser to backend
$self->on(
message => sub {
my ($self, $octets) = @_;
my $dom;
$self->logf(debug => '[ws] < %s', $octets);
if ($octets eq 'PING') {
lib/Convos/Controller/Chat.pm view on Meta::CPAN
$self->redis->rpush("user:$login:cmd_history", $dom->text(0));
$self->redis->ltrim("user:$login:cmd_history", -30, -1);
}
}
}
sub _schedule_day_changed_event {
my $self = shift;
my $t = 86400 - time % 86400;
Scalar::Util::weaken($self);
$self->stash(
day_changed_event_tid => Mojo::IOLoop->timer(
$t => sub {
$self or return;
$self->send_partial('event/day_changed', timestamp => time + 1,);
$self->_schedule_day_changed_event;
}
)
);
}
lib/Convos/Core.pm view on Meta::CPAN
die "Convos::Core is already started" if $self->{start}++;
# TODO: Remove in future versions and/or move to Convos::Upgrader
$self->redis->del($_)
for qw( convos:backend:lock convos:backend:pid convos:backend:started convos:host2convos convos:loopback:names );
$self->redis->del('core:control'); # need to clear instructions queued while backend was stopped
$self->_start_control_channel;
Scalar::Util::weaken($self);
Mojo::IOLoop->delay(
sub {
my ($delay) = @_;
$self->redis->smembers('connections', $delay->begin);
},
sub {
my ($delay, $connections) = @_;
for my $id (@$connections) {
$self->_connection($id)->_state('disconnected')->{core_connect_timer} = 1;
}
lib/Convos/Core.pm view on Meta::CPAN
}
);
return $self;
}
sub _start_control_channel {
my $self = shift;
my $cb;
Scalar::Util::weaken($self);
$cb = sub {
my ($redis, $instruction) = @_;
$redis->brpop($instruction->[0], 0, $cb);
$instruction->[1] or return;
my ($command, $login, $name) = split /:/, $instruction->[1];
my $action = "ctrl_$command";
$self->$action($login, $name);
};
lib/Convos/Core.pm view on Meta::CPAN
my $validation = $self->_validation($input, qw( login name nick password server username ));
if ($validation->has_error) {
$self->$cb($validation, undef);
return $self;
}
my ($login, $name) = $validation->param([qw( login name )]);
warn "[core:$login] add ", _dumper($validation->output), "\n" if DEBUG;
Scalar::Util::weaken($self);
Mojo::IOLoop->delay(
sub {
my ($delay) = @_;
$self->redis->exists("user:$login:connection:$name", $delay->begin);
},
sub {
my ($delay, $exists) = @_;
if ($exists) {
$validation->error(name => ['exists']);
lib/Convos/Core.pm view on Meta::CPAN
Stop a connection by connection id.
=cut
sub ctrl_stop {
my ($self, $login, $server) = @_;
my $id = join ':', $login, $server;
my $conn = $self->{connections}{$id} or return;
Scalar::Util::weaken($self);
$conn->disconnect(sub { delete $self->{connections}{$id} });
}
=head2 ctrl_restart
$self->ctrl_restart($login, $server);
Restart a connection by connection id.
=cut
sub ctrl_restart {
my ($self, $login, $server) = @_;
my $id = join ':', $login, $server;
if (my $conn = $self->{connections}{$id}) {
Scalar::Util::weaken($self);
$conn->disconnect(
sub {
delete $self->{connections}{$id};
$self->ctrl_start($login => $server);
}
);
}
else {
$self->ctrl_start($login => $server);
}
lib/Convos/Core.pm view on Meta::CPAN
}
);
}
sub _connection {
my ($self, $id) = @_;
my $conn = $self->{connections}{$id};
unless ($conn) {
my ($login, $name) = split /:/, $id;
Scalar::Util::weaken($self);
$conn = Convos::Core::Connection->new(redis => $self->redis, log => $self->log, login => $login, name => $name);
$conn->on(save => sub { $_[1]->{message} and $_[1]->{timestamp} and $self->archive->save(@_); });
$self->{connections}{$id} = $conn;
}
$conn;
}
sub _dumper { # function
Data::Dumper->new([@_])->Indent(0)->Sortkeys(1)->Terse(1)->Dump;
lib/Convos/Core/Connection.pm view on Meta::CPAN
irc_rpl_listend irc_mode irc_quit irc_kick irc_error
irc_rpl_namreply irc_rpl_endofnames err_nicknameinuse
);
has _irc => sub {
my $self = shift;
my $irc = Mojo::IRC->new(debug_key => join ':', $self->login, $self->name);
$irc->parser(Parse::IRC->new(ctcp => 1));
Scalar::Util::weaken($self);
$irc->register_default_event_handlers;
$irc->on(close => sub { $self->_irc_close });
$irc->on(error => sub { $self->_irc_error($_[1]) });
for my $event (@ADD_MESSAGE_EVENTS) {
$irc->on($event => sub { $self->add_message($_[1]) });
}
for my $event (@ADD_SERVER_MESSAGE_EVENTS) {
$irc->on($event => sub { $self->add_server_message($_[1]) });
}
lib/Convos/Core/Connection.pm view on Meta::CPAN
Attributes fetched from backend: nick, user, host and channels. The latter
is set in L</channels> and used by L</irc_rpl_welcome>.
=cut
sub connect {
my ($self) = @_;
my $irc = $self->_irc;
Scalar::Util::weaken($self);
$self->{core_connect_timer} = 0;
$self->{keepnick_tid} ||= $irc->ioloop->recurring(60 => sub { $self->_steal_nick });
$self->_subscribe;
$self->redis->execute(
[hgetall => $self->{path}],
[get => 'convos:frontend:url'],
sub {
my ($redis, $args, $url) = @_;
$self->redis->hset($self->{path} => tls => $self->{disable_tls} ? 0 : 1);
lib/Convos/Core/Connection.pm view on Meta::CPAN
my ($delay, $nick) = @_;
$self->_irc->write(NICK => $nick) if $nick and $self->_irc->nick ne $nick;
}
);
}
sub _subscribe {
my $self = shift;
my $irc = $self->_irc;
Scalar::Util::weaken($self);
$self->{messages} = $self->redis->subscribe("convos:user:@{[$self->login]}:@{[$self->name]}");
$self->{messages}->on(
error => sub {
my ($sub, $error) = @_;
$self->log->warn("[$self->{path}] Re-subcribing to messages to @{[$irc->name]}. ($error)");
$self->_subscribe;
},
);
$self->{messages}->on(
message => sub {
lib/Convos/Core/Connection.pm view on Meta::CPAN
:Zurich.CH.EU.Undernet.Org 001 somenick :Welcome to the UnderNet IRC Network, somenick
=cut
sub irc_rpl_welcome {
my ($self, $message) = @_;
$self->{attempts} = 0;
Scalar::Util::weaken($self);
$self->redis->zrange(
$self->{conversation_path},
0, -1,
sub {
for my $channel ($self->channels_from_conversations($_[1])) {
$self->redis->hget(
"$self->{path}:$channel",
key => sub {
$_[1] ? $self->_irc->write(JOIN => $channel, $_[1]) : $self->_irc->write(JOIN => $channel);
}
lib/Convos/Core/Connection.pm view on Meta::CPAN
command => 'QUIT',
prefix => 'nick!~user@localhost'
};
=cut
sub irc_quit {
my ($self, $message) = @_;
my ($nick) = IRC::Utils::parse_user($message->{prefix});
Scalar::Util::weaken($self);
$self->_publish(nick_quit => {nick => $nick, message => $message->{params}[0]});
}
=head2 irc_kick
'raw_line' => ':testing!~marcus@home.means.no KICK #testmore :marcus_',
'params' => [ '#testmore', 'marcus_' ],
'command' => 'KICK',
'handled' => 1,
'prefix' => 'testing!~marcus@40.101.45.31.customer.cdi.no'
lib/Convos/Core/Connection.pm view on Meta::CPAN
=head2 irc_part
=cut
sub irc_part {
my ($self, $message) = @_;
my ($nick) = IRC::Utils::parse_user($message->{prefix});
my $channel = lc $message->{params}[0];
Scalar::Util::weaken($self);
if ($nick eq $self->_irc->nick) {
my $name = as_id $self->name, $channel;
$self->redis->zrem(
$self->{conversation_path},
$name,
sub {
$self->_publish(remove_conversation => {target => $channel});
}
);
lib/Convos/Core/Connection.pm view on Meta::CPAN
=cut
sub err_bannedfromchan {
my ($self, $message) = @_;
my $channel = lc $message->{params}[1];
my $name = as_id $self->name, $channel;
$self->_publish_and_save(server_message => {status => 401, message => $message->{params}[2]});
Scalar::Util::weaken($self);
$self->redis->zrem(
$self->{conversation_path},
$name,
sub {
$self->_publish(remove_conversation => {target => $channel});
}
);
}
=head2 err_nicknameinuse
lib/Convos/Core/Connection.pm view on Meta::CPAN
=cut
sub err_nosuchchannel {
my ($self, $message) = @_;
my $channel = lc $message->{params}[1];
my $name = as_id $self->name, $channel;
$self->_publish(server_message => {status => 400, message => qq(No such channel "$channel")});
if ($channel =~ /^[#&]/) {
Scalar::Util::weaken($self);
$self->redis->zrem(
$self->{conversation_path},
$name,
sub {
$self->_publish(remove_conversation => {target => $channel});
}
);
}
}