remove vestigial IPC::Open2 from PerlInterpreter.pm
[scpubgit/Object-Remote.git] / lib / Object / Remote.pm
index 680197e..b8f7645 100644 (file)
 package Object::Remote;
 
 use Object::Remote::MiniLoop;
-use Object::Remote::Proxy;
-use Scalar::Util qw(weaken blessed);
-use Object::Remote::Future;
+use Object::Remote::Handle;
+use Object::Remote::Logging qw( :log );
 use Module::Runtime qw(use_module);
-use Moo;
+
+our $VERSION = '0.003000'; # 0.3.0
 
 sub new::on {
   my ($class, $on, @args) = @_;
-  __PACKAGE__->new(
-    connection => $on,
-    class => $class,
-    args => \@args
-  )->proxy;
+  my $conn = __PACKAGE__->connect($on);
+  log_trace { sprintf("constructing instance of $class on connection for child pid of %i", $conn->child_pid) };
+  return $conn->remote_object(class => $class, args => \@args);
 }
 
-has connection => (
-  is => 'ro', required => 1,
-  coerce => sub {
-    blessed($_[0])
-      ? $_[0]
-      : use_module('Object::Remote::Connection')->new_from_spec($_[0])
-  },
-);
-
-has id => (is => 'rwp');
-
-has disarmed_free => (is => 'rwp');
-
-sub disarm_free { $_[0]->_set_disarmed_free(1); $_[0] }
+sub can::on {
+  my ($class, $on, $name) = @_;
+  my $conn = __PACKAGE__->connect($on);
+  log_trace { "Invoking remote \$class->can('$name')" };
+  return $conn->remote_sub(join('::', $class, $name));
+}
 
