basically operating chain code
Matt S Trout [Wed, 16 Feb 2011 10:57:24 +0000 (10:57 +0000)]
lib/App/Clifton/Chain.pm
lib/App/Clifton/Component.pm
lib/App/Clifton/Server.pm
lib/App/Clifton/Service.pm
lib/App/Clifton/Task.pm
lib/App/Clifton/Tower/IRC.pm [new file with mode: 0644]
lib/App/Clifton/Tower/Jabber.pm
lib/App/Clifton/UserConfig.pm
notes/jsetup

index 400ee9b..3641613 100644 (file)
@@ -2,7 +2,28 @@ package App::Clifton::Chain;
 
 use Moo;
 
+extends 'App::Clifton::Component';
+
 has jabber_user => (is => 'ro', required => 1);
 has irc_channel => (is => 'ro', required => 1);
 
+has jabber_tower => (is => 'ro', required => 1);
+has irc_tower => (is => 'ro', required => 1, weak_ref => 1);
+
+sub handle_xmpp_message {
+  my ($self, $msg) = @_;
+  $self->irc_tower->send_irc_message({
+    to => $self->irc_channel,
+    text => $msg->body
+  });
+}
+
+sub handle_irc_message {
+  my ($self, $message, $hints) = @_;
+  $self->jabber_tower->send_xmpp_message({
+    to => $self->jabber_user,
+    body => join(': ', $hints->{prefix_name}, $hints->{text})
+  });
+}
+
 1;
index 7f80acd..6f857ba 100644 (file)
@@ -6,6 +6,7 @@ sub _debug_self {
   "${self}: ".join ', ', map "$_ => ".$args->{$_}, keys %$args;
 }
 
+use Try::Tiny;
 use Log::Contextual qw(:log);
 use Moo;
 
@@ -54,9 +55,7 @@ sub _eval_cb {
   my ($self, $code) = @_;
   my $str = "$self";
   sub {
-    local $@;
-    eval { $code->(@_); 1 }
-      or log_error { "Exception from ${self}: $@" };
+    try { $code->(@_) } catch { log_error { "Exception from ${self}: $_" } }
   };
 }
 
index c154786..4a46499 100644 (file)
@@ -2,6 +2,8 @@ package App::Clifton::Server;
 
 use aliased 'App::Clifton::ConsoleService';
 use aliased 'App::Clifton::ConfigLoader';
+use aliased 'App::Clifton::Tower::Jabber' => 'Jabber_Tower';
+use aliased 'App::Clifton::Tower::IRC' => 'IRC_Tower';
 use Moo;
 
 extends 'App::Clifton::Service';
@@ -22,6 +24,10 @@ sub _build_config_loader { ConfigLoader->new }
 
 has console_service => (is => 'lazy');
 
