ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-FCP/FCP.pm
(Generate patch)

Comparing AnyEvent-FCP/FCP.pm (file contents):
Revision 1.2 by root, Sat Jul 25 06:28:49 2009 UTC vs.
Revision 1.5 by root, Tue Dec 1 13:49:56 2009 UTC

2 2
3AnyEvent::FCP - freenet client protocol 2.0 3AnyEvent::FCP - freenet client protocol 2.0
4 4
5=head1 SYNOPSIS 5=head1 SYNOPSIS
6 6
7 use AnyEvent::FCP; 7 use AnyEvent::FCP;
8 8
9 my $fcp = new AnyEvent::FCP; 9 my $fcp = new AnyEvent::FCP;
10 10
11 my $ni = $fcp->txn_node_info->result; 11# transactions return condvars
12 my $ni = $fcp->node_info; 12 my $lp_cv = $fcp->list_peers;
13 my $pr_cv = $fcp->list_persistent_requests;
14
15 my $peers = $lp_cv->recv;
16 my $reqs = $pr_cv->recv;
13 17
14=head1 DESCRIPTION 18=head1 DESCRIPTION
15 19
16This module implements the freenet client protocol version 2.0, as used by 20This module implements the freenet client protocol version 2.0, as used by
17freenet 0.7. See L<Net::FCP> for the earlier freenet 0.5 version. 21freenet 0.7. See L<Net::FCP> for the earlier freenet 0.5 version.
18 22
19See L<http://wiki.freenetproject.org/FreenetFCPSpec2Point0> for a description 23See L<http://wiki.freenetproject.org/FreenetFCPSpec2Point0> for a
20of what the messages do. 24description of what the messages do.
21 25
22The module uses L<AnyEvent> to find a suitable event module. 26The module uses L<AnyEvent> to find a suitable event module.
23 27
28Only very little is implemented, ask if you need more, and look at the
29example program later in this section.
30
24=head2 IMPORT TAGS 31=head2 IMPORT TAGS
25 32
26Nothing much can be "imported" from this module right now. 33Nothing much can be "imported" from this module right now.
27 34
28=head2 FREENET BASICS 35=head2 THE AnyEvent::FCP CLASS
29
30Ok, this section will not explain any freenet basics to you, just some
31problems I found that you might want to avoid:
32 36
33=over 4 37=over 4
34 38
35=item freenet URIs are _NOT_ URIs
36
37Whenever a "uri" is required by the protocol, freenet expects a kind of
38URI prefixed with the "freenet:" scheme, e.g. "freenet:CHK...". However,
39these are not URIs, as freeent fails to parse them correctly, that is, you
40must unescape an escaped characters ("%2c" => ",") yourself. Maybe in the
41future this library will do it for you, so watch out for this incompatible
42change.
43
44=back
45
46=head2 THE AnyEvent::FCP CLASS
47
48=over 4
49
50=cut 39=cut
51 40
52package AnyEvent::FCP; 41package AnyEvent::FCP;
53 42
54use common::sense; 43use common::sense;
55 44
56use Carp; 45use Carp;
57 46
58our $VERSION = '0.1'; 47our $VERSION = '0.21';
59 48
60use Scalar::Util (); 49use Scalar::Util ();
61 50
62use AnyEvent; 51use AnyEvent;
63use AnyEvent::Handle; 52use AnyEvent::Handle;
64 53
65sub touc($) { 54sub touc($) {
66 local $_ = shift; 55 local $_ = shift;
67 1 while s/((?:^|_)(?:svk|chk|uri|fcp)(?:_|$))/\U$1/; 56 1 while s/((?:^|_)(?:svk|chk|uri|fcp|ds|mime)(?:_|$))/\U$1/;
68 s/(?:^|_)(.)/\U$1/g; 57 s/(?:^|_)(.)/\U$1/g;
69 $_ 58 $_
70} 59}
71 60
72sub tolc($) { 61sub tolc($) {
73 local $_ = shift; 62 local $_ = shift;
74 1 while s/(SVK|CHK|URI|FCP)([^_])/$1\_$2/i; 63 1 while s/(SVK|CHK|URI|FCP|DS|MIME)([^_])/$1\_$2/i;
75 1 while s/([^_])(SVK|CHK|URI|FCP)/$1\_$2/i; 64 1 while s/([^_])(SVK|CHK|URI|FCP|DS|MIME)/$1\_$2/i;
76 s/(?<=[a-z])(?=[A-Z])/_/g; 65 s/(?<=[a-z])(?=[A-Z])/_/g;
77 lc 66 lc
78} 67}
79 68
80=item $fcp = new AnyEvent::FCP [host => $host][, port => $port][, progress => \&cb][, name => $name] 69=item $fcp = new AnyEvent::FCP [host => $host][, port => $port][, progress => \&cb][, name => $name]
81 70
82Create a new FCP connection to the given host and port (default 71Create a new FCP connection to the given host and port (default
83127.0.0.1:9481, or the environment variables C<FREDHOST> and C<FREDPORT>). 72127.0.0.1:9481, or the environment variables C<FREDHOST> and C<FREDPORT>).
84 73
85If no C<name> was specified, then AnyEvent::FCP will generate a (hopefully) 74If no C<name> was specified, then AnyEvent::FCP will generate a
86unique client name for you. 75(hopefully) unique client name for you.
76
77=cut
87 78
88#TODO 79#TODO
89#You can install a progress callback that is being called with the AnyEvent::FCP 80#You can install a progress callback that is being called with the AnyEvent::FCP
90#object, a txn object, the type of the transaction and the attributes. Use 81#object, a txn object, the type of the transaction and the attributes. Use
91#it like this: 82#it like this:
94# my ($self, $txn, $type, $attr) = @_; 85# my ($self, $txn, $type, $attr) = @_;
95# 86#
96# warn "progress<$txn,$type," . (join ":", %$attr) . ">\n"; 87# warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
97# } 88# }
98 89
99=cut
100
101sub new { 90sub new {
102 my $class = shift; 91 my $class = shift;
103 my $self = bless { @_ }, $class; 92 my $self = bless { @_ }, $class;
104 93
105 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1"; 94 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1";
132 ); 121 );
133 122
134 $self 123 $self
135} 124}
136 125
137sub progress { 126#sub progress {
138 my ($self, $txn, $type, $attr) = @_; 127# my ($self, $txn, $type, $attr) = @_;
139 128#
140 $self->{progress}->($self, $txn, $type, $attr) 129# $self->{progress}->($self, $txn, $type, $attr)
141 if $self->{progress}; 130# if $self->{progress};
142} 131#}
143 132
144sub send_msg { 133sub send_msg {
145 my ($self, $type, %kv) = @_; 134 my ($self, $type, %kv) = @_;
146 135
147 my $data = delete $kv{data}; 136 my $data = delete $kv{data};
253 &$sub; 242 &$sub;
254 $cv->recv 243 $cv->recv
255 }; 244 };
256} 245}
257 246
247=item $cv = $fcp->list_peers ([$with_metdata[, $with_volatile]])
248
249=item $peers = $fcp->list_peers_sync ([$with_metdata[, $with_volatile]])
250
251=cut
252
258_txn list_peers => sub { 253_txn list_peers => sub {
259 my ($self, $cv, $with_metadata, $with_volatile) = @_; 254 my ($self, $cv, $with_metadata, $with_volatile) = @_;
260 255
261 my @res; 256 my @res;
262 257
275 } 270 }
276 }, 271 },
277 ); 272 );
278}; 273};
279 274
275=item $cv = $fcp->list_peer_notes ($node_identifier)
276
277=item $notes = $fcp->list_peer_notes_sync ($node_identifier)
278
279=cut
280
280_txn list_peer_notes => sub { 281_txn list_peer_notes => sub {
281 my ($self, $cv, $node_identifier) = @_; 282 my ($self, $cv, $node_identifier) = @_;
282 283
283 $self->send_msg (list_peer_notes => 284 $self->send_msg (list_peer_notes =>
284 node_identifier => $node_identifier, 285 node_identifier => $node_identifier,
289 1 290 1
290 }, 291 },
291 ); 292 );
292}; 293};
293 294
295=item $cv = $fcp->watch_global ($enabled[, $verbosity_mask])
296
297=item $fcp->watch_global_sync ($enabled[, $verbosity_mask])
298
299=cut
300
294_txn watch_global => sub { 301_txn watch_global => sub {
295 my ($self, $cv, $enabled, $verbosity_mask) = @_; 302 my ($self, $cv, $enabled, $verbosity_mask) = @_;
296 303
297 $self->send_msg (watch_global => 304 $self->send_msg (watch_global =>
298 enabled => $enabled ? "true" : "false", 305 enabled => $enabled ? "true" : "false",
299 defined $verbosity_mask ? (verbosity_mask => $verbosity_mask+0) : (), 306 defined $verbosity_mask ? (verbosity_mask => $verbosity_mask+0) : (),
300 ); 307 );
301 308
302 $cv->(); 309 $cv->();
303}; 310};
311
312=item $cv = $fcp->list_persistent_requests
313
314=item $reqs = $fcp->list_persistent_requests_sync
315
316=cut
304 317
305_txn list_persistent_requests => sub { 318_txn list_persistent_requests => sub {
306 my ($self, $cv) = @_; 319 my ($self, $cv) = @_;
307 320
308 my %res; 321 my %res;
333 0 346 0
334 } 347 }
335 }; 348 };
336}; 349};
337 350
351=item $cv = $fcp->remove_request ($global, $identifier)
352
353=item $status = $fcp->remove_request_sync ($global, $identifier)
354
355=cut
356
338_txn remove_request => sub { 357_txn remove_request => sub {
339 my ($self, $cv, $global, $identifier) = @_; 358 my ($self, $cv, $global, $identifier) = @_;
340 359
341 $self->send_msg (remove_request => 360 $self->send_msg (remove_request =>
342 global => $global ? "true" : "false", 361 global => $global ? "true" : "false",
346 365
347 $cv->($kv); 366 $cv->($kv);
348 1 367 1
349 }, 368 },
350 ); 369 );
351
352 $cv->();
353}; 370};
371
372=item $cv = $fcp->modify_persistent_request ($global, $identifier[, $client_token[, $priority_class]])
373
374=item $sync = $fcp->modify_persistent_request_sync ($global, $identifier[, $client_token[, $priority_class]])
375
376=cut
354 377
355_txn modify_persistent_request => sub { 378_txn modify_persistent_request => sub {
356 my ($self, $cv, $global, $identifier, $client_token, $priority_class) = @_; 379 my ($self, $cv, $global, $identifier, $client_token, $priority_class) = @_;
357 380
358 $self->send_msg (modify_persistent_request => 381 $self->send_msg (modify_persistent_request =>
359 global => $global ? "true" : "false", 382 global => $global ? "true" : "false",
360 identifier => $identifier,
361 defined $client_token ? (client_token => $client_token ) : (), 383 defined $client_token ? (client_token => $client_token ) : (),
362 defined $priority_class ? (priority_class => $priority_class) : (), 384 defined $priority_class ? (priority_class => $priority_class) : (),
385 identifier => $identifier,
363 id_cb => sub { 386 id_cb => sub {
364 my ($self, $type, $kv, $rdata) = @_; 387 my ($self, $type, $kv, $rdata) = @_;
365 388
366 $cv->($kv); 389 $cv->($kv);
367 1 390 1
368 }, 391 },
369 ); 392 );
370
371 $cv->();
372}; 393};
394
395=item $cv = $fcp->get_plugin_info ($name, $detailed)
396
397=item $info = $fcp->get_plugin_info_sync ($name, $detailed)
398
399=cut
373 400
374_txn get_plugin_info => sub { 401_txn get_plugin_info => sub {
375 my ($self, $cv, $name, $detailed) = @_; 402 my ($self, $cv, $name, $detailed) = @_;
376 403
377 $self->send_msg (get_plugin_info => 404 $self->send_msg (get_plugin_info =>
382 409
383 $cv->($kv); 410 $cv->($kv);
384 1 411 1
385 }, 412 },
386 ); 413 );
414};
387 415
388 $cv->(); 416=item $cv = $fcp->client_get ($uri, $identifier, %kv)
417
418=item $status = $fcp->client_get_sync ($uri, $identifier, %kv)
419
420%kv can contain (L<http://wiki.freenetproject.org/FCP2p0ClientGet>).
421
422ignore_ds, ds_only, verbosity, max_size, max_temp_size, max_retries,
423priority_class, persistence, client_token, global, return_type,
424binary_blob, allowed_mime_types, filename, temp_filename
425
426=cut
427
428_txn client_get => sub {
429 my ($self, $cv, $uri, $identifier, %kv) = @_;
430
431 $self->send_msg (client_get =>
432 %kv,
433 uri => $uri,
434 identifier => $identifier,
435 id_cb => sub {
436 my ($self, $type, $kv, $rdata) = @_;
437
438 $cv->($kv);
439 1
440 },
441 );
389}; 442};
390 443
391=back 444=back
445
446=head1 EXAMPLE PROGRAM
447
448 use AnyEvent::FCP;
449
450 my $fcp = new AnyEvent::FCP;
451
452 # let us look at the global request list
453 $fcp->watch_global (1, 0);
454
455 # list them, synchronously
456 my $req = $fcp->list_persistent_requests_sync;
457
458 # go through all requests
459 for my $req (values %$req) {
460 # skip jobs not directly-to-disk
461 next unless $req->{return_type} eq "disk";
462 # skip jobs not issued by FProxy
463 next unless $req->{identifier} =~ /^FProxy:/;
464
465 if ($req->{data_found}) {
466 # file has been successfully downloaded
467
468 ... move the file away
469 (left as exercise)
470
471 # remove the request
472
473 $fcp->remove_request (1, $req->{identifier});
474 } elsif ($req->{get_failed}) {
475 # request has failed
476 if ($req->{get_failed}{code} == 11) {
477 # too many path components, should restart
478 } else {
479 # other failure
480 }
481 } else {
482 # modify priorities randomly, to improve download rates
483 $fcp->modify_persistent_request (1, $req->{identifier}, undef, int 6 - 5 * (rand) ** 1.7)
484 if 0.1 > rand;
485 }
486 }
487
488 # see if the dummy plugin is loaded, to ensure all previous requests have finished.
489 $fcp->get_plugin_info_sync ("dummy");
392 490
393=head1 SEE ALSO 491=head1 SEE ALSO
394 492
395L<http://wiki.freenetproject.org/FreenetFCPSpec2Point0>, L<Net::FCP>. 493L<http://wiki.freenetproject.org/FreenetFCPSpec2Point0>, L<Net::FCP>.
396 494

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines