AnyEvent-MP

 view release on metacpan or  search on metacpan

META.json  view on Meta::CPAN

         "recommends" : {
            "Net::Interface" : "1.011"
         },
         "requires" : {
            "AnyEvent" : "6.14",
            "AnyEvent::Watchdog" : "1",
            "CBOR::XS" : "1.5",
            "Digest::HMAC" : "1.03",
            "Digest::SHA3" : "0.24",
            "Guard" : "1.022",
            "JSON::XS" : "2.25",
            "MIME::Base64" : "3",
            "Task::Weaken" : "0",
            "common::sense" : "0"
         }
      }
   },
   "release_status" : "stable",
   "version" : "2.02",
   "x_serialization_backend" : "JSON::PP version 2.27300"
}

META.yml  view on Meta::CPAN

    - inc
recommends:
  Net::Interface: '1.011'
requires:
  AnyEvent: '6.14'
  AnyEvent::Watchdog: '1'
  CBOR::XS: '1.5'
  Digest::HMAC: '1.03'
  Digest::SHA3: '0.24'
  Guard: '1.022'
  JSON::XS: '2.25'
  MIME::Base64: '3'
  Task::Weaken: '0'
  common::sense: '0'
version: '2.02'
x_serialization_backend: 'CPAN::Meta::YAML version 0.012'

MP.pm  view on Meta::CPAN


And as a result, a port with just a default receiver consists of a single
code reference stored in a global hash - it can't become much cheaper.

=item Why favour JSON, why not a real serialising format such as Storable?

In fact, any AnyEvent::MP node will happily accept Storable as framing
format, but currently there is no way to make a node use Storable by
default (although all nodes will accept it).

The default framing protocol is JSON because a) JSON::XS is many times
faster for small messages and b) most importantly, after years of
experience we found that object serialisation is causing more problems
than it solves: Just like function calls, objects simply do not travel
easily over the network, mostly because they will always be a copy, so you
always have to re-think your design.

Keeping your messages simple, concentrating on data structures rather than
objects, will keep your messages clean, tidy and efficient.

=back

MP/Config.pm  view on Meta::CPAN

Move along please, nothing to see here at the moment.

=cut

package AnyEvent::MP::Config;

use common::sense;

use Carp ();
use AnyEvent ();
use JSON::XS ();

our $VERSION = '2.02';

our $CONFIG_FILE = exists $ENV{PERL_ANYEVENT_MP_RC} ? $ENV{PERL_ANYEVENT_MP_RC}
                   : exists $ENV{HOME}              ? "$ENV{HOME}/.perl-anyevent-mp"
                   :                                  "$ENV{APPDATA}/perl-anyevent-mp";

our %CFG;

sub load {
   if (open my $fh, "<:raw", $CONFIG_FILE) {
      return if eval {
         local $/;
         %CFG = %{ JSON::XS->new->utf8->relaxed->decode (scalar <$fh>) };
         1
      };
   }

   %CFG = (
      version => 1,
   );
}

sub save {
   return unless delete $CFG{dirty};

   open my $fh, ">:raw", "$CONFIG_FILE~new~"
      or Carp::croak "$CONFIG_FILE~new~: $!";

   syswrite $fh, JSON::XS->new->pretty->utf8->encode (\%CFG) . "\n"
      or Carp::croak "$CONFIG_FILE~new~: $!";

   close $fh
      or Carp::croak "$CONFIG_FILE~new~: $!";

   unlink "$CONFIG_FILE~";
   link $CONFIG_FILE, "$CONFIG_FILE~";
   rename "$CONFIG_FILE~new~", $CONFIG_FILE
      or Carp::croak "$CONFIG_FILE: $!";
}

MP/Global.pm  view on Meta::CPAN

use AnyEvent::MP;
use AnyEvent::MP::Kernel;

AE::log 7 => "starting global service.";

#############################################################################
# node protocol parts for global nodes

package AnyEvent::MP::Kernel;

use JSON::XS ();

# TODO: this is ugly (classical use vars vs. our),
# maybe this should go into MP::Kernel

# "import" from Kernel
our %NODE;
our $NODE;
#our $GLOBAL;
our $SRCNODE; # the origin node id
our %NODE_REQ;

MP/Kernel.pm  view on Meta::CPAN


During execution of a message callback, this variable contains the node ID
of the origin node.

The main use of this variable is for debugging output - there are probably
very few other cases where you need to know the source node ID.

=cut

sub _inject {
   warn "RCV $SRCNODE -> " . eval { JSON::XS->new->encode (\@_) } . "\n" if TRACE && @_;

   &{ $PORT{+shift} or return };
}

# this function adds a node-ref, so you can send stuff to it
# it is basically the central routing component.
sub add_node {
   $NODE{$_[0]} || do {
      my ($node) = @_;

MP/Kernel.pm  view on Meta::CPAN

         or Carp::croak "'undef' or the empty string are not valid node/port IDs";

      # registers itself in %NODE
      new AnyEvent::MP::Node::Remote $node
   }
}

sub snd(@) {
   my ($nodeid, $portid) = split /#/, shift, 2;

   warn "SND $nodeid <- " . eval { JSON::XS->new->encode ([$portid, @_]) } . "\n" if TRACE && @_;

   ($NODE{$nodeid} || add_node $nodeid)
      ->{send} (["$portid", @_]);
}

sub port_is_local($) {
   my ($nodeid, undef) = split /#/, $_[0], 2;

   $nodeid eq $NODE
}

MP/Kernel.pm  view on Meta::CPAN

$NODE_REQ{g_slave} = sub {
   # load global module and redo the request
   require AnyEvent::MP::Global;
   &{ $NODE_REQ{g_slave} }
};

#############################################################################
# local database operations

# canonical probably not needed
our $sv_eq_coder = JSON::XS->new->utf8->allow_nonref;

# are the two scalars equal? very very ugly and slow, need better way
sub sv_eq($$) {
   ref $_[0] || ref $_[1]
      ? (JSON::XS::encode $sv_eq_coder, $_[0]) eq (JSON::XS::encode $sv_eq_coder, $_[1])
      : $_[0] eq $_[1]
        && defined $_[0] == defined $_[1]
}

# local database management

sub db_del($@) {
   my $family = shift;

   my @del = grep exists $LOCAL_DB{$family}{$_}, @_;

MP/Transport.pm  view on Meta::CPAN

   my $framing    = $self->{s_framing};
   my $hdl        = $self->{hdl};
   my $push_write = $hdl->can ("push_write");

   if ($framing eq "cbor") {
      require CBOR::XS;
      $self->{send} = sub {
         $push_write->($hdl, CBOR::XS::encode_cbor ($_[0]));
      };
   } elsif ($framing eq "json") {
      require JSON::XS;
      $self->{send} = sub {
         $push_write->($hdl, JSON::XS::encode_json ($_[0]));
      };
   } else {
      $self->{send} = sub {
         $push_write->($hdl, $framing => $_[0]);
      };
   }
}

sub set_rcv_framing {
   my ($self) = @_;

MP/Transport.pm  view on Meta::CPAN


      $hdl->on_read (sub {
         $AnyEvent::MP::Kernel::SRCNODE = $node;

         AnyEvent::MP::Kernel::_inject (@$_)
            for $coder->incr_parse_multiple ($_[0]{rbuf});

         ()
      });
   } elsif ($framing eq "json") {
      require JSON::XS;
      my $coder = JSON::XS->new->utf8;

      $hdl->on_read (sub {
         $AnyEvent::MP::Kernel::SRCNODE = $node;

         AnyEvent::MP::Kernel::_inject (@$_)
            for $coder->incr_parse (delete $_[0]{rbuf});

         ()
      });
   } else {

Makefile.PL  view on Meta::CPAN

    NAME         => "AnyEvent::MP",
    VERSION_FROM => "MP/Config.pm",
    EXE_FILES    => ["bin/aemp"],
    CONFIGURE_REQUIRES => { ExtUtils::MakeMaker => 6.52, Canary::Stability => 0 },
    PREREQ_PM    => {
       AnyEvent           => 6.14,
       AnyEvent::Watchdog => 1.0,
       Digest::SHA3       => 0.24,
       Digest::HMAC       => 1.03,
       MIME::Base64       => 3,
       JSON::XS           => 2.25,
       CBOR::XS           => 1.5,
       Guard              => 1.022,
       common::sense      => 0,
       Task::Weaken       => 0,
    },
    META_MERGE => {
        recommends => {
           Net::Interface => 1.011,
        }
    },

README  view on Meta::CPAN


        And as a result, a port with just a default receiver consists of a
        single code reference stored in a global hash - it can't become much
        cheaper.

    Why favour JSON, why not a real serialising format such as Storable?
        In fact, any AnyEvent::MP node will happily accept Storable as
        framing format, but currently there is no way to make a node use
        Storable by default (although all nodes will accept it).

        The default framing protocol is JSON because a) JSON::XS is many
        times faster for small messages and b) most importantly, after years
        of experience we found that object serialisation is causing more
        problems than it solves: Just like function calls, objects simply do
        not travel easily over the network, mostly because they will always
        be a copy, so you always have to re-think your design.

        Keeping your messages simple, concentrating on data structures
        rather than objects, will keep your messages clean, tidy and
        efficient.

