File Coverage

blib/lib/Sprocket.pm
Criterion Covered Total %
statement 129 144 89.5
branch 21 40 52.5
condition 3 6 50.0
subroutine 31 32 96.8
pod 4 13 30.7
total 188 235 80.0


line stmt bran cond sub pod time code
1             package Sprocket;
2              
3 13     13   1590443 use strict;
  13         30  
  13         342  
4 13     13   76 use warnings;
  13         27  
  13         438  
5              
6             our $VERSION = '0.07';
7              
8 13     13   3045 use Carp qw( croak );
  13         36  
  13         517  
9 13     13   4240 use Sprocket::Common;
  13         33  
  13         173  
10 13     13   83 use POE;
  13         23  
  13         111  
11              
12             our $sprocket;
13             our $sprocket_aio;
14              
15 13     13   8542 use Sprocket::AIO;
  13         33  
  13         75  
16 13     13   2940 use Scalar::Util qw( weaken );
  13         31  
  13         1084  
17              
18 13     13   5471 use Sprocket::Util::Observable;
  13         41  
  13         379  
19 13     13   80 use base qw( Sprocket::Util::Observable );
  13         27  
  13         2386  
20              
21             # weak list of all sprocket components
22             our %COMPONENTS;
23             our %PLUGINS;
24              
25             # events sent to process_plugins
26             sub EVENT_NAME() { 0 }
27             sub SERVER() { 1 }
28             sub CONNECTION() { 2 }
29              
30              
31             sub import {
32 52     52   6202 shift;
33              
34 52         112 my @modules = @_;
35              
36 52         154 unshift( @modules, 'Common' );
37 52         132 @modules = map { 'Sprocket::'.$_ } @modules;
  96         296  
38            
39 52         161 unshift( @modules, 'POE' );
40              
41 52         123 my $package = caller();
42 52         71 my @failed;
43              
44 52         117 foreach my $module ( @modules ) {
45 143         3012 my $code = "package $package; use $module;";
46 13     13   79 eval( $code );
  13     13   24  
  13         67  
  13         82  
  13         27  
  13         125  
  143         7871  
47 143 50       13162 if ( $@ ) {
48 5         26 warn $@;
49 5         11 push( @failed, $module );
50             }
51             }
52              
53 52 100       190 unless ( defined( $sprocket ) ) {
54 13         592 Sprocket->new();
55             }
56              
57             {
58 13     13   3117 no strict 'refs';
  13         30  
  13         10801  
  52         93  
59 52         142 *{ $package . '::sprocket' } = \$sprocket;
  52         323  
60             }
61              
62 52 50       1170 @failed and croak 'could not import (' . join( ' ', @failed ) . ')';
63             }
64              
65             sub new {
66 13     13 0 44 my $class = shift;
67 13 50       72 croak "$class requires an even number of parameters" if @_ % 2;
68 13 50       37 return $sprocket if ( defined( $sprocket ) );
69              
70 13         110 my $self = $sprocket = $class->SUPER::new( @_ );
71 13         2150 $self->{_uuid} = gen_uuid( $self );
72            
73 13         232 $self->register_hook( [qw(
74             sprocket.component.add
75             sprocket.component.remove
76             sprocket.plugin.add
77             sprocket.plugin.remove
78             sprocket.shutdown
79             )] );
80              
81 13         75 return $self;
82             }
83              
84             sub add_plugin {
85 14     15 0 44 my $self = shift;
86 14         74 my $uuid = $_[ 0 ]->uuid;
87            
88 14         113 $PLUGINS{ $uuid } = $_[ 0 ];
89 14         88 weaken( $PLUGINS{ $uuid } );
90            
91 14         132 $self->broadcast( 'sprocket.plugin.add', {
92             source => $self,
93             target => $_[ 0 ],
94             } );
95            
96 14         123 return;
97             }
98              
99             sub remove_plugin {
100 4     5 0 21 my ( $self, $uuid ) = @_;
101              
102 4         8 $self->broadcast( 'sprocket.plugin.remove', {
103             source => $self,
104             target => $uuid,
105             } );
106            
107             # supplied the object, get the uuid from it
108 4 0       30 $uuid = $uuid->uuid if ( ref( $uuid ) );
109              
110 0         0 delete $PLUGINS{ $uuid };
111            
112 0         0 return;
113             }
114              
115             sub add_component {
116 10     15 0 19 my $self = shift;
117 10         113 my $uuid = $_[ 0 ]->uuid;
118            
119 10         89 $COMPONENTS{ $uuid } = $_[ 0 ];
120 10         59 weaken( $COMPONENTS{ $uuid } );
121            
122 10         88 $self->broadcast( 'sprocket.component.add', {
123             source => $self,
124             target => $_[ 0 ],
125             } );
126            
127 10         44 return;
128             }
129              
130             sub remove_component {
131 12     17 0 49 my ( $self, $uuid ) = @_;
132              
133 12         62 $self->broadcast( 'sprocket.component.remove', {
134             source => $self,
135             target => $uuid,
136             } );
137            
138 12 50       75 $uuid = $uuid->uuid if ( ref( $uuid ) );
139            
140 12         57 my $count = 0;
141 12         28 delete $COMPONENTS{ $uuid };
142 12         34 foreach my $id ( keys %COMPONENTS ) {
143 5 50       17 next unless defined( $COMPONENTS{ $id } );
144 5         14 $count++;
145             }
146              
147 12 100       47 $self->finalize_shutdown() if ( $count == 0 );
148              
149 12         35 return $count;
150             }
151              
152             sub finalize_shutdown {
153 7     12 0 14 my $self = shift;
154            
155             # this will self elimiate double calls
156 7 100       28 return if ( $self->{__SHUTDOWN__}++ );
157            
158 5 50       20 $sprocket_aio->shutdown()
159             if ( $sprocket_aio );
160              
161 5         23 $self->broadcast( 'sprocket.shutdown', {
162             source => $self,
163             } );
164              
165 5         22 $self->clear_hooks();
166            
167 5         8 return;
168             }
169              
170             sub get_components {
171             # XXX does this make our refs strong again?
172 0     5 0 0 return [ values %COMPONENTS ];
173             }
174              
175             sub get_connection {
176 0     5 0 0 my $uuid = $_[ 1 ];
177              
178 0         0 foreach my $id ( keys %COMPONENTS ) {
179 0 0       0 next unless ( defined( $COMPONENTS{ $id } ) );
180 0 0       0 if ( my $con = $COMPONENTS{ $id }->get_connection( $uuid, 1 ) ) {
181 0         0 return $con;
182             }
183             }
184              
185 0         0 return undef;
186             }
187              
188             sub shutdown_all {
189 3     7 1 1602 my $self = shift;
190            
191 3         6 my $count = 0;
192 3         11 foreach my $id ( keys %COMPONENTS ) {
193 5 50       18 next unless ( defined( $COMPONENTS{ $id } ) );
194 5         22 $COMPONENTS{ $id }->shutdown( @_ );
195 5         69 $count++;
196             }
197            
198 3 50       15 $self->finalize_shutdown() if ( $count == 0 );
199            
200 3         11 return $count;
201             }
202              
203             sub get_plugin {
204 0     4 0 0 my $uuid = $_[ 1 ];
205            
206 0 0       0 return defined( $PLUGINS{ $uuid } ) ? $PLUGINS{ $uuid } : undef;
207             }
208              
209             sub callback {
210 5     9 1 778 my ( $self, $ses, $event, @etc ) = @_;
211            
212 5         18 my $id = $self->_resolve_session( $ses );
213              
214             return Sprocket::AnonCallback->new( sub {
215 12     12   739 $poe_kernel->call( $id => $event => @etc => @_ );
216 5         80 }, $id );
217             }
218              
219             sub postback {
220 2     2 1 15 my ( $self, $ses, $event, @etc ) = @_;
221            
222 2         6 my $id = $self->_resolve_session( $ses );
223              
224             return Sprocket::AnonCallback->new( sub {
225 2     2   10 $poe_kernel->post( $id => $event => @etc => @_ );
226 2         160 return;
227 2         15 }, $id );
228             }
229              
230             sub _resolve_session {
231 7     7   13 my ( $self, $ses ) = @_;
232              
233 7 100 66     165 if ( defined( $ses ) && $ses =~ m/^\d+$/ ) {
    100          
234 4         13 return $ses;
235             } elsif ( UNIVERSAL::can( $ses, 'ID' ) ) {
236 2         11 return $ses->ID();
237             } else {
238 1         7 my $s = $poe_kernel->alias_resolve( $ses );
239 1 50       45 return $s->ID() if ( $s );
240             }
241            
242 0         0 return $poe_kernel->get_active_session()->ID();
243             }
244              
245             sub run {
246 0     0 1 0 shift;
247 0         0 return $poe_kernel->run( @_ );
248             }
249              
250             1;
251              
252             package Sprocket::AnonCallback;
253              
254 13     13   139 use POE;
  13         25  
  13         160  
255              
256             our %callback_ids;
257              
258             sub new {
259 7     7   16 my ( $class, $cb, $id ) = @_;
260            
261 7   33     39 my $self = bless( $cb, ref $class || $class );
262              
263 7         58 $poe_kernel->refcount_increment(
264             $Sprocket::AnonCallback::callback_ids{$self} = $id,
265             __PACKAGE__
266             );
267              
268 7         242 return $self;
269             }
270              
271             sub DESTROY {
272 7     7   2179 my $self = shift;
273 7         35 my $id = delete $Sprocket::AnonCallback::callback_ids{"$self"};
274              
275 7 50       17 if ( defined( $id ) ) {
276 7         38 $poe_kernel->refcount_decrement( $id, __PACKAGE__ );
277             } else {
278 0         0 warn "connection callback DESTROY without session_id to refcount_decrement";
279             }
280              
281 7         250 return;
282             }
283              
284             1;
285              
286             __END__