File Coverage

lib/CPANPLUS/Daemon.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package CPANPLUS::Daemon;
2              
3 1     1   134583 use strict;
  1         6  
  1         54  
4 1     1   6 use vars qw[$VERSION];
  1         6  
  1         41  
5              
6 1     1   49 use IO::String;
  1         2  
  1         33  
7 1     1   6 use Params::Check qw[check];
  1         2  
  1         66  
8 1     1   820 use POE qw[Component::Server::TCP];
  0            
  0            
9             use CPANPLUS::Shell qw[Default];
10             use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext';
11              
12             use base 'Object::Accessor';
13              
14             local $Params::Check::VERBOSE = 1;
15              
16             $VERSION = '0.02';
17              
18             =pod
19              
20             =head1 NAME
21              
22             CPANPLUS::Daemon -- Remote CPANPLUS access
23              
24             =head1 SYNOPSIS
25              
26             ### from the command line
27             cpanpd -p secret # using defaults
28             cpanpd -P 666 -u my_user -p secret # options provided, recommended
29              
30             ### using the API
31             use CPANPLUS::Daemon;
32             $daemon = CPANPLUS::Daemon->new(
33             username => 'my_user',
34             password => 'secret',
35             port => 666,
36             );
37             $daemon->run;
38            
39             ### (dis)connecting to the daemon, from the default shell
40             CPAN Terminal> /connect --user=my_user --pass=secret localhost 666
41             ...
42             CPAN Terminal> /disconnect
43            
44             =head1 DESCRIPTION
45              
46             C let's you run a daemon that listens on a specified
47             port and can act as a remote backend to your L.
48              
49             You can use the L shell to connect to the
50             daemon.
51             Note that both sides (ie, both the server and the client) ideally
52             should run the same version of the L, to
53             ensure maximum compatibillity
54              
55             See the L documentation on how to connect
56             to a remote daemon.
57              
58             =head1 METHODS
59              
60             =head2 $daemon = CPANPLUS::Daemon->new(password => $pass, [username => $user, port => $port]);
61              
62             Creates a new C object, based on the following paremeters:
63              
64             =over 4
65              
66             =item password (required)
67              
68             The password needed to connect to this server instance
69              
70             =item username (optional)
71              
72             The user needed to connect to this server instance. Defaults to C.
73              
74             =item port
75              
76             The port number this server instance will listen on. Defaults to C<1337>.
77              
78             =back
79              
80             =cut
81              
82             sub new {
83             my $class = shift;
84             my %hash = @_;
85             my $self = bless {}, $class;
86              
87             my $tmpl = {
88             password => { required => 1 },
89             username => { default => 'cpanpd' },
90             port => { default => 1337 },
91             };
92              
93             $self->mk_accessors( qw[conf shell], keys %$tmpl );
94              
95             $self->shell( CPANPLUS::Shell->new() );
96             $self->conf( $self->shell->backend->configure_object );
97              
98              
99             my $args = check( $tmpl, \%hash ) or return;
100              
101             ### make sure to disable the pager ###
102             $self->conf->set_program( pager => '' );
103              
104             ### store all provided opts as accessors
105             $self->$_( $args->{$_} ) for keys %$tmpl;
106              
107             return $self;
108             }
109              
110             =head2 $daemon->run( [stdout => \*OUT, stderr => \*ERR] );
111              
112             This actually makes the daemon active. Note that from here on, you lose
113             control of the program, and it is handed to the daemon. You can now
114             only exit the program via a C or another way that terminates
115             the process.
116              
117             You can override where the daemon sends its output by supplying the an
118             alternate filehandle via the C and C parameter
119              
120             =cut
121              
122             sub run {
123             my $self = shift;
124             my %hash = @_;
125              
126             $|++;
127             ### redirect STDOUT and STDERR ###
128             local *STDOUT_SAVE;
129             local *STDERR_SAVE;
130              
131             open( STDOUT_SAVE, ">&STDOUT" ) or warn loc("Couldn't dup STDOUT: %1");
132             open( STDERR_SAVE, ">&STDERR" ) or warn loc("Couldn't dup STDERR: %1");
133              
134             my($stdout_fh, $stderr_fh);
135             my $tmpl = {
136             stdout => { default => \*STDOUT_SAVE, store => \$stdout_fh },
137             stderr => { default => \*STDERR_SAVE, store => \$stderr_fh },
138             };
139            
140             check( $tmpl, \%hash ) or return;
141              
142             #close *STDOUT; close *STDERR;
143             *STDERR = *STDOUT;
144              
145             POE::Component::Server::TCP->new(
146             Alias => "cpanpd",
147             Port => $self->port,
148             ClientInput => sub {
149             my ($session, $heap, $input) = @_[SESSION, HEAP, ARG0];
150              
151             my $remote_host = $heap->{remote_ip} .':'.
152             $heap->{remote_port};
153             my($user,$pass,$command) = split "\0", $input;
154              
155             my $status; # the status value to return 0 || 1
156             my $msg; # the message we'll send back
157             my $locmsg; # the message we'll print locally
158              
159             unless( $user eq $self->username and $pass eq $self->password ) {
160              
161             $status = 0;
162             $msg = loc( "Remote command failed: Invalid password ".
163             "for user '%1'\n", $user). "\n";
164             $locmsg = "[$remote_host] ". $msg;
165              
166             } else {
167              
168             ### print it now anyway, so we can see what the daemon
169             ### is currently doing
170             print $stdout_fh loc("[%1] Running '%2'\n",
171             $remote_host, $command );
172              
173             $status = 1;
174              
175             ### VERSION verification for compatibility ###
176             if( $command =~ /^VERSION=(.+)$/ ) {
177             my $local_ver = $CPANPLUS::Shell::Default::VERSION;
178             my $remote_ver = $1 || 0;
179              
180             if( $local_ver != $remote_ver) {
181             $msg = loc("Differing shell versions detected:\n".
182             "Local: %1\n".
183             "Remote: %2\n".
184             "Continuing is not advised, do so at your ".
185             "own risk", $local_ver, $remote_ver);
186              
187             $locmsg = loc( '[%1] Differing version detected'.
188             '. remote: %1 local %2',
189             $remote_host, $remote_ver,
190             $local_ver ). "\n";
191             } else {
192             $msg = loc("Connection accepted" );
193             $locmsg = loc('[%1] Connection accepted',
194             $remote_host ). "\n";
195             }
196              
197             ### normal command ###
198             } else {
199             tie *STDOUT, 'IO::String';
200             $self->shell->dispatch_on_input( input => $command );
201              
202             seek( STDOUT, 0, 0 );
203              
204             $msg .= join "", ;
205             }
206             }
207              
208             ### print the local message, send back and answer + status
209             print $stdout_fh $locmsg;
210             $heap->{client}->put( $status ."\0". $msg);
211             }
212             );
213              
214             print $stdout_fh loc("Starting '%1' on port %2...", 'cpanpd', $self->port ).$/;
215              
216             $poe_kernel->run;
217              
218             print $stdout_fh loc("Exiting '%1'...", 'cpanpd').$/;
219             exit 0;
220             }
221              
222             1;
223              
224             =head1 AUTHOR
225              
226             This module by Jos Boumans Ekane@cpan.orgE.
227              
228             =head1 COPYRIGHT
229              
230             This module is copyright (c) 2005 Jos Boumans Ekane@cpan.orgE.
231             All rights reserved.
232              
233             This library is free software; you may redistribute and/or modify it
234             under the same terms as Perl itself.
235              
236             =cut
237              
238             # Local variables:
239             # c-indentation-style: bsd
240             # c-basic-offset: 4
241             # indent-tabs-mode: nil
242             # End:
243             # vim: expandtab shiftwidth=4: