File Coverage

blib/lib/POE/TIKC.pm
Criterion Covered Total %
statement 8 176 4.5
branch 0 116 0.0
condition 0 21 0.0
subroutine 3 22 13.6
pod 0 7 0.0
total 11 342 3.2


line stmt bran cond sub pod time code
1             package POE::TIKC;
2             # (c) Copyright 2004, David Davis
3              
4 1     1   25141 use POE qw( Filter::Reference Component::Server::TCP Component::Client::TCP );
  1         60317  
  1         7  
5              
6 1     1   178864 use strict;
  1         2  
  1         3243  
7             #use warnings FATAL => "all";
8              
9             #$|++;
10              
11             our $VERSION = '0.02';
12              
13 0     0 0 0 sub DEBUG { 0 }
14              
15             # the client and server use this hash
16             our %clients;
17             #{
18             # tcp session id => {
19             # alias => mock session id,
20             # alias2 => another mock session id,
21             # }
22             #}
23              
24             our $connected = 0;
25              
26             POE::Session->create(
27             heap => {
28             alias =>'_tikc_manager',
29             },
30             package_states => [
31             'POE::TIKC' => [qw(
32             _start
33             shutdown
34             create_session
35             alias_list
36             )],
37             ],
38             );
39              
40             sub _start {
41 1     1   284 my ($kernel, $heap) = @_[KERNEL, HEAP];
42              
43 1         6 $kernel->alias_set($heap->{alias});
44             # $kernel->delay_set(alias_list => 5);
45             }
46              
47             sub shutdown {
48 0 0   0 0   return if ($_[HEAP]->{shutdown});
49 0           $_[HEAP]->{shutdown} = 1;
50 0           foreach my $c (keys %clients) {
51 0           $_[KERNEL]->call($c => 'shutdown');
52             }
53 0           $_[KERNEL]->call('_tikc_server' => 'shutdown');
54 0           $_[KERNEL]->call('_tikc_client' => 'shutdown');
55             }
56              
57             sub alias_list {
58 0     0 0   my ($kernel, $heap) = @_[KERNEL, HEAP];
59            
60 0           my @aliases;
61 0           my $kr_sessions = $POE::Kernel::poe_kernel->[POE::Kernel::KR_SESSIONS];
62 0           foreach my $key ( keys %$kr_sessions ) {
63 0 0         next if $key =~ /POE::Kernel/;
64 0           foreach my $a ($kernel->alias_list($kr_sessions->{$key}->[0])) {
65             #next if ($a =~ m/^_tikc/);
66 0           push(@aliases,$a);
67             }
68             }
69 0 0         DEBUG && print "(s) aliases: ".join(',',@aliases)."\n";
70 0           $kernel->delay_set(alias_list => 5);
71             }
72              
73             sub create_session {
74 0     0 0   my ($sid, $alias) = @_[ARG0,ARG1];
75 0 0         return if ($_[HEAP]->{shutdown});
76             return POE::Session->create(
77             heap => {
78             _tikc_proxy_session => 1,
79             client => $sid,
80             alias => $alias,
81             },
82             inline_states => {
83             _start => sub {
84 0 0   0     DEBUG && print "proxy session ".$_[SESSION]->ID." startup as ".$_[HEAP]->{alias}."\n";
85 0           $_[KERNEL]->alias_set($_[HEAP]->{alias});
86             },
87             _i_k_c_shutdown => sub {
88 0     0     $_[HEAP]->{shutdown} = 1;
89 0 0         DEBUG && print "proxy session ".$_[SESSION]->ID." shutdown called\n";
90 0           $_[KERNEL]->alias_remove($_[HEAP]->{alias});
91             },
92             _stop => sub {
93 0 0   0     DEBUG && print "proxy session ".$_[SESSION]->ID." stopped\n";
94             },
95             _default => sub {
96 0 0   0     return undef if ($_[ARG0] =~ /^_signal/);
97 0 0         return if ($_[HEAP]->{shutdown});
98 0 0         DEBUG && print "(sp) calling $_[ARG0] in remote alias: $_[HEAP]->{alias} through proxy\n";
99 0           $_[KERNEL]->call($_[HEAP]->{client} => _tikc_send => {
100             action => 'post',
101             event => $_[ARG0],
102             alias => $_[HEAP]->{alias},
103             args => splice(@_,ARG1),
104             });
105             },
106             },
107 0           )->ID;
108             }
109              
110             sub create_server {
111 0     0 0   my $class = shift;
112 0   0       my $opt = shift || {};
113            
114             POE::Component::Server::TCP->new(
115             Alias => "_tikc_server",
116             Address => $opt->{address} || "127.0.0.1",
117             Port => $opt->{port} || 2021,
118             ClientFilter => "POE::Filter::Reference",
119             ClientDisconnected => sub {
120 0     0     my ($kernel,$sid) = ($_[KERNEL],$_[SESSION]->ID);
121 0 0         if (ref($clients{$sid}) eq 'HASH') {
122 0           my @aliases;
123 0           foreach my $a (keys %{$clients{$sid}}) {
  0            
124             # $a is an alias
125             # value is a session id
126 0           $kernel->call($clients{$sid}->{$a} => '_i_k_c_shutdown');
127 0           push(@aliases, $a);
128             }
129 0 0         if (@aliases) {
130 0           foreach my $c (keys %clients) {
131             # skip the exiting client
132 0 0         next if ($c == $sid);
133 0           $kernel->call($c => _tikc_send => { type => 'server', action => 'remove', aliases => \@aliases });
134             }
135             }
136             }
137 0           delete $clients{$sid};
138 0           $connected = 0;
139 0 0         DEBUG && print "Client Disconnected!\n";
140             },
141             ClientShutdownOnError => 1,
142             ClientError => sub {
143 0     0     my ($kernel,$sid) = ($_[KERNEL],$_[SESSION]->ID);
144             # shouldn't client error ALWAYS call client disconnected?
145 0 0         if (ref($clients{$sid}) eq 'HASH') {
146 0           my @aliases;
147 0           foreach my $a (keys %{$clients{$sid}}) {
  0            
148             # $a is an alias
149             # value is a session id
150 0           $kernel->call($clients{$sid}->{$a} => '_i_k_c_shutdown');
151 0           push(@aliases, $a);
152             }
153 0 0         if (@aliases) {
154 0           foreach my $c (keys %clients) {
155             # skip the exiting client
156 0 0         next if ($c == $sid);
157 0           $kernel->call($c => _tikc_send => { type => 'server', action => 'remove', aliases => \@aliases });
158             }
159             }
160             }
161 0           delete $clients{$sid};
162 0           $connected = 0;
163 0 0         DEBUG && print "Client Error, disconnected: $_[ARG2]\n";
164             },
165             ClientConnected => sub {
166 0     0     my ($kernel,$heap) = @_[KERNEL, HEAP];
167            
168 0 0         DEBUG && print "Client Connected!\n";
169             # TODO put a timer here to disconnect clients that
170             # don't auth before 15 seconds
171            
172             # tell the client what aliases the server already knows
173 0           my %aliases;
174 0           my $kr_sessions = $POE::Kernel::poe_kernel->[POE::Kernel::KR_SESSIONS];
175 0           foreach my $key ( keys %$kr_sessions ) {
176 0 0         next if $key =~ /POE::Kernel/;
177 0           foreach my $a ($kernel->alias_list($kr_sessions->{$key}->[0])) {
178             # skip over internal sessions
179 0 0         next if ($a =~ m/^_tikc/);
180 0           my $h = $kr_sessions->{$key}->[0]->get_heap();
181 0 0 0       next if (ref($h) eq 'HASH' && $h->{_tikc_proxy_session});
182 0           $aliases{$a}++;
183             }
184             }
185             # tell this client about sessions that we know about from other clients
186 0           foreach my $a (keys %clients) {
187 0           foreach my $k (keys %{$clients{$a}}) {
  0            
188 0           $aliases{$k}++;
189             }
190             }
191 0 0         DEBUG && print "(s) sending aliases: ".join(',',keys %aliases)."\n";
192 0           $kernel->call($_[SESSION] => _tikc_send => { type => 'client', action => 'setup', aliases => [keys %aliases] });
193             },
194             ClientInput => \&input,
195             InlineStates => {
196             _tikc_send => sub {
197 0     0     my ($kernel, $heap, $data) = @_[KERNEL, HEAP, ARG0];
198              
199 0 0         if ($heap->{client}) {
200 0 0         DEBUG && print "(s) sending data to ".$_[SESSION]->ID."\n";
201 0           $heap->{client}->put($data);
202             } else {
203 0 0         DEBUG && print "(s) data sent to client ".$_[SESSION]->ID." ignored\n";
204             }
205             },
206             },
207 0   0       );
      0        
208             }
209              
210             sub create_client {
211 0     0 0   my $class = shift;
212 0   0       my $opt = shift || {};
213            
214             POE::Component::Client::TCP->new(
215             Alias => "_tikc_client",
216             RemoteAddress => $opt->{address} || "127.0.0.1",
217             RemotePort => $opt->{port} || 2021,
218             Filter => "POE::Filter::Reference",
219             ConnectError => sub {
220 0     0     my ($kernel,$sid) = ($_[KERNEL],$_[SESSION]->ID);
221            
222 0           $kernel->delay_set(reconnect => 2);
223            
224 0 0         if (ref($clients{$sid}) eq 'HASH') {
225 0           foreach my $a (keys %{$clients{$sid}}) {
  0            
226             # $a is an alias
227             # value is a session id
228 0           $kernel->call($clients{$sid}->{$a} => '_i_k_c_shutdown');
229             }
230             }
231            
232 0           delete $clients{$sid};
233 0           $connected = 0;
234 0 0         DEBUG && print "Connect error, $_[ARG2]\n";
235             },
236             Disconnected => sub {
237 0     0     my ($kernel,$sid) = ($_[KERNEL],$_[SESSION]->ID);
238            
239 0           $kernel->delay_set(reconnect => 2);
240            
241 0 0         if (ref($clients{$sid}) eq 'HASH') {
242 0           foreach my $a (keys %{$clients{$sid}}) {
  0            
243             # $a is an alias
244             # value is a session id
245 0           $kernel->call($clients{$sid}->{$a} => '_i_k_c_shutdown');
246             }
247             }
248            
249 0           delete $clients{$sid};
250 0           $connected = 0;
251 0 0         DEBUG && print "Disconnected! Reconnecting...\n";
252             },
253             Connected => sub {
254 0     0     my ($kernel,$heap) = @_[KERNEL, HEAP];
255            
256 0 0         DEBUG && print "Connected!\n";
257             # tell the server what aliases we have
258 0           my @aliases;
259 0           my $kr_sessions = $POE::Kernel::poe_kernel->[POE::Kernel::KR_SESSIONS];
260 0           foreach my $key ( keys %$kr_sessions ) {
261 0 0         next if $key =~ /POE::Kernel/;
262 0           foreach my $a ($kernel->alias_list($kr_sessions->{$key}->[0])) {
263             # skip over internal sessions
264 0 0         next if ($a =~ m/^_tikc/);
265 0           my $h = $kr_sessions->{$key}->[0]->get_heap();
266 0 0 0       next if (ref($h) eq 'HASH' && $h->{_tikc_proxy_session});
267 0           push(@aliases,$a);
268             }
269             }
270 0           push(@aliases, map { keys %{$clients{$_}} } %clients);
  0            
  0            
271 0 0         DEBUG && print "(c) sending aliases: ".join(',',@aliases)."\n";
272 0           $kernel->call($_[SESSION] => _tikc_send => { type => 'server', action => 'setup', aliases => \@aliases });
273             },
274             ServerInput => \&input,
275             InlineStates => {
276             _tikc_send => sub {
277 0     0     my ($kernel, $heap, $data) = @_[KERNEL, HEAP, ARG0];
278              
279 0 0         if ($heap->{server}) {
280 0 0         DEBUG && print "(c) sending data to ".$_[SESSION]->ID."\n";
281 0           $heap->{server}->put($data);
282             } else {
283 0 0         DEBUG && print "(c) data sent to server ".$_[SESSION]->ID." ignored\n";
284             }
285             },
286             },
287 0   0       );
      0        
288             }
289              
290             sub input {
291 0     0 0   my ( $heap, $kernel, $data ) = @_[ HEAP, KERNEL, ARG0 ];
292              
293 0 0         if (ref($data) eq 'HASH') {
294 0 0         if (exists($data->{action})) {
295 0 0         if ($data->{action} eq 'post') {
    0          
    0          
296             # if this session isn't a 'real' session
297             # _default of our mock session forwards it to the server
298 0 0         DEBUG && print "(i) searching for == $data->{alias} ==\n";
299 0           my $sr = $kernel->alias_resolve($data->{alias});
300 0 0         if (ref($sr)) {
301 0           my $h = $sr->get_heap();
302 0 0         DEBUG && print "(i) posting to $data->{alias}\n";
303 0 0         if (@{$data->{args}}) {
  0            
304 0           $kernel->call($sr => $data->{event} => @{$data->{args}});
  0            
305             } else {
306 0           $kernel->call($sr => $data->{event});
307             }
308             } else {
309             # XXX notify client?
310 0 0         DEBUG && print "(i) client posted to invalid alias $data->{alias}, ignoring\n";
311             }
312             } elsif ($data->{action} eq 'setup') {
313 0           foreach my $i (@{$data->{aliases}}) {
  0            
314 0           my $sr = $kernel->alias_resolve($i);
315 0 0         if (ref($sr)) {
316 0           warn "Session (alias $i) already exists as session_id: ".$sr->ID."\n";
317 0           my $h = $sr->get_heap();
318 0 0 0       if (ref($h) eq 'HASH' && $h->{_tikc_proxy_session}) {
319 0           warn "!!!! it is a tikc proxy session, I'll use that session\n";
320 0           $clients{$_[SESSION]->ID}->{$i} = $sr->ID;
321             }
322             } else {
323 0 0         DEBUG && print "(i) creating proxy session for remote alias $i\n";
324 0           my $sid = $_[SESSION]->ID;
325             # create a client key with the session id
326              
327 0           $clients{$sid}->{$i} = $kernel->call(_tikc_manager => 'create_session' => $sid => $i);
328              
329 0 0         DEBUG && do {
330 0           require Data::Dumper;
331 0           print Data::Dumper->Dump([\%clients]);
332             };
333             }
334             }
335 0           foreach my $c (keys %clients) {
336 0 0         next if ($c == $_[SESSION]->ID);
337 0           $kernel->call($c => _tikc_send => {
338             action => 'setup',
339             aliases => $data->{aliases},
340             });
341             }
342             # we're considered connected after the first setup command
343 0           $connected = 1;
344             } elsif ($data->{action} eq 'remove') {
345 0           my $sid = $_[SESSION]->ID;
346 0 0         DEBUG && print "(i) I was told me to remove aliases: ".join(',',@{$data->{aliases}})."\n";
  0            
347 0           foreach my $a (@{$data->{aliases}}) {
  0            
348 0 0         if (exists($clients{$sid}->{$a})) {
349 0 0         DEBUG && print "(i) shutting down session $clients{$sid}->{$a}\n";
350 0           $kernel->call($clients{$sid}->{$a} => '_i_k_c_shutdown');
351             }
352             }
353             }
354             } else {
355 0 0         DEBUG && print "Received response from TIKC without action\n";
356             }
357             } else {
358 0 0         DEBUG && print "Received an unknown response from TIKC type: ", ref($data)."\n";
359             }
360             }
361              
362             1;
363              
364             __END__