File Coverage

blib/lib/Net/PSYC/Event.pm
Criterion Covered Total %
statement 88 158 55.7
branch 31 64 48.4
condition 14 42 33.3
subroutine 10 18 55.5
pod 2 12 16.6
total 145 294 49.3


line stmt bran cond sub pod time code
1             package Net::PSYC::Event;
2             #
3             # Net::PSYC::Event - Event wrapper for different event systems.
4             #
5             # nur weil diese sachen im jahre 2003 aus Net::PSYC.pm ausgelagert
6             # wurden, und bis dahin nur mit IO::Select gearbeitet haben,
7             # haben sie dennoch und nach wie vor den originalcopyright... ;)
8             #
9             # aha, na dann sag mir auch mal, welche der zeilen aus net::psyc stammen. es ist
10             # mir auch irgendwie wurscht. oder nein, vielleicht: welches der konzepte...
11             #
12             # TODO: maybe extra arguments in add are much nicer.. also to avoid
13             # cyclic data structures.. we will see..
14              
15 4     4   221 use strict;
  4         6  
  4         1095  
16              
17 4     4   28 use base qw(Exporter);
  4         5  
  4         6124  
18              
19             my (%unl2obj, %obj2unl, %unl2wrapper, %context2obj);
20             # context2obj is an approach to be able to route context. Clients use this too.
21             my (%PSYC_SOCKETS);
22              
23             our $VERSION = '0.4';
24              
25             our @EXPORT = qw();
26             our @EXPORT_OK = qw(register_uniform unregister_uniform watch forget init start_loop stop_loop add remove can_read can_write has_exception revoke);
27              
28             import Net::PSYC qw(W sendmsg same_host send_mmp parse_uniform parse_psyc MERGEVAR FORK);
29              
30             # dirty_wait hack!
31 0     0 0 0 sub PSYC_SOCKETS () { \%PSYC_SOCKETS }
32              
33             # vielleicht sollte man psyc-state auf dauer mit register_uniform verknüpfen.
34             # so wie ich es schonmal geplant hatte. Vor allem, was tut man mit den
35             # register_uniform() calls. bekommen die _einen_ state oder nochmal getrennt
36             # nach source und target mehrere. Sind user in der lage das selbst zu
37             # entscheiden/begreifen??
38             sub register_uniform {
39 2     2 1 19 my ($unl, $obj) = @_;
40              
41 2   50     16 $unl ||= 'default';
42            
43 2 50       10 if (ref $obj) {
44 0         0 $unl2obj{$unl} = $obj;
45 0         0 $obj2unl{$obj} = $unl;
46 0 0       0 unless ($obj->can('msg')) {
47 0         0 W0('%s does not have a msg()-method! Cannot deliver packet!',
48             ref $obj);
49 0         0 return $obj;
50             }
51 0 0 0     0 unless ($obj->can('diminish') && $obj->can('augment')
      0        
      0        
52             && $obj->can('assign') && $obj->can('reset')) {
53 0         0 my $o = $obj;
54 0         0 $obj = Net::PSYC::Event::Wrapper->new($o, $unl);
55             }
56             } else {
57 2   33     17 $obj ||= caller; # just a class.. that sux.
58 2         6 $unl2obj{$unl} = $obj;
59 2         6 $obj2unl{$obj} = $unl;
60 2 50 33     18 if (defined($unl) && exists $unl2wrapper{$unl} && $unl2wrapper{$unl}->{'obj'} eq $obj) {
      33        
61 0         0 return $unl2wrapper{$unl};
62             }
63 2 50       200 unless (eval "$obj->can('msg')") {
64 0         0 W0('%s does not have a msg() function! Cannot deliver packet!',
65             scalar($obj));
66 0         0 return $obj;
67             }
68 2         28 $obj = Net::PSYC::Event::Wrapper->new($obj, $unl);
69             }
70 2         5 $unl2wrapper{$unl} = $obj;
71 2         23 W1('register_uniform(%s, %s)', $unl, $obj->{'obj'});
72            
73 2         16 return $obj;
74             }
75              
76             sub find_context {
77 0     0 0 0 my ($context) = @_;
78 0         0 return $context2obj{$context};
79             }
80              
81             sub register_context {
82 0     0 0 0 my ($context, $obj) = @_;
83 0 0       0 unless (ref $obj) {
84 0         0 W0('register_context needs an object to register for.');
85 0         0 return 0;
86             }
87 0         0 $context2obj{$context} = $obj;
88             }
89              
90             sub find_object {
91 0     0 0 0 my $uni = shift;
92 0         0 my $o = $unl2obj{$uni};
93 0 0       0 unless ($o) {
94 0         0 my $h = parse_uniform($uni);
95 0 0       0 if (ref $h) {
96 0         0 $o = $unl2obj{$h->{'object'}};
97             }
98             }
99 0   0     0 $o ||= $unl2obj{'default'};
100 0         0 return $o;
101             }
102              
103             sub find_uniform {
104 0     0 0 0 return $obj2unl{$_[0]};
105             }
106              
107             sub unl2wrapper {
108 26     26 0 40 my $unl = shift;
109 26         43 my $o = $unl2wrapper{$unl};
110 26 50       60 unless ($o) {
111 26         65 my $h = parse_uniform($unl);
112 26 100       76 if (ref $h) {
113 16         310 $o = $unl2wrapper{$h->{'object'}};
114             }
115             }
116 26   33     99 $o ||= $unl2wrapper{'default'};
117 26         77 return $o;
118             }
119              
120             sub unregister_uniform {
121 0     0 1 0 my $unl = shift;
122 0         0 delete $obj2unl{$unl2obj{$unl}};
123 0         0 delete $unl2wrapper{$unl};
124 0         0 delete $unl2obj{$unl};
125 0         0 return 1;
126             }
127              
128             # watch(psyc-socket-object)
129             sub watch {
130 5     5 0 8 my $obj = shift;
131 5         15 W2('watch(%s)', scalar($obj));
132 5         73 $PSYC_SOCKETS{fileno($obj->{'SOCKET'})} = $obj;
133 5         30 add($obj->{'SOCKET'}, 'r', \&deliver );
134             #add($obj->{'SOCKET'}, 'w', sub { $obj->write() }, 0);
135             }
136              
137             # forget(psyc-socket-object)
138             sub forget {
139 0     0 0 0 my $obj = shift;
140 0         0 W2('forget(%s)', scalar($obj));
141 0         0 delete $PSYC_SOCKETS{fileno($obj->{'SOCKET'})};
142 0         0 remove($obj->{'SOCKET'});
143             }
144              
145             sub deliver {
146 30     30 0 49 my $socket = shift;
147 30         38 my $repeat = shift;
148 30 50       102 return 1 if (!exists $PSYC_SOCKETS{fileno($socket)});
149 30         52 my $obj = $PSYC_SOCKETS{fileno($socket)};
150            
151 30 50 66     104 unless ( $repeat || $obj->read() ) { # connection lost
152 0         0 Net::PSYC::shutdown($obj);
153 0         0 W0('Lost connection to %s:%s', $obj->{'R_IP'}, $obj->{'R_PORT'});
154 0         0 return 1;
155             }
156              
157 30         207 my ($MMPvars, $MMPdata) = $obj->recv(); # get a packet
158            
159 30 100       139 return 1 if (!defined($MMPvars)); # incomplete .. stop
160            
161 22 100       71 return -1 if ($MMPvars == 0); # fragment .. keep on going
162            
163 16 50       41 if ($MMPvars == -1) { # shutdown
164 0         0 Net::PSYC::shutdown($obj);
165 0         0 W0('Someone is making trouble: %s', $MMPdata);
166 0         0 W0('Closing connection to %s:%s.', $obj->{'R_IP'}, $obj->{'R_PORT'});
167 0         0 return 1;
168             }
169              
170 16 50       120 if ($MMPvars->{'_target'}) {
171 16         58 my $t = parse_uniform($MMPvars->{'_target'});
172              
173 16 50       117 unless (ref $t) {
174 0         0 Net::PSYC::shutdown($obj);
175 0         0 W0('Could not parse that _target: %s.', $MMPvars->{'_target'});
176 0         0 W0('Closing connection to %s:%s.', $obj->{'R_IP'},
177             $obj->{'R_PORT'});
178 0         0 return 1;
179             }
180 16 50       55 unless (same_host($t->{'host'}, '127.0.0.1')) {
181             # this is a remote uni
182 0 0       0 if ($obj->TRUST > 10) { # we relay
183 0         0 send_mmp($MMPvars->{'_target'}, $MMPdata, $MMPvars);
184 0         0 return -1;
185             } # we dont relay
186 0         0 sendmsg($MMPvars->{'_source'},
187             '_error_relay_denied',
188             "I won't deliver that!");
189 0         0 return -1;
190             }
191             }
192            
193 16         22 my $cb;
194 16 50       42 unless (exists $MMPvars->{'_target'}) {
195 0         0 $cb = unl2wrapper(0);
196             } else {
197 16         44 $cb = unl2wrapper($MMPvars->{'_target'});
198             }
199            
200 16 50       40 unless ($cb) {
201 0         0 W0('Found no recipient for %s. Dropping message.',
202             $MMPvars->{'_target'});
203 0         0 return -1;
204             }
205              
206 16         39 my $iscontext = exists $MMPvars->{'_context'};
207 16   33     66 my $t = $MMPvars->{'_context'} || $MMPvars->{'_source'};
208            
209 16         59 my ($mc, $data, $vars) = parse_psyc($MMPdata, $obj->{'LF'});
210             =state
211             my ($mc, $data, $vars) = parse_psyc($MMPdata, $obj->{'LF'}, $cb,
212             $iscontext, $t);
213             =cut
214              
215             # means.. no mc but proper vars. its a state change.
216 16 50       108 return -1 if ($mc eq '');
217              
218 16 50 33     43 if (!$mc && $mc == 0) {
219 0         0 W0('Broken PSYC packet from %s. Parser says: %s', $obj->{'peeraddr'},
220             $data);
221 0         0 W0('Closing connection to %s:%s.', $obj->{'R_IP'}, $obj->{'R_PORT'});
222 0         0 Net::PSYC::shutdown($obj);
223 0         0 return 1;
224             }
225              
226 16 100 100     96 if (
      100        
      33        
227             ($mc eq '_notice_circuit_established' && Net::PSYC::FORK) ||
228             ($mc eq '_status_circuit' && !Net::PSYC::FORK)
229             ) {
230 2         5 my @mods;
231 2 50       8 if (exists $MMPvars->{'_understand_modules'}) {
232 2 50       23 if (ref $MMPvars->{'_understand_modules'} eq 'ARRAY') {
    50          
233             # hm.. maybe it make sense to filter out the empty and
234             # undef ones..
235 0         0 @mods = map { $_ } @{$MMPvars->{'_understand_modules'}};
  0         0  
  0         0  
236             } elsif ($MMPvars->{'_understand_modules'}) {
237 2         7 @mods = ( $MMPvars->{'_understand_modules'} );
238             }
239             }
240 2         6 $obj->{'OK'} = 1;
241 2         117 revoke($obj->{'SOCKET'});
242 2         6 $obj->{'R'}->{'_understand_modules'} = { map { $_ => 1 } @mods };
  2         16  
243 2         7 map { $obj->gotiate($_) } @mods;
  2         12  
244             }
245              
246 16         63 foreach (keys %$MMPvars) {
247 61 100       143 $vars->{$_} = $MMPvars->{$_} if (MERGEVAR($_));
248             }
249            
250 16         36 $vars->{'_INTERNAL_origin'} = $obj;
251 16         56 $cb->msg($MMPvars->{'_source'}, $mc, $data, $vars);
252 16         1083 return -1;
253             }
254              
255             sub init {
256 4 100   4 0 17 if ($_[0] eq 'Event') {
    50          
    0          
257 1         668 require Net::PSYC::Event::Event;
258 0         0 import Net::PSYC::Event::Event qw(can_read can_write has_exception add remove start_loop stop_loop revoke);
259 0         0 return 1;
260             } elsif ($_[0] eq 'IO::Select') {
261 3         1557 require Net::PSYC::Event::IO_Select;
262 3         254 import Net::PSYC::Event::IO_Select qw(can_read can_write has_exception add remove start_loop stop_loop revoke);
263 3         10 return 1;
264             } elsif ($_[0] eq 'Gtk2') {
265 0         0 require Net::PSYC::Event::Gtk2;
266 0         0 import Net::PSYC::Event::Gtk2 qw(can_read can_write has_exception add remove start_loop stop_loop revoke);
267 0         0 return 1;
268             }
269             }
270              
271             package Net::PSYC::Event::Wrapper;
272             # a wrapper-object to make classes work like objects in register_uniform
273              
274 4     4   23 use strict;
  4         8  
  4         809  
