--- /dev/null
+package App::Clifton::Chain;
+
+use Moo;
+
+has jabber_user => (is => 'ro', required => 1);
+has irc_channel => (is => 'ro', required => 1);
+
+1;
--- /dev/null
+package App::Clifton::ChainSetByIRCChannel;
+
+use aliased 'App::Clifton::Chain';
+use Moo;
+
+with 'App::Clifton::Set';
+
+sub _set_of_class { Chain }
+sub _set_over { 'irc_channel' }
+
+1;
--- /dev/null
+package App::Clifton::ChainSetByJabberUser;
+
+use aliased 'App::Clifton::Chain';
+use Moo;
+
+with 'App::Clifton::Set';
+
+sub _set_of_class { Chain }
+sub _set_over { 'jabber_user' }
+
+1;
}
}
+around _replace_weakself => sub {
+ my ($orig, $self) = (shift, shift);
+ $self->_eval_cb($self->$orig(@_));
+};
+
+around _capture_weakself => sub {
+ my ($orig, $self) = (shift, shift);
+ $self->_eval_cb($self->$orig(@_));
+};
+
sub _schedule {
my ($self, $code) = @_;
- $self->get_loop->later($code);
+ $self->get_loop->later($self->_eval_cb($code));
+}
+
+sub _eval_cb {
+ my ($self, $code) = @_;
+ my $str = "$self";
+ sub {
+ local $@;
+ eval { $code->(@_); 1 }
+ or log_error { "Exception from ${self}: $@" };
+ };
}
sub DESTROY {
use aliased 'App::Clifton::ConsoleService::Session';
use IO::Async::Listener;
use IO::Socket::UNIX;
-use Scalar::Util qw(weaken);
use Moo;
extends 'App::Clifton::Service';
has $_ => (is => 'lazy') for qw(listener session socket);
+has server => (is => 'ro', required => 1, weak_ref => 1);
+
sub _build_socket {
my ($self) = @_;
my $location = $self->socket_location;
my ($self) = @_;
Session->new->${\sub {
my ($session) = @_;
- $session->lex_env->lexicals->{'$_SERVICE'} = \$self;
- weaken(${$session->lex_env->{'$_SERVICE'}});
+ # no need to weaken this since server is already weak
+ $session->lex_env->lexicals->{'$_SERVER'} = \$self->server;
$session;
}};
}
+++ /dev/null
-package App::Clifton::JabberService;
-
-use Moo;
-
-extends 'App::Clifton::Service';
-
-1;
sub run {
my ($self) = @_;
set_logger(Log::Contextual::SimpleLogger->new({ levels => [ qw(
- info warn debug
+ info warn debug error
) ] }));
my $loop = IO::Async::Loop->new;
my $server = Server->new(
log_info { "Server startup complete" };
});
});
- $loop->loop_forever;
+ while (1) {
+ local $@;
+ last if eval { $loop->loop_forever; 1 };
+ my $error = $@;
+ log_error { "Server exception: ${error}" };
+ }
+ log_info { "Server shut down cleanly" };
}
1;
package App::Clifton::Server;
-use aliased 'App::Clifton::ServiceContainer';
+use aliased 'App::Clifton::ConsoleService';
use aliased 'App::Clifton::ConfigLoader';
use Moo;
sub BUILD {
my ($self, $args) = @_;
$args->{loop}->add($self);
- $self->$_ for qw(services);
+ $self->$_ for qw(console_service);
}
has config_file => (is => 'ro', required => 1);
sub _build_config_loader { ConfigLoader->new }
-has services => (is => 'lazy');
+has console_service => (is => 'lazy');
-sub _build_services {
- shift->_new_child(ServiceContainer, {});
+sub _build_console_service {
+ my ($self) = @_;
+ $self->_new_child(ConsoleService, { server => $self });
}
sub reload_config { shift->_do(reload_config => @_) }
+++ /dev/null
-package App::Clifton::ServiceContainer;
-
-use aliased 'App::Clifton::JabberService';
-use aliased 'App::Clifton::IRCService';
-use aliased 'App::Clifton::ConsoleService';
-use Log::Contextual qw(:log);
-use Moo;
-
-extends 'App::Clifton::Component';
-
-has jabber => (is => 'lazy');
-has irc => (is => 'lazy');
-has console => (is => 'lazy');
-
-sub BUILD {
- my ($self) = @_;
- $self->$_ for qw(console irc jabber);
-}
-
-sub _build_jabber {
- my ($self) = @_;
- log_debug { "Spawning jabber service" };
- $self->_new_child(JabberService, { irc_service => $self->irc });
-}
-
-sub _build_irc {
- my ($self) = @_;
- log_debug { "Spawning IRC service" };
- $self->_new_child(IRCService, {});
-}
-
-sub _build_console {
- my ($self) = @_;
- log_debug { "Spawning console service" };
- $self->_new_child(ConsoleService, {});
-}
-
-1;
--- /dev/null
+package App::Clifton::Tower::Jabber;
+
+use aliased 'App::Clifton::UserConfigSet';
+use aliased 'App::Clifton::ChainSetByJabberUser' => 'ChainSet';
+use aliased 'Net::Async::XMPP::Client' => 'XMPP_Client';
+use Log::Contextual qw(:log);
+use Moo;
+
+extends 'App::Clifton::Component';
+
+has xmpp_client => (is => 'lazy');
+
+sub xmpp_active { shift->xmpp_client->xmpp->is_loggedin }
+
+has $_ => (is => 'ro', required => 1)
+ for qw(bridge_name server jabber_config);
+
+has userconfig_set => (
+ is => 'ro', # Moobug init_arg => undef,
+ default => sub { UserConfigSet->new }
+);
+
+has chain_set => (
+ is => 'ro', # Moobug init_arg => undef,
+ default => sub { ChainSet->new }
+);
+
+sub _build_xmpp_client {
+ my ($self) = @_;
+ $self->_login_xmpp_client($self->_new_child(XMPP_Client, { }));
+}
+
+sub _login_xmpp_client {
+ my ($self, $xmpp) = @_;
+ my $conf = $self->jabber_config;
+ $xmpp->login(
+ jid => $conf->user, host => $conf->server, password => $conf->pass,
+ );
+ $xmpp;
+}
+
+sub handle_message {
+ my ($self, $msg) = @_;
+
+ my $me = $self->jabber_config->user;
+
+ return log_debug {
+ "Received message for ${\$msg->to} instead of $me - ignoring"
+ } unless $msg->to eq $me;
+
+ (my $from = $msg->from) =~ s/\/.*//;
+
+ return log_debug {
+ "Received message from me ($me) - ignoring"
+ } if $from eq $me;
+
+ return log_debug {
+ "Received message from user ${from} not in my config"
+ } unless my $user = $self->userconfig_set->get({ name => $from });
+
+ if (my $chain = $self->chain_set->get({ jabber_user => $from })) {
+ $chain->handle_xmpp_message($msg);
+ } else {
+ if ($msg->body =~ m{^\s*/start\s*$}) {
+ $self->send_xmpp_message({
+ to => $from, body => 'Connecting ...'
+ });
+ $self->start_chain_for($user)->on_finished(
+ $self->_capture_weakself(sub {
+ my ($self, $result) = @_;
+ $self->send_xmpp_message({
+ to => $from, body => 'Connection result: '.$result
+ });
+ })
+ );
+ } else {
+ $self->send_xmpp_message({
+ to => $from,
+ body => 'Not currently connected - send /start to connect'
+ });
+ }
+ }
+}
+
+sub send_xmpp_message {
+ my ($self, $args) = @_;
+ $self->xmpp_client->compose(%$args)->send;
+}
+
+1;
+
+# and later
+
+# package App::Clifton::Tower::IRC;
+
+# has irc_client
+
+# has irc_server_name
+
+# has user_config
+
+# has chain_set
+
+# package App::Clifton::Chain
+
+#