ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-Fork-Remote/Remote.pm
Revision: 1.1
Committed: Sat Apr 27 01:44:55 2013 UTC (11 years, 5 months ago) by root
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3     AnyEvent::Fork::Remote - remote processes with AnyEvent::Fork interface
4    
5     THE API IS NOT FINISHED, CONSIDER THIS A BETA RELEASE
6    
7     =head1 SYNOPSIS
8    
9     use AnyEvent;
10     use AnyEvent::Fork::Remote;
11    
12     my $rpc = AnyEvent::Fork::Remote
13     ->new
14     ->require ("MyModule")
15     ->run ("MyModule::run", my $cv = AE::cv);
16    
17     my $fh = $cv->recv;
18    
19     =head1 DESCRIPTION
20    
21     Despite what the name of this module might suggest, it doesn't actualyl
22     create remote processes for you. But it does make it easy to use them,
23     once you have started them.
24    
25     This module implements a very similar API as L<AnyEvent::Fork>. In fact,
26     similar enough to require at most minor modifications to support both
27     at the same time. For example, it works with L<AnyEvent::Fork::RPC> and
28     L<AnyEvent::Fork::Pool>.
29    
30     The documentation for this module will therefore only document the parts
31     of the API that differ between the two modules.
32    
33     =head2 SUMMARY OF DIFFERENCES
34    
35     Here is a short summary of the main differences between L<AnyEvent::Fork>
36     and this module:
37    
38     =over 4
39    
40     =item * C<send_fh> is not implemented and will fail
41    
42     =item * the child-side C<run> function must read from STDIN and write to STDOUT
43    
44     =item * C<fork> does not actually fork, but will create a new process
45    
46     =back
47    
48     =head1 EXAMPLES
49    
50     =head1 PARENT PROCESS USAGE
51    
52     =over 4
53    
54     =cut
55    
56     package AnyEvent::Fork::Remote;
57    
58     use common::sense;
59    
60     use Errno ();
61    
62     use AnyEvent ();
63     use AnyEvent::Util ();
64    
65     our $VERSION = 0.1;
66    
67     # xored together must start and and with \n
68     my $magic0 = "Pdk{6y[_zZ";
69     my $magic1 = "Z^yZ7~i=oP";
70    
71     =item my $proc = new_exec AnyEvent::Fork::Remote $path, @args...
72    
73     Creates a new C<AnyEvent::Fork::Remote> object. Unlike L<AnyEvent::Fork>,
74     processes are only created when C<run> is called, every other method call
75     is is simply recorded until then.
76    
77     Each time a new process is needed, it executes C<$path> with the given
78     arguments (the first array member must be the program name, as with
79     the C<exec> function with explicit PROGRAM argument) and both C<STDIN>
80     and C<STDOUT> connected to a communications socket. No input must be
81     consumed by the comamnd before F<perl> is started, and no output should be
82     generated.
83    
84     The program I<must> invoke F<perl> somehow, with STDIN and STDOUT intact,
85     without specifying anything to execute (no script file name, no C<-e>
86     switch etc.).
87    
88     Here are some examples to give you an idea:
89    
90     # just "perl"
91     $proc = new_exec AnyEvent::Fork::Remote
92     "/usr/bin/perl", "perl";
93    
94     # rsh othernode exec perl
95     $proc = new_exec AnyEvent::Fork::Remote
96     "/usr/bin/rsh", "rsh", "othernode", "exec perl";
97    
98     # a complicated ssh command
99     $proc = new_exec AnyEvent::Fork::Remote
100     "/usr/bin/ssh",
101     qw(ssh -q
102     -oCheckHostIP=no -oTCPKeepAlive=yes -oStrictHostKeyChecking=no
103     -oGlobalKnownHostsFile=/dev/null -oUserKnownHostsFile=/dev/null
104     otherhost
105     exec perl);
106    
107     =item my $proc = new AnyEvent::Fork::Remote $create_callback
108    
109     Basically the same as C<new_exec>, but instead of a hardcoded command
110     path, it expects a callback which is invoked each time a process needs to
111     be created.
112    
113     The C<$create_callback> is called with another callback as argument,
114     and should call this callback with the file handle that is connected
115     to a F<perl> process. This callback can be invoked even after the
116     C<$create_callback> returns.
117    
118     Example: emulate C<new_exec> using C<new>.
119    
120     use AnyEvent::Util;
121     use Proc::FastSpawn;
122    
123     $proc = new AnyEvent::Fork::Remote sub {
124     my $done = shift;
125    
126     my ($a, $b) = AnyEvent::Util::portable_socketpair
127     or die;
128    
129     open my $oldin , "<&0" or die;
130     open my $oldout, ">&1" or die;
131    
132     open STDIN , "<&" . fileno $b or die;
133     open STDOUT, ">&" . fileno $b or die;
134    
135     spawn "/usr/bin/rsh", ["rsh", "othernode", "perl"];
136    
137     open STDIN , "<&" . fileno $oldin ;
138     open STDOUT, ">&" . fileno $oldout;
139    
140     $done->($a);
141     };
142    
143     =cut
144    
145     sub new_exec {
146     my ($class, $program, @argv) = @_;
147    
148     require AnyEvent::Util;
149     require Proc::FastSpawn;
150    
151     $class->new (sub {
152     my $done = shift;
153    
154     my ($a, $b) = AnyEvent::Util::portable_socketpair ()
155     or die;
156    
157     open my $oldin , "<&0" or die;
158     open my $oldout, ">&1" or die;
159    
160     open STDIN , "<&" . fileno $b or die;
161     open STDOUT, ">&" . fileno $b or die;
162    
163     Proc::FastSpawn::spawn ($program, \@argv);
164    
165     open STDIN , "<&" . fileno $oldin ;
166     open STDOUT, ">&" . fileno $oldout;
167    
168     $done->($a);
169     })
170     }
171    
172     sub new {
173     my ($class, $create) = @_;
174    
175     bless [
176     $create,
177     "",
178     [],
179     ], $class
180     }
181    
182     =item $new_proc = $proc->fork
183    
184     Quite the same as the same method of L<AnyEvent::Fork>, except that it
185     simply clones the object without creating an actual process.
186    
187     =cut
188    
189     sub fork {
190     my $self = shift;
191    
192     bless [
193     $self->[0],
194     $self->[1],
195     [@{ $self->[2] }],
196     ], ref $self
197     }
198    
199     =item undef = $proc->pid
200    
201     The C<pid> method always returns C<undef> and only exists for
202     compatibility with L<AnyEvent::Fork>.
203    
204     =cut
205    
206     sub pid {
207     undef
208     }
209    
210     =item $proc = $proc->send_fh (...)
211    
212     Not supported and always croaks.
213    
214     =cut
215    
216     sub send_fh {
217     require Carp;
218     Carp::croak ("send_fh is not supported on AnyEvent::Fork::Remote objects");
219     }
220    
221     =item $proc = $proc->eval ($perlcode, @args)
222    
223     Quite the same as the same method of L<AnyEvent::Fork>.
224    
225     =cut
226    
227     # quote a binary string as a perl scalar
228     sub sq($) {
229     my $s = shift;
230    
231     $s =~ /'/
232     or return "'$s'";
233    
234     $s =~ s/(\x10+)/\x10.'$1'.q\x10/g;
235     "q\x10$s\x10"
236     }
237    
238     # quote a list of strings
239     sub aq(@) {
240     "(" . (join ",", map sq $_, @_) . ")"
241     }
242    
243     sub eval {
244     my ($self, $perlcode, @args) = @_;
245    
246     $self->[1] .= '{ local @_ = ' . (aq @args) . "; $perlcode }\n";
247     }
248    
249     =item $proc = $proc->require ($module, ...)
250    
251     Quite the same as the same method of L<AnyEvent::Fork>.
252    
253     =cut
254    
255     sub require {
256     my ($self, @modules) = @_;
257    
258     s%::%/%g for @modules;
259     $self->eval ('require "$_.pm" for @_', @modules);
260    
261     $self
262     }
263    
264     =item $proc = $proc->send_arg ($string, ...)
265    
266     Quite the same as the same method of L<AnyEvent::Fork>.
267    
268     =cut
269    
270     sub send_arg {
271     my ($self, @arg) = @_;
272    
273     push @{ $self->[2] }, @arg;
274    
275     $self
276     }
277    
278     =item $proc->run ($func, $cb->($fh))
279    
280     Very similar to the run method of L<AnyEvent::Fork>.
281    
282     On the parent side, the API is identical. On the child side, the
283     "communications socket" is in fact just C<*STDIN>, and typically can only
284     be read from.
285    
286     If the run function wants to read data that is written to C<$fh> in the
287     parent, then it should read from STDIN. If the run function wants to
288     provide data that can later be read from C<$fh>, then it should write them
289     to STDOUT.
290    
291     You can write a run function that works with both L<AnyEvent::Fork> and
292     this module by checking C<fileno $fh> in on the passed callback in the run
293     function:
294    
295     sub run {
296     my ($rfh, ...) = @_;
297     my $wfh = fileno $rfh ? $rfh : *STDOUT;
298    
299     # now use $rfh for reading and $wfh for writing
300     }
301    
302     =cut
303    
304     sub run {
305     my ($self, $func, $cb) = @_;
306    
307     my $code = 'BEGIN {' . $self->[1] . '}'
308     . 'syswrite STDOUT, ' . (sq $magic0) . '^' . (sq $magic1) . ';'
309     . $func . (aq @{ $self->[2] }) . ';'
310     . "\n__END__\n";
311    
312     $self->[0](sub {
313     my $fh = shift
314     or die "AnyEvent::Fork::Remote: create callback failed";
315    
316    
317    
318     });
319     }
320    
321     my $x = new_exec AnyEvent::Fork::Remote "/usr/bin/rsh", "rsh", "rain", "exec perl";#d#
322     $x->require ("Carp", "Storable");#d#
323     $x->send_arg (1, 2, 3);#d#
324     $x->eval ('sub run { die }');#d#
325     $x->run ("run", sub {
326     });
327    
328    
329     =item my $proc = new_from_stdio $fh
330    
331     Creates an C<AnyEvent::Fork::Remote> object from a file handle. This file
332     handle must be connected to both STDIN and STDOUT of a F<perl> process.
333    
334     This form might be more convenient than C<new> or C<new_exec> when
335     creating an C<AnyEvent::Fork::Remote> object, but the resulting object
336     does not support C<fork>.
337    
338     #TODO: really implement?
339    
340     =back
341    
342     =head1 SEE ALSO
343    
344     L<AnyEvent::Fork>, the same as this module, for local processes.
345    
346     L<AnyEvent::Fork::RPC>, to talk to the created processes.
347    
348     L<AnyEvent::Fork::Pool>, to manage whole pools of processes.
349    
350     =head1 AUTHOR AND CONTACT INFORMATION
351    
352     Marc Lehmann <schmorp@schmorp.de>
353     http://software.schmorp.de/pkg/AnyEvent-Fork-Remote
354    
355     =cut
356    
357     1
358