bin/aemp  view on Meta::CPAN

=back

=cut

use common::sense;

# should come before anything else, so all modules
# will be loaded on each restart
BEGIN {
   if (@ARGV == 1 && $ARGV[0] =~ /^\[/) {
      require JSON::XS;
      @ARGV = @{ JSON::XS->new->utf8->decode (shift) };
   } else {
      for (@ARGV) {
         if (/^[\[\{\"]/) {
            require JSON::XS;
            $_ = JSON::XS->new->utf8->allow_nonref->decode ($_);
         }
      }
   }

   if ($ARGV[0] eq "run") {
      shift;

      # d'oh
      require AnyEvent::Watchdog;
      # only now can we load additional modules

bin/aemp  view on Meta::CPAN

      AnyEvent::MP::Kernel::configure (@ARGV);

      AnyEvent::detect () eq "AnyEvent::Impl::EV"
         ? EV::loop ()
         : AE::cv ()->recv;
   }
}

use Carp ();

use JSON::XS;

use AnyEvent;
use AnyEvent::Util;

use AnyEvent::MP;
use AnyEvent::MP::Config;

sub my_run_cmd {
   my ($cmd) = @_;

bin/aemp  view on Meta::CPAN


   print <<EOF;
Entering interactive shell - no commandline editing of course (use rlfe etc.).

\=           display a list of nodes
\=name       switch to another node
package P   switch to package P when evaluating
\$ECHO       contains the name of a port that echos everything sent to it

EOF
   my $json = JSON::XS->new->pretty->ascii;
   my $pkg = "AnyEvent::MP::Kernel";
   my $cv = AE::cv;
   my $echo = port {
      print "\nECHO<$AnyEvent::MP::Kernel::SRCNODE> ", $json->encode (\@_), "\n$node $pkg> ";
   };
   print "$node $pkg> ";
   my $t = AE::io *STDIN, 0, sub {
      chomp (my $line = <STDIN>);

      if ($line =~ s/^=//) {

bin/aemp  view on Meta::CPAN


   my $cv = AE::cv;
   my $to = AE::timer 5, 0, sub { exit 1 };
   AnyEvent::MP::Kernel::eval_on $node, $expr, port { &$cv };
   mon $node, $cv;

   my ($err, @res) = $cv->recv;

   die "$err @res" if length $err;

   print +(substr JSON::XS->new->encode (\@res), 1, -1), "\n";
}

sub docmd;

our %CMD = (
   snd => sub {
      my $port = shift @ARGV;
      init;

      snd $port, @ARGV; @ARGV = ();

bin/aemp  view on Meta::CPAN

      print join " ", $cv->recv, "\n";
   },

   cal => sub {
      my $port = shift @ARGV;
      init;

      my $cv = AE::cv;
      cal $port, @ARGV, sub { &$cv }; @ARGV = ();

      print +(substr JSON::XS->new->encode ([$cv->recv]), 1, -1), "\n";
   },

   mon => sub {
      my $port = shift @ARGV;
      init;

      mon $port, my $cv = AE::cv;
      print join " ", $cv->recv, "\n";
   },

bin/aemp  view on Meta::CPAN

   },
   delparent => sub {
      delete $profile->{parent};
      ++$cfg->{dirty};
   },
   showprofile => sub {
      @ARGV >= 1
         or die "profile name is missing\n";
      my $name = shift @ARGV;

      print JSON::XS->new->pretty->encode ($cfg->{profile}{$name} || {});
   },
   showconfig => sub {
      my $name = @ARGV ? shift @ARGV : AnyEvent::MP::Kernel::nodename;

      my $profile = AnyEvent::MP::Config::find_profile $name, @ARGV;
      @ARGV = ();

      # make it look nicer:
      delete $profile->{profile};
      delete $profile->{parent};

      print JSON::XS->new->pretty->encode ($profile);
   },
);

for my $attr (qw(
   monitor_timeout connect_interval framing_format auth_offer
   auth_accept autocork nodelay secure
)) {
   $CMD{"set$attr"} = sub {
      @ARGV >= 1
         or die "$attr value is missing\n";



( run in 0.553 second using v1.01-cache-2.11-cpan-4d50c553e7e )