-sub proxy {
-  bless({ remote => $_[0], method => 'call' }, 'Object::Remote::Proxy');
+sub new {
+  shift;
+  Object::Remote::Handle->new(@_)->proxy;
 }
 
-sub BUILD {
-  my ($self, $args) = @_;
-  unless ($self->id) {
-    die "No id supplied and no class either" unless $args->{class};
-    ref($_) eq 'HASH' and $_ = [ %$_ ] for $args->{args};
-    $self->_set_id(
-      await_future(
-        $self->connection->send(
-          class_call => $args->{class}, 0,
-          $args->{constructor}||'new', @{$args->{args}||[]}
-        )
-      )->{remote}->disarm_free->id
-    );
-  }
-  $self->connection->register_remote($self);
+sub connect {
+  my ($class, $to) = @_;
+  use_module('Object::Remote::Connection')->maybe::start::new_from_spec($to);
 }
 
 sub current_loop {
   our $Current_Loop ||= Object::Remote::MiniLoop->new
 }
 
-sub call {
-  my ($self, $method, @args) = @_;
-  my $w = wantarray;
-  $method = "start::${method}" if (caller(0)||'') eq 'start';
-  future {
-    $self->connection->send(call => $self->id, $w, $method, @args)
-  };
-}
+1;
 
-sub call_discard {
-  my ($self, $method, @args) = @_;
-  $self->connection->send_discard(call => $self->id, $method, @args);
-}
+=head1 NAME
 
-sub call_discard_free {
-  my ($self, $method, @args) = @_;
-  $self->disarm_free;
-  $self->connection->send_discard(call_free => $self->id, $method, @args);
-}
+Object::Remote - Call methods on objects in other processes or on other hosts
 
-sub DEMOLISH {
-  my ($self, $gd) = @_;
-  return if $gd or $self->disarmed_free;
-  $self->connection->send_free($self->id);
-}
+=head1 SYNOPSIS
 
-1;
+Creating a connection:
+
+  use Object::Remote;
+
+  my $conn = Object::Remote->connect('myserver'); # invokes ssh
+
+Calling a subroutine:
+
+  my $capture = IPC::System::Simple->can::on($conn, 'capture');
+
+  warn $capture->('uptime');
+
+Using an object:
+
+  my $eval = Eval::WithLexicals->new::on($conn);
+
+  $eval->eval(q{my $x = `uptime`});
+
+  warn $eval->eval(q{$x});
+
+Importantly: 'myserver' only requires perl 5.8+ - no non-core modules need to
+be installed on the far side, Object::Remote takes care of it for you!
+
+=head1 DESCRIPTION
+
+Object::Remote allows you to create an object in another process - usually
+one running on another machine you can connect to via ssh, although there
+are other connection mechanisms available.
+
+The idea here is that in many cases one wants to be able to run a piece of
+code on another machine, or perhaps many other machines - but without having
+to install anything on the far side.
+
+=head1 COMPONENTS
+
+=head2 Object::Remote
+
+The "main" API, which provides the L</connect> method to create a connection
+to a remote process/host, L</new::on> to create an object on a connection,
+and L</can::on> to retrieve a subref over a connection.
+
+=head2 Object::Remote::Connection
+
+The object representing a connection, which provides the
+L<Object::Remote::Connection/remote_object> and
+L<Object::Remote::Connection/remote_sub> methods that are used by
+L</new::on> and L</can::on> to return proxies for objects and subroutines
+on the far side.
+
+=head2 Object::Remote::Future
+
+Code for dealing with asynchronous operations, which provides the
+L<Object::Remote::Future/start::method> syntax for calling a possibly
+asynchronous method without blocking, and
+L<Object::Remote::Future/await_future> and L<Object::Remote::Future/await_all>
+to block until an asynchronous call completes or fails.
+
+=head1 METHODS
+
+=head2 connect
+
+  my $conn = Object::Remote->connect('-'); # fork()ed connection
+
+  my $conn = Object::Remote->connect('myserver'); # connection over ssh
+
+  my $conn = Object::Remote->connect('user@myserver'); # connection over ssh
+
+  my $conn = Object::Remote->connect('root@'); # connection over sudo
+
+=head2 new::on
+
+  my $eval = Eval::WithLexicals->new::on($conn);
+
+  my $eval = Eval::WithLexicals->new::on('myserver'); # implicit connect
+
+  my $obj = Some::Class->new::on($conn, %args); # with constructor arguments
+
+=head2 can::on
+
+  my $hostname = Sys::Hostname->can::on($conn, 'hostname');
+
+  my $hostname = Sys::Hostname->can::on('myserver', 'hostname');
+
+=head1 ENVIRONMENT
+
+=over 4
+
+=item OBJECT_REMOTE_PERL_BIN
+
+When starting a new Perl interpreter the contents of this environment
+variable will be used as the path to the executable. If the variable
+is not set the path is 'perl'
+
+=item OBJECT_REMOTE_LOG_LEVEL
+
+Setting this environment variable will enable logging and send all log messages
+at the specfied level or higher to STDERR. Valid level names are: trace debug
+verbose info warn error fatal
+
+=item OBJECT_REMOTE_LOG_FORMAT
+
+The format of the logging output is configurable. By setting this environment variable
+the format can be controlled via printf style position variables. See
+L<Object::Remote::Logging::Logger>.
+
+=item OBJECT_REMOTE_LOG_FORWARDING
+
+Forward log events from remote connections to the local Perl interpreter. Set to 0 to disable
+this feature which is enabled by default. See L<Object::Remote::Logging>.
+
+=item OBJECT_REMOTE_LOG_SELECTIONS
+
+Space seperated list of class names to display logs for if logging output is enabled. Default
+value is "Object::Remote::Logging" which selects all logs generated by Object::Remote.
+See L<Object::Remote::Logging::Router>.
+
+=back
+
+=head1 SUPPORT
+
+IRC: #web-simple on irc.perl.org
+
+=head1 AUTHOR
+
+mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
+
+=head1 CONTRIBUTORS
+
+phaylon - Robert Sedlacek (cpan:PHAYLON) <r.sedlacek@shadowcat.co.uk>
+
+triddle - Tyler Riddle (cpan:TRIDDLE) <t.riddle@shadowcat.co.uk>
+
+=head1 SPONSORS
+
+Parts of this code were paid for by
+
+  Socialflow L<http://www.socialflow.com>
+
+  Shadowcat Systems L<http://www.shadow.cat>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2012 the Object::Remote L</AUTHOR>, L</CONTRIBUTORS> and
+L</SPONSORS> as listed above.
+
+=head1 LICENSE
+
+This library is free software and may be distributed under the same terms
+as perl itself.
+
+=cut