File Coverage

blib/lib/POE/Devel/ProcAlike.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             # Declare our package
2             package POE::Devel::ProcAlike;
3 1     1   3344 use strict; use warnings;
  1     1   3  
  1         36  
  1         6  
  1         2  
  1         460  
4              
5             # Initialize our version
6 1     1   8 use vars qw( $VERSION );
  1         2  
  1         59  
7             $VERSION = '0.02';
8              
9             # Import what we need from the POE namespace
10 1     1   462 use POE;
  0            
  0            
11             use POE::Component::Fuse;
12             use base 'POE::Session::AttributeBased';
13              
14             # load our modules to manage the filesystem
15             use Filesys::Virtual::Async::Dispatcher;
16             use Filesys::Virtual::Async::inMemory;
17             use POE::Devel::ProcAlike::POEInfo;
18             use POE::Devel::ProcAlike::PerlInfo;
19             use POE::Devel::ProcAlike::ModuleInfo;
20              
21             # portability...
22             use File::Spec;
23              
24             # Set some constants
25             BEGIN {
26             if ( ! defined &DEBUG ) { *DEBUG = sub () { 0 } }
27             }
28              
29             # starts the component!
30             sub spawn {
31             my $class = shift;
32              
33             # are we already created?
34             if ( $poe_kernel->alias_resolve( 'poe-devel-procalike' ) ) {
35             if ( DEBUG ) {
36             warn "Calling " . __PACKAGE__ . "->spawn() multiple times will only result in a singleton!";
37             }
38             return 1;
39             }
40              
41             # The options hash
42             my %opt;
43              
44             # Support passing in a hash ref or a regular hash
45             if ( ( @_ & 1 ) and ref $_[0] and ref( $_[0] ) eq 'HASH' ) {
46             %opt = %{ $_[0] };
47             } else {
48             # Sanity checking
49             if ( @_ & 1 ) {
50             warn __PACKAGE__ . ' requires an even number of options passed to spawn()';
51             return 0;
52             }
53              
54             %opt = @_;
55             }
56              
57             # lowercase keys
58             %opt = map { lc($_) => $opt{$_} } keys %opt;
59              
60             # setup the FUSE mount options
61             if ( ! exists $opt{'fuseopts'} or ! defined $opt{'fuseopts'} ) {
62             if ( DEBUG ) {
63             warn 'Using default FUSEOPTS = undef';
64             }
65              
66             # Set the default
67             $opt{'fuseopts'} = undef;
68             } else {
69             # TODO validate for sanity
70             }
71              
72             # setup the user-supplied "misc" fsv object
73             if ( ! exists $opt{'vfilesys'} or ! defined $opt{'vfilesys'} ) {
74             if ( DEBUG ) {
75             warn 'Using default VFILESYS = undef';
76             }
77              
78             # Set the default
79             $opt{'vfilesys'} = undef;
80             } else {
81             # make sure it's a real object
82             if ( ! ref $opt{'vfilesys'} ) {
83             warn 'The passed-in vfilesys option is not an object';
84             return 0;
85             } else {
86             if ( ! $opt{'vfilesys'}->isa( 'Filesys::Virtual::Async' ) ) {
87             warn 'The passed-in vfilesys object is not a subclass of Filesys::Virtual::Async';
88             return 0;
89             }
90             }
91             }
92              
93             # Create our session
94             POE::Session->create(
95             __PACKAGE__->inline_states(),
96             'heap' => {
97             'ALIAS' => 'poe-devel-procalike',
98             'FUSEOPTS' => $opt{'fuseopts'},
99              
100             # our filesystem objects
101             'DISPATCHER' => undef,
102             'ROOTFS' => undef,
103             'PERLFS' => POE::Devel::ProcAlike::PerlInfo->new(),
104             'POEFS' => POE::Devel::ProcAlike::POEInfo->new(),
105             'MODULEFS' => POE::Devel::ProcAlike::ModuleInfo->new(),
106             'MISCFS' => $opt{'vfilesys'},
107             },
108             );
109              
110             # return success
111             return 1;
112             }
113              
114             # This starts the component
115             sub _start : State {
116             if ( DEBUG ) {
117             warn 'Starting alias "' . $_[HEAP]->{'ALIAS'} . '"';
118             }
119              
120             # Set up the alias for ourself
121             $_[KERNEL]->alias_set( $_[HEAP]->{'ALIAS'} );
122              
123             # create the root filesystem for use in the Dispatcher
124             my $filesystem = {
125             File::Spec->rootdir() => {
126             'mode' => => oct( '040755' ),
127             'ctime' => time(),
128             },
129             File::Spec->catdir( File::Spec->rootdir(), 'perl' ) => {
130             'mode' => => oct( '040755' ),
131             'ctime' => time(),
132             },
133             File::Spec->catdir( File::Spec->rootdir(), 'kernel' ) => {
134             'mode' => => oct( '040755' ),
135             'ctime' => time(),
136             },
137             File::Spec->catdir( File::Spec->rootdir(), 'modules' ) => {
138             'mode' => => oct( '040755' ),
139             'ctime' => time(),
140             },
141             File::Spec->catdir( File::Spec->rootdir(), 'misc' ) => {
142             'mode' => => oct( '040755' ),
143             'ctime' => time(),
144             },
145             };
146             $_[HEAP]->{'ROOTFS'} = Filesys::Virtual::Async::inMemory->new(
147             'filesystem' => $filesystem,
148             'readonly' => 1,
149             );
150              
151             # finally, tie them all together in the dispatcher!
152             $_[HEAP]->{'DISPATCHER'} = Filesys::Virtual::Async::Dispatcher->new(
153             'rootfs' => $_[HEAP]->{'ROOTFS'},
154             );
155             $_[HEAP]->{'DISPATCHER'}->mount( File::Spec->catdir( File::Spec->rootdir(), 'perl' ), $_[HEAP]->{'PERLFS'} );
156             $_[HEAP]->{'DISPATCHER'}->mount( File::Spec->catdir( File::Spec->rootdir(), 'kernel' ), $_[HEAP]->{'POEFS'} );
157             $_[HEAP]->{'DISPATCHER'}->mount( File::Spec->catdir( File::Spec->rootdir(), 'modules' ), $_[HEAP]->{'MODULEFS'} );
158             if ( defined $_[HEAP]->{'MISCFS'} ) {
159             $_[HEAP]->{'DISPATCHER'}->mount( File::Spec->catdir( File::Spec->rootdir(), 'misc' ), $_[HEAP]->{'MISCFS'} );
160             }
161              
162             # spawn the fuse poco
163             POE::Component::Fuse->spawn(
164             'umount' => 1,
165             'mkdir' => 1,
166             'mount' => "/tmp/poefuse_$$",
167             'rmdir' => 1,
168             ( defined $_[HEAP]->{'FUSEOPTS'} ? %{ $_[HEAP]->{'FUSEOPTS'} } : () ),
169              
170             # make sure the user cannot override those options
171             'alias' => $_[HEAP]->{'ALIAS'} . '-fuse',
172             'vfilesys' => $_[HEAP]->{'DISPATCHER'},
173             'session' => $_[SESSION]->ID,
174             );
175              
176             return;
177             }
178              
179             # POE Handlers
180             sub _stop : State {
181             if ( DEBUG ) {
182             warn 'Stopping alias "' . $_[HEAP]->{'ALIAS'} . '"';
183             }
184              
185             return;
186             }
187              
188             sub shutdown : State {
189             # cleanup some stuff
190             $_[KERNEL]->alias_remove( $_[HEAP]->{'ALIAS'} );
191              
192             # tell poco-fuse to shutdown
193             $_[KERNEL]->post( $_[HEAP]->{'ALIAS'} . '-fuse', 'shutdown' );
194              
195             return;
196             }
197              
198             # handles poco-fuse shutting down
199             sub fuse_CLOSED : State {
200             $_[KERNEL]->yield( 'shutdown' );
201              
202             return;
203             }
204              
205             # adds a poco to the fs
206             sub register : State {
207             my $fsv = $_[ARG0];
208              
209             # determine caller info
210             my $module = ( caller(4) )[0];
211             if ( $module eq 'POE::Kernel' ) {
212             # we were not dispatched via call(), complain!
213             warn "Registering a module must be done via call() not post()";
214             return;
215             }
216              
217             # Weed out modules that we know is unable to register
218             if ( $module eq 'main' ) {
219             warn "Unable to register from package 'main' because it is ambiguous, please do so from a proper package";
220             return;
221             }
222              
223             # is the fsv a valid object?
224             if ( ! defined $fsv or ! ref $fsv or ! $fsv->isa( 'Filesys::Virtual::Async' ) ) {
225             warn "The FsV object is not a valid subclass of Filesys::Virtual::Async";
226             return;
227             }
228              
229             # Try to register the module!
230             my $result = $_[HEAP]->{'MODULEFS'}->register( $module );
231             if ( defined $result ) {
232             # successfully registered, add it to the dispatcher!
233             $_[HEAP]->{'DISPATCHER'}->mount( File::Spec->catdir( File::Spec->rootdir(), 'modules', $result ), $fsv );
234             return 1;
235             } else {
236             warn "The package '$module' is already registered";
237             return;
238             }
239             }
240              
241             # removes a poco from the fs
242             sub unregister : State {
243             # determine caller info
244             my $module = ( caller(4) )[0];
245             if ( $module eq 'POE::Kernel' ) {
246             # we were not dispatched via call(), complain!
247             warn "Unregistering a module must be done via call() not post()";
248             return;
249             }
250              
251             # Weed out modules that we know is unable to register
252             if ( $module eq 'main' ) {
253             warn "Unable to register from package 'main' because it is ambiguous, please do so from a proper package";
254             return;
255             }
256              
257             # Try to register the module!
258             my $result = $_[HEAP]->{'MODULEFS'}->unregister( $module );
259             if ( defined $result ) {
260             # successfully unregistered, remove it from the dispatcher!
261             $_[HEAP]->{'DISPATCHER'}->umount( File::Spec->catdir( File::Spec->rootdir(), 'modules', $result ) );
262             return 1;
263             } else {
264             warn "The package '$module' was never registered";
265             return;
266             }
267             }
268              
269             1;
270             __END__