275              
276             # this is beta since it does not allow anyone to handle several psyc-objects at
277             # once. remember: register_uniform() allows wildcards
278             =state
279             use base 'Net::PSYC::State';
280             =cut
281              
282             sub new {
283 2     2   6 my $class = shift;
284 2         5 my $o = shift;
285 2         7 my $unl = shift;
286              
287 2         6 my $self = {};
288 2 50       10 if (ref $o) {
289 0     0   0 $self->{'msg'} = sub{ $o->msg(@_) };
  0         0  
290             =state
291             $self->{'assign'} = sub{ $o->assign(@_) } if ($o->can('assign'));
292             $self->{'augment'} = sub{ $o->augment(@_) } if ($o->can('augment'));
293             $self->{'diminish'} = sub{ $o->diminish(@_) } if ($o->can('diminish'));
294             $self->{'reset'} = sub{ $o->reset(@_) } if ($o->can('reset'));
295             =cut
296             } else {
297 2         120 $self->{'msg'} = eval "\\&$o\::msg";
298             =state
299             foreach ('assign','augment','diminish','restet') {
300             $self->{$_} = eval "\\&$o\::$_" if (eval "$o->can('$_')");
301             }
302             =cut
303             }
304 2         9 $self->{'unl'} = $unl;
305 2         4 $self->{'obj'} = $o;
306 2         11 return bless $self, $class;
307             }
308              
309             sub msg {
310 16     16   24 my $self = shift;
311             =cut
312             $self->SUPER::msg(@_);
313             =cut
314 16         22 &{$self->{'msg'}};
  16         48  
315             }
316             =state
317              
318             sub assign {
319             my $self = shift;
320             return if ($self->{'assign'} && $self->{'assign'}->(@_));
321             $self->SUPER::assign(@_);
322             }
323              
324             sub augment {
325             my $self = shift;
326             return if ($self->{'augment'} && $self->{'augment'}->(@_));
327             $self->SUPER::augment(@_);
328             }
329              
330             sub diminish {
331             my $self = shift;
332             return if ($self->{'diminish'} && $self->{'diminish'}->(@_));
333             $self->SUPER::diminish(@_);
334             }
335              
336             sub reset {
337             my $self = shift;
338             return if ($self->{'reset'} && $self->{'reset'}->(@_));
339             $self->SUPER::reset(@_);
340             }
341             =cut
342              
343              
344             1;
345              
346             __END__