… | |
… | |
69 | |
69 | |
70 | use AnyEvent; |
70 | use AnyEvent; |
71 | use AnyEvent::Handle; |
71 | use AnyEvent::Handle; |
72 | use AnyEvent::Util (); |
72 | use AnyEvent::Util (); |
73 | |
73 | |
|
|
74 | our %TOLC; # tolc cache |
|
|
75 | |
74 | sub touc($) { |
76 | sub touc($) { |
75 | local $_ = shift; |
77 | local $_ = shift; |
76 | 1 while s/((?:^|_)(?:svk|chk|uri|fcp|ds|mime|dda)(?:_|$))/\U$1/; |
78 | 1 while s/((?:^|_)(?:svk|chk|uri|fcp|ds|mime|dda)(?:_|$))/\U$1/; |
77 | s/(?:^|_)(.)/\U$1/g; |
79 | s/(?:^|_)(.)/\U$1/g; |
78 | $_ |
80 | $_ |
… | |
… | |
96 | |
98 | |
97 | =cut |
99 | =cut |
98 | |
100 | |
99 | sub new { |
101 | sub new { |
100 | my $class = shift; |
102 | my $class = shift; |
|
|
103 | |
|
|
104 | my $rand = join "", map chr 0x21 + rand 94, 1..40; # ~ 262 bits entropy |
|
|
105 | |
101 | my $self = bless { |
106 | my $self = bless { |
102 | host => $ENV{FREDHOST} || "127.0.0.1", |
107 | host => $ENV{FREDHOST} || "127.0.0.1", |
103 | port => $ENV{FREDPORT} || 9481, |
108 | port => $ENV{FREDPORT} || 9481, |
104 | timeout => 3600 * 2, |
109 | timeout => 3600 * 2, |
105 | name => time.rand.rand.rand, # lame |
110 | name => time.rand.rand.rand, # lame |
106 | @_, |
111 | @_, |
107 | queue => [], |
112 | queue => [], |
108 | req => {}, |
113 | req => {}, |
|
|
114 | prefix => "..:aefcpid:$rand:", |
109 | id => "a0", |
115 | idseq => "a0", |
110 | }, $class; |
116 | }, $class; |
111 | |
117 | |
112 | { |
118 | { |
113 | Scalar::Util::weaken (my $self = $self); |
119 | Scalar::Util::weaken (my $self = $self); |
114 | |
120 | |
… | |
… | |
131 | ); |
137 | ); |
132 | |
138 | |
133 | $self |
139 | $self |
134 | } |
140 | } |
135 | |
141 | |
|
|
142 | sub identifier { |
|
|
143 | $_[0]{prefix} . ++$_[0]{idseq} |
|
|
144 | } |
|
|
145 | |
136 | sub send_msg { |
146 | sub send_msg { |
137 | my ($self, $type, %kv) = @_; |
147 | my ($self, $type, %kv) = @_; |
138 | |
148 | |
139 | my $data = delete $kv{data}; |
149 | my $data = delete $kv{data}; |
140 | |
150 | |
141 | if (exists $kv{id_cb}) { |
151 | if (exists $kv{id_cb}) { |
142 | my $id = $kv{identifier} ||= ++$self->{id}; |
152 | my $id = $kv{identifier} ||= $self->identifier; |
143 | $self->{id}{$id} = delete $kv{id_cb}; |
153 | $self->{id}{$id} = delete $kv{id_cb}; |
144 | } |
154 | } |
145 | |
155 | |
146 | my $msg = (touc $type) . "\012" |
156 | my $msg = (touc $type) . "\012" |
147 | . join "", map +(touc $_) . "=$kv{$_}\012", keys %kv; |
157 | . join "", map +(touc $_) . "=$kv{$_}\012", keys %kv; |
… | |
… | |
224 | |
234 | |
225 | if (my $cb = $PERSISTENT_TYPE{$type}) { |
235 | if (my $cb = $PERSISTENT_TYPE{$type}) { |
226 | my $id = $kv->{identifier}; |
236 | my $id = $kv->{identifier}; |
227 | my $req = $_[0]{req}{$id} ||= {}; |
237 | my $req = $_[0]{req}{$id} ||= {}; |
228 | $cb->($self, $req, $kv); |
238 | $cb->($self, $req, $kv); |
229 | $self->recv (request_change => $kv, $type, @extra); |
239 | $self->recv (request_changed => $kv, $type, @extra); |
230 | } |
240 | } |
231 | |
241 | |
232 | my $on = $self->{on}; |
242 | my $on = $self->{on}; |
233 | for (0 .. $#$on) { |
243 | for (0 .. $#$on) { |
234 | unless (my $res = $on->[$_]($self, $type, $kv, @extra)) { |
244 | unless (my $res = $on->[$_]($self, $type, $kv, @extra)) { |
… | |
… | |
246 | } |
256 | } |
247 | |
257 | |
248 | sub on_read { |
258 | sub on_read { |
249 | my ($self) = @_; |
259 | my ($self) = @_; |
250 | |
260 | |
251 | my $type; |
261 | my ($k, $v, $type); |
252 | my %kv; |
262 | my %kv; |
253 | my $rdata; |
263 | my $rdata; |
254 | |
264 | |
255 | my $hdr_cb; $hdr_cb = sub { |
265 | my $hdr_cb; $hdr_cb = sub { |
256 | if ($_[1] =~ /^([^=]+)=(.*)$/) { |
266 | if (($v = index $_[1], "=") >= 0) { |
257 | my ($k, $v) = ($1, $2); |
267 | $k = substr $_[1], 0, $v; |
|
|
268 | $v = substr $_[1], $v + 1; |
|
|
269 | $k = ($TOLC{$k} ||= tolc $k); |
|
|
270 | |
|
|
271 | if ($k !~ /\./) { |
|
|
272 | # special case common case, for performance only |
|
|
273 | $kv{$k} = $v; |
|
|
274 | } else { |
258 | my @k = split /\./, tolc $k; |
275 | my @k = split /\./, $k; |
259 | my $ro = \\%kv; |
276 | my $ro = \\%kv; |
260 | |
277 | |
261 | while (@k) { |
278 | while (@k) { |
262 | my $k = shift @k; |
279 | $k = shift @k; |
263 | if ($k =~ /^\d+$/) { |
280 | if ($k =~ /^\d+$/) { |
264 | $ro = \$$ro->[$k]; |
281 | $ro = \$$ro->[$k]; |
265 | } else { |
282 | } else { |
266 | $ro = \$$ro->{$k}; |
283 | $ro = \$$ro->{$k}; |
|
|
284 | } |
267 | } |
285 | } |
|
|
286 | |
|
|
287 | $$ro = $v; |
268 | } |
288 | } |
269 | |
|
|
270 | $$ro = $v; |
|
|
271 | |
289 | |
272 | $_[0]->push_read (line => $hdr_cb); |
290 | $_[0]->push_read (line => $hdr_cb); |
273 | } elsif ($_[1] eq "Data") { |
291 | } elsif ($_[1] eq "Data") { |
274 | $_[0]->push_read (chunk => delete $kv{data_length}, sub { |
292 | $_[0]->push_read (chunk => delete $kv{data_length}, sub { |
275 | $rdata = \$_[1]; |
293 | $rdata = \$_[1]; |
… | |
… | |
281 | die "protocol error, expected message end, got $_[1]\n";#d# |
299 | die "protocol error, expected message end, got $_[1]\n";#d# |
282 | } |
300 | } |
283 | }; |
301 | }; |
284 | |
302 | |
285 | $self->{hdl}->push_read (line => sub { |
303 | $self->{hdl}->push_read (line => sub { |
286 | $type = tolc $_[1]; |
304 | $type = ($TOLC{$_[1]} ||= tolc $_[1]); |
287 | $_[0]->push_read (line => $hdr_cb); |
305 | $_[0]->push_read (line => $hdr_cb); |
288 | }); |
306 | }); |
289 | } |
307 | } |
290 | |
308 | |
291 | sub default_recv { |
309 | sub default_recv { |
… | |
… | |
371 | my ($name, $sub) = @_; |
389 | my ($name, $sub) = @_; |
372 | |
390 | |
373 | *{$name} = sub { |
391 | *{$name} = sub { |
374 | my $cv = AE::cv; |
392 | my $cv = AE::cv; |
375 | |
393 | |
376 | splice @_, 1, 0, $cv, sub { $cv->throw ($_[0]{extra_description}) }; |
394 | splice @_, 1, 0, $cv, sub { $cv->croak ($_[0]{extra_description}) }; |
377 | &$sub; |
395 | &$sub; |
378 | $cv->recv |
396 | $cv->recv |
379 | }; |
397 | }; |
380 | |
398 | |
381 | *{"$name\_"} = sub { |
399 | *{"$name\_"} = sub { |
382 | my ($ok, $err) = pop; |
400 | my ($ok, $err) = pop; |
383 | |
401 | |
384 | if (ARRAY:: eq ref $ok) { |
402 | if (ARRAY:: eq ref $ok) { |
385 | ($ok, $err) = @$ok; |
403 | ($ok, $err) = @$ok; |
386 | } elsif (UNIVERSAL::isa $ok, AnyEvent::CondVar::) { |
404 | } elsif (UNIVERSAL::isa $ok, AnyEvent::CondVar::) { |
387 | $err = sub { $ok->throw ($_[0]{extra_description}) }; |
405 | $err = sub { $ok->croak ($_[0]{extra_description}) }; |
388 | } else { |
406 | } else { |
389 | my $bt = Carp::longmess ""; |
407 | my $bt = Carp::longmess ""; |
390 | $err = sub { |
408 | $err = sub { |
391 | die "$_[0]{extra_description}$bt"; |
409 | die "$_[0]{code_description} ($_[0]{extra_description})$bt"; |
392 | }; |
410 | }; |
393 | } |
411 | } |
394 | |
412 | |
395 | $ok ||= $NOP_CB; |
413 | $ok ||= $NOP_CB; |
396 | |
414 | |
… | |
… | |
517 | ); |
535 | ); |
518 | |
536 | |
519 | $self->on (sub { |
537 | $self->on (sub { |
520 | my ($self, $type, $kv, @extra) = @_; |
538 | my ($self, $type, $kv, @extra) = @_; |
521 | |
539 | |
|
|
540 | $guard if 0; |
|
|
541 | |
522 | if ($kv->{identifier} eq $identifier) { |
542 | if ($kv->{identifier} eq $identifier) { |
523 | if ($type eq "persistent_request_modified") { |
543 | if ($type eq "persistent_request_modified") { |
524 | $ok->($kv); |
544 | $ok->($kv); |
525 | return; |
545 | return; |
526 | } elsif ($type eq "protocol_error") { |
546 | } elsif ($type eq "protocol_error") { |
… | |
… | |
539 | =cut |
559 | =cut |
540 | |
560 | |
541 | _txn get_plugin_info => sub { |
561 | _txn get_plugin_info => sub { |
542 | my ($self, $ok, $err, $name, $detailed) = @_; |
562 | my ($self, $ok, $err, $name, $detailed) = @_; |
543 | |
563 | |
|
|
564 | my $id = $self->identifier; |
|
|
565 | |
544 | $self->send_msg (get_plugin_info => |
566 | $self->send_msg (get_plugin_info => |
|
|
567 | identifier => $id, |
545 | plugin_name => $name, |
568 | plugin_name => $name, |
546 | detailed => $detailed ? "true" : "false", |
569 | detailed => $detailed ? "true" : "false", |
547 | id_cb => sub { |
|
|
548 | my ($self, $type, $kv, $rdata) = @_; |
|
|
549 | |
|
|
550 | $ok->($kv); |
|
|
551 | 1 |
|
|
552 | }, |
|
|
553 | ); |
570 | ); |
|
|
571 | $self->on (sub { |
|
|
572 | my ($self, $type, $kv) = @_; |
|
|
573 | |
|
|
574 | if ($kv->{identifier} eq $id) { |
|
|
575 | if ($type eq "get_plugin_info") { |
|
|
576 | $ok->($kv); |
|
|
577 | } else { |
|
|
578 | $err->($kv, $type); |
|
|
579 | } |
|
|
580 | return; |
|
|
581 | } |
|
|
582 | |
|
|
583 | 1 |
|
|
584 | }); |
554 | }; |
585 | }; |
555 | |
586 | |
556 | =item $status = $fcp->client_get ($uri, $identifier, %kv) |
587 | =item $status = $fcp->client_get ($uri, $identifier, %kv) |
557 | |
588 | |
558 | %kv can contain (L<http://wiki.freenetproject.org/FCP2p0ClientGet>). |
589 | %kv can contain (L<http://wiki.freenetproject.org/FCP2p0ClientGet>). |
… | |
… | |
564 | =cut |
595 | =cut |
565 | |
596 | |
566 | _txn client_get => sub { |
597 | _txn client_get => sub { |
567 | my ($self, $ok, $err, $uri, $identifier, %kv) = @_; |
598 | my ($self, $ok, $err, $uri, $identifier, %kv) = @_; |
568 | |
599 | |
|
|
600 | $self->serialise ($identifier => sub { |
|
|
601 | my ($self, $guard) = @_; |
|
|
602 | |
569 | $self->send_msg (client_get => |
603 | $self->send_msg (client_get => |
570 | %kv, |
604 | %kv, |
571 | uri => $uri, |
605 | uri => $uri, |
572 | identifier => $identifier, |
606 | identifier => $identifier, |
|
|
607 | ); |
|
|
608 | |
|
|
609 | $self->on (sub { |
|
|
610 | my ($self, $type, $kv, @extra) = @_; |
|
|
611 | |
|
|
612 | $guard if 0; |
|
|
613 | |
|
|
614 | if ($kv->{identifier} eq $identifier) { |
|
|
615 | if ($type eq "persistent_get") { |
|
|
616 | $ok->($kv); |
|
|
617 | return; |
|
|
618 | } elsif ($type eq "protocol_error") { |
|
|
619 | $err->($kv); |
|
|
620 | return; |
|
|
621 | } |
|
|
622 | } |
|
|
623 | |
|
|
624 | 1 |
|
|
625 | }); |
573 | ); |
626 | }); |
574 | |
|
|
575 | $ok->(); |
|
|
576 | }; |
627 | }; |
577 | |
628 | |
578 | =item $status = $fcp->remove_request ($identifier[, $global]) |
629 | =item $status = $fcp->remove_request ($identifier[, $global]) |
579 | |
630 | |
580 | Remove the request with the given isdentifier. Returns true if successful, |
631 | Remove the request with the given isdentifier. Returns true if successful, |
… | |
… | |
592 | identifier => $identifier, |
643 | identifier => $identifier, |
593 | global => $global ? "true" : "false", |
644 | global => $global ? "true" : "false", |
594 | ); |
645 | ); |
595 | $self->on (sub { |
646 | $self->on (sub { |
596 | my ($self, $type, $kv, @extra) = @_; |
647 | my ($self, $type, $kv, @extra) = @_; |
|
|
648 | |
|
|
649 | $guard if 0; |
597 | |
650 | |
598 | if ($kv->{identifier} eq $identifier) { |
651 | if ($kv->{identifier} eq $identifier) { |
599 | if ($type eq "persistent_request_removed") { |
652 | if ($type eq "persistent_request_removed") { |
600 | $ok->(1); |
653 | $ok->(1); |
601 | return; |
654 | return; |