+has jabber_towers => (is => 'ro', default => sub { {} });
+
+has irc_towers => (is => 'ro', default => sub { {} });
+
 sub _build_console_service {
   my ($self) = @_;
   $self->_new_child(ConsoleService, { server => $self });
@@ -37,4 +43,39 @@ sub _body_for_reload_config {
   $args->{on_finished}->($config);
 }
 
+sub start_chain { shift->_do(start_chain => @_) }
+
+sub _dependencies_for_start_chain {
+  my ($self, $args) = @_;
+  {
+    irc_tower => $self->start_irc_tower($args->{irc_tower})
+  }
+}
+
+sub _body_for_start_chain {
+  my ($self, $args) = @_;
+  $args->{irc_tower}->start_chain($args);
+}
+
+sub start_irc_tower { shift->_do(start_irc_tower => @_) }
+
+sub _guard_for_start_irc_tower {
+  my ($self, $args) = @_;
+  if (my $tower = $self->irc_towers->{$args->{server}}{$args->{irc_nick}}) {
+    ($tower);
+  } else {
+    ();
+  }
+}
+
+sub _body_for_start_irc_tower {
+  my ($self, $args) = @_;
+  $self->_new_child(IRC_Tower, {
+    irc_server => $args->{server},
+    irc_nick => $args->{irc_nick},
+    on_setup => $args->{on_finished},
+    server => $self,
+  });
+}
+
 1;
index 043e877..49bb786 100644 (file)
@@ -6,17 +6,26 @@ use Moo;
 extends 'App::Clifton::Component';
 
 sub _do {
-  my ($self, $do, @args) = @_;
+  my ($self, $do, $args) = @_;
   my $body = do {
     my $body_call = $self->_capture_weakself("_body_for_${do}");
-    sub { $body_call->(@args, @_) }
+    sub { $body_call->(@_) }
+  };
+  my @guard = do {
+    if ($self->can("_guard_for_${do}")) {
+      my $guard_call = $self->_capture_weakself("_guard_for_${do}");
+      (guard => sub { $guard_call->(@_) });
+    } else {
+      ();
+    }
   };
   my $deps = {};
   if (my $dep_call = $self->can("_dependencies_for_${do}")) {
-    $deps = $self->$dep_call(@args);
+    $deps = $self->$dep_call($args);
   }
   $self->_new_child(Task, {
-    name => $do, body => $body, dependencies => $deps
+    name => $do, body => $body, dependencies => $deps, @guard,
+    args => $args,
   });
 }
 
index 216e3c3..c641be1 100644 (file)
@@ -12,6 +12,10 @@ has name => (is => 'ro', required => 1);
 
 has body => (is => 'ro', required => 1);
 
+has guard => (is => 'ro', predicate => 'has_guard');
+
+has args => (is => 'ro', required => 1);
+
 has dependencies => (is => 'ro', default => sub { {} });
 
 has merge_point => (is => 'lazy');
@@ -20,6 +24,9 @@ sub _build_merge_point { Async::MergePoint->new }
 
 sub BUILD {
   my ($self) = @_;
+  if (my $cb = $self->args->{on_finished}) {
+    $self->on_finished($cb);
+  }
   my $deps = $self->dependencies;
   if (my @needs = keys %$deps) {
     my $mp = $self->merge_point;
@@ -37,12 +44,17 @@ sub _schedule_body {
   my ($self, %args) = @_;
   my $fire_body = $self->_capture_weakself('_fire_body');
   $args{on_finished} = $self->_finished_callback;
+  %args = (%{$self->args}, %args);
   $self->_schedule(sub { $fire_body->(\%args); });
 }
 
 sub _fire_body {
   my $self = shift;
-  $self->body->(@_);
+  if ($self->has_guard and my ($result) = $self->guard->(@_)) {
+    $_[0]->{on_finished}($result);
+  } else {
+    $self->body->(@_);
+  }
 }
 
 sub _finished_callback {
diff --git a/lib/App/Clifton/Tower/IRC.pm b/lib/App/Clifton/Tower/IRC.pm
new file mode 100644 (file)
index 0000000..5dffc0e
--- /dev/null
@@ -0,0 +1,63 @@
+package App::Clifton::Tower::IRC;
+
+use aliased 'Net::Async::IRC' => 'IRC_Client';
+use aliased 'App::Clifton::Chain';
+use Log::Contextual qw(:log);
+use Moo;
+             
+extends 'App::Clifton::Component';
+
+has server => (is => 'ro', required => 1, weak_ref => 1);
+has irc_server => (is => 'ro', required => 1);
+has irc_nick => (is => 'ro', required => 1);
+has irc_client => (is => 'lazy');
+has chains => (is => 'ro', default => sub { {} });
+
+sub _build_irc_client { shift->_new_child(IRC_Client, {}) }
+
+sub BUILD {
+  my ($self, $args) = @_;
+  my $on_setup = $args->{on_setup};
+  $self->irc_client->configure(
+    on_message_text => $self->_replace_weakself('receive_irc_message')
+  );
+  $self->irc_client->login(
+    nick => $self->irc_nick, host => $self->irc_server,
+    on_login => $self->_capture_weakself(sub {
+      my $self = shift;
+      $self->server->irc_towers->{$self->irc_server}{$self->irc_nick}
+        = $self;
+      $on_setup->($self);
+    }),
+  );
+}
+
+sub start_chain {
+  my ($self, $args) = @_;
+  $self->irc_client->send_message('JOIN', undef, $args->{irc_channel});
+  my $new = $self->_new_child(Chain, {
+    %$args, irc_tower => $self,
+  });
+  $self->chains->{$args->{irc_channel}} = $new;
+  # I note here that actually we should make the Chain do
+  # setup (JOIN) and confirm that first, but oh well
+  $args->{on_finished}->({
+    chain => $new,
+    message => 'SUCCESS'
+  });
+}
+
+sub send_irc_message {
+  my ($self, $args) = @_;
+  $self->irc_client->send_message('PRIVMSG', undef, @{$args}{qw(to text)});
+}
+
+sub receive_irc_message {
+  my ($self, $message, $hints) = @_;
+  return if $hints->{prefix_is_me};
+  if (my $chain = $self->chains->{$hints->{target_name}}) {
+    $chain->handle_irc_message($message, $hints);
+  }
+}
+
+1;
index 381695f..44c8d0d 100644 (file)
@@ -13,7 +13,9 @@ 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);
+  for qw(bridge_name jabber_config irc_config);
+
+has server => (is => 'ro', required => 1, weak_ref => 1);
 
 has userconfig_set => (
   is => 'ro', # Moobug init_arg => undef,
@@ -35,10 +37,13 @@ sub _login_xmpp_client {
   my $conf = $self->jabber_config;
   $xmpp->login(
     jid => $conf->user, host => $conf->server, password => $conf->pass,
+    on_message => $self->_replace_weakself('handle_message'),
   );
   $xmpp;
 }
 
+sub BUILD { $_[0]->xmpp_client }
+
 sub handle_message {
   my ($self, $msg) = @_;
 
@@ -68,8 +73,11 @@ sub handle_message {
       $self->start_chain_for($user)->on_finished(
         $self->_capture_weakself(sub {
           my ($self, $result) = @_;
+          if ($result->{chain}) {
+            $self->chain_set->add($result->{chain});
+          }
           $self->send_xmpp_message({
-            to => $from, body => 'Connection result: '.$result
+            to => $from, body => 'Connection result: '.$result->{message}
           });
         })
       );
@@ -87,6 +95,19 @@ sub send_xmpp_message {
   $self->xmpp_client->compose(%$args)->send;
 }
 
+sub start_chain_for {
+  my ($self, $user) = @_;
+  $self->server->start_chain({
+    jabber_tower => $self,
+    jabber_user => $user->name,
+    irc_tower => {
+      server => $self->irc_config->server,
+      irc_nick => $user->irc_nick
+    },
+    irc_channel => $self->irc_config->channel,
+  });
+}
+
 1;
 
 # and later
index 0b82954..aba192a 100644 (file)
@@ -2,6 +2,7 @@ package App::Clifton::UserConfig;
 
 use Moo;
 
+has name => (is => 'ro', required => 1);
 has allow => (is => 'ro', required => 1);
 has irc_nick => (is => 'ro', required => 1);
 
index cc524a3..347099d 100644 (file)
@@ -1,5 +1,7 @@
 use App::Clifton::Tower::Jabber
-my $j = $_SERVER->_new_child('App::Clifton::Tower::Jabber', { server => $_SERVER, bridge_name => 'hearts', jabber_config => $_SERVER->current_config->bridges->get({ name => 'hearts' })->jabber });
+my $hearts = $_SERVER->current_config->bridges->get({ name => 'hearts' });
+my $j = $_SERVER->_new_child('App::Clifton::Tower::Jabber', { server => $_SERVER, bridge_name => 'hearts', jabber_config => $hearts->jabber, irc_config => $hearts->irc });
+$j->userconfig_set->add($_SERVER->current_config->users->get({ name => 'mst@corvina.org' });
 my $xmpp = $j->xmpp_client;
 $xmpp->compose(to => 'mst@corvina.org', body => 'hi')->send
 $xmpp->configure(on_message => $j->_replace_weakself('handle_message'));