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.10 by root, Tue Aug 4 00:50:25 2015 UTC vs.
Revision 1.11 by root, Fri Aug 7 01:54:00 2015 UTC

35 35
36 use AnyEvent::FCP; 36 use AnyEvent::FCP;
37 37
38 my $fcp = new AnyEvent::FCP; 38 my $fcp = new AnyEvent::FCP;
39 39
40 $fcp->watch_global_sync (1, 0); 40 $fcp->watch_global (1, 0);
41 my $req = $fcp->list_persistent_requests_sync; 41 my $req = $fcp->list_persistent_requests;
42 42
43TODO
43 for my $req (values %$req) { 44 for my $req (values %$req) {
44 if ($req->{filename} =~ /a/) { 45 if ($req->{filename} =~ /a/) {
45 $fcp->modify_persistent_request_sync (1, $req->{identifier}, undef, 0); 46 $fcp->modify_persistent_request (1, $req->{identifier}, undef, 0);
46 } 47 }
47 } 48 }
48 49
49=head2 IMPORT TAGS 50=head2 IMPORT TAGS
50 51
51Nothing much can be "imported" from this module right now. 52Nothing much can be "imported" from this module right now.
52 53
53=head2 THE AnyEvent::FCP CLASS 54=head1 THE AnyEvent::FCP CLASS
54 55
55=over 4 56=over 4
56 57
57=cut 58=cut
58 59
77 $_ 78 $_
78} 79}
79 80
80sub tolc($) { 81sub tolc($) {
81 local $_ = shift; 82 local $_ = shift;
82 1 while s/(SVK|CHK|URI|FCP|DS|MIME|DDA)([^_])/$1\_$2/i; 83 1 while s/(SVK|CHK|URI|FCP|DS|MIME|DDA)([^_])/$1\_$2/;
83 1 while s/([^_])(SVK|CHK|URI|FCP|DS|MIME|DDA)/$1\_$2/i; 84 1 while s/([^_])(SVK|CHK|URI|FCP|DS|MIME|DDA)/$1\_$2/;
84 s/(?<=[a-z])(?=[A-Z])/_/g; 85 s/(?<=[a-z])(?=[A-Z])/_/g;
85 lc 86 lc
86} 87}
87 88
88=item $fcp = new AnyEvent::FCP [host => $host][, port => $port][, progress => \&cb][, name => $name] 89=item $fcp = new AnyEvent::FCP [host => $host][, port => $port][, name => $name]
89 90
90Create a new FCP connection to the given host and port (default 91Create a new FCP connection to the given host and port (default
91127.0.0.1:9481, or the environment variables C<FREDHOST> and C<FREDPORT>). 92127.0.0.1:9481, or the environment variables C<FREDHOST> and C<FREDPORT>).
92 93
93If no C<name> was specified, then AnyEvent::FCP will generate a 94If no C<name> was specified, then AnyEvent::FCP will generate a
94(hopefully) unique client name for you. 95(hopefully) unique client name for you.
95 96
96You can install a progress callback that is being called with the AnyEvent::FCP
97object, the type, a hashref with key-value pairs and a reference to any received data,
98for all unsolicited messages.
99
100Example:
101
102 sub progress_cb {
103 my ($self, $type, $kv, $rdata) = @_;
104
105 if ($type eq "simple_progress") {
106 warn "$kv->{identifier} $kv->{succeeded}/$kv->{required}\n";
107 }
108 }
109
110=cut 97=cut
111 98
112sub new { 99sub new {
113 my $class = shift; 100 my $class = shift;
114 my $self = bless { @_ }, $class; 101 my $self = bless {
115 102 host => $ENV{FREDHOST} || "127.0.0.1",
116 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1"; 103 port => $ENV{FREDPORT} || 9481,
117 $self->{port} ||= $ENV{FREDPORT} || 9481; 104 timeout => 3600 * 2,
118 $self->{name} ||= time.rand.rand.rand; # lame 105 name => time.rand.rand.rand, # lame
119 $self->{timeout} ||= 3600*2; 106 @_,
120 $self->{progress} ||= sub { }; 107 queue => [],
121 108 req => {},
122 $self->{id} = "a0"; 109 id => "a0",
110 }, $class;
123 111
124 { 112 {
125 Scalar::Util::weaken (my $self = $self); 113 Scalar::Util::weaken (my $self = $self);
126 114
127 $self->{hdl} = new AnyEvent::Handle 115 $self->{hdl} = new AnyEvent::Handle
135 on_eof => $self->{on_eof} || sub { }; 123 on_eof => $self->{on_eof} || sub { };
136 124
137 Scalar::Util::weaken ($self->{hdl}{fcp} = $self); 125 Scalar::Util::weaken ($self->{hdl}{fcp} = $self);
138 } 126 }
139 127
140 $self->send_msg ( 128 $self->send_msg (client_hello =>
141 client_hello =>
142 name => $self->{name}, 129 name => $self->{name},
143 expected_version => "2.0", 130 expected_version => "2.0",
144 ); 131 );
145 132
146 $self 133 $self
147} 134}
202 push @$queue, $cb; 189 push @$queue, $cb;
203 $cb->($self, AnyEvent::Util::guard { $self->_push_queue ($queue) }) 190 $cb->($self, AnyEvent::Util::guard { $self->_push_queue ($queue) })
204 unless $#$queue; 191 unless $#$queue;
205} 192}
206 193
194# how to merge these types into $self->{persistent}
195our %PERSISTENT_TYPE = (
196 persistent_get => sub { %{ $_[1] } = (type => "persistent_get" , %{ $_[2] }) },
197 persistent_put => sub { %{ $_[1] } = (type => "persistent_put" , %{ $_[2] }) },
198 persistent_put_dir => sub { %{ $_[1] } = (type => "persistent_put_dir", %{ $_[2] }) },
199 persistent_request_modified => sub { %{ $_[1] } = (%{ $_[1] }, %{ $_[2] }) },
200 persistent_request_removed => sub { delete $_[0]{req}{$_[2]{identifier}} },
201
202 simple_progress => sub { $_[1]{simple_progress} = $_[2] }, # get/put
203
204 uri_generated => sub { $_[1]{uri_generated} = $_[2] }, # put
205 generated_metadata => sub { $_[1]{generated_metadata} = $_[2] }, # put
206 started_compression => sub { $_[1]{started_compression} = $_[2] }, # put
207 finished_compression => sub { $_[1]{finished_compression} = $_[2] }, # put
208 put_fetchable => sub { $_[1]{put_fetchable} = $_[2] }, # put
209 put_failed => sub { $_[1]{put_failed} = $_[2] }, # put
210 put_successful => sub { $_[1]{put_successful} = $_[2] }, # put
211
212 sending_to_network => sub { $_[1]{sending_to_network} = $_[2] }, # get
213 compatibility_mode => sub { $_[1]{compatibility_mode} = $_[2] }, # get
214 expected_hashes => sub { $_[1]{expected_hashes} = $_[2] }, # get
215 expected_mime => sub { $_[1]{expected_mime} = $_[2] }, # get
216 expected_data_length => sub { $_[1]{expected_data_length} = $_[2] }, # get
217 get_failed => sub { $_[1]{get_failed} = $_[2] }, # get
218 data_found => sub { $_[1]{data_found} = $_[2] }, # get
219 enter_finite_cooldown => sub { $_[1]{enter_finite_cooldown} = $_[2] }, # get
220);
221
222sub recv {
223 my ($self, $type, $kv, @extra) = @_;
224
225 if (my $cb = $PERSISTENT_TYPE{$type}) {
226 my $id = $kv->{identifier};
227 my $req = $_[0]{req}{$id} ||= {};
228 $cb->($self, $req, $kv);
229 $self->recv (request_change => $kv, $type, @extra);
230 }
231
232 my $on = $self->{on};
233 for (0 .. $#$on) {
234 unless (my $res = $on->[$_]($self, $type, $kv, @extra)) {
235 splice @$on, $_, 1 unless defined $res;
236 return;
237 }
238 }
239
240 if (my $cb = $self->{queue}[0]) {
241 $cb->($self, $type, $kv, @extra)
242 and shift @{ $self->{queue} };
243 } else {
244 $self->default_recv ($type, $kv, @extra);
245 }
246}
247
207sub on_read { 248sub on_read {
208 my ($self) = @_; 249 my ($self) = @_;
209 250
210 my $type; 251 my $type;
211 my %kv; 252 my %kv;
212 my $rdata; 253 my $rdata;
213
214 my $done_cb = sub {
215 $kv{pkt_type} = $type;
216
217 my $on = $self->{on};
218 for (0 .. $#$on) {
219 unless (my $res = $on->[$_]($self, $type, \%kv, $rdata)) {
220 splice @$on, $_, 1 unless defined $res;
221 return;
222 }
223 }
224
225 if (my $cb = $self->{queue}[0]) {
226 $cb->($self, $type, \%kv, $rdata)
227 and shift @{ $self->{queue} };
228 } else {
229 $self->default_recv ($type, \%kv, $rdata);
230 }
231 };
232 254
233 my $hdr_cb; $hdr_cb = sub { 255 my $hdr_cb; $hdr_cb = sub {
234 if ($_[1] =~ /^([^=]+)=(.*)$/) { 256 if ($_[1] =~ /^([^=]+)=(.*)$/) {
235 my ($k, $v) = ($1, $2); 257 my ($k, $v) = ($1, $2);
236 my @k = split /\./, tolc $k; 258 my @k = split /\./, tolc $k;
249 271
250 $_[0]->push_read (line => $hdr_cb); 272 $_[0]->push_read (line => $hdr_cb);
251 } elsif ($_[1] eq "Data") { 273 } elsif ($_[1] eq "Data") {
252 $_[0]->push_read (chunk => delete $kv{data_length}, sub { 274 $_[0]->push_read (chunk => delete $kv{data_length}, sub {
253 $rdata = \$_[1]; 275 $rdata = \$_[1];
254 $done_cb->(); 276 $self->recv ($type, \%kv, $rdata);
255 }); 277 });
256 } elsif ($_[1] eq "EndMessage") { 278 } elsif ($_[1] eq "EndMessage") {
257 $done_cb->(); 279 $self->recv ($type, \%kv);
258 } else { 280 } else {
259 die "protocol error, expected message end, got $_[1]\n";#d# 281 die "protocol error, expected message end, got $_[1]\n";#d#
260 } 282 }
261 }; 283 };
262 284
272 if ($type eq "node_hello") { 294 if ($type eq "node_hello") {
273 $self->{node_hello} = $kv; 295 $self->{node_hello} = $kv;
274 } elsif (exists $self->{id}{$kv->{identifier}}) { 296 } elsif (exists $self->{id}{$kv->{identifier}}) {
275 $self->{id}{$kv->{identifier}}($self, $type, $kv, $rdata) 297 $self->{id}{$kv->{identifier}}($self, $type, $kv, $rdata)
276 and delete $self->{id}{$kv->{identifier}}; 298 and delete $self->{id}{$kv->{identifier}};
277 } else {
278 &{ $self->{progress} };
279 } 299 }
280} 300}
301
302our $NOP_CB = sub { };
281 303
282sub _txn { 304sub _txn {
283 my ($name, $sub) = @_; 305 my ($name, $sub) = @_;
284 306
285 *{$name} = sub { 307 *{$name} = sub {
286 splice @_, 1, 0, (my $cv = AnyEvent->condvar);
287 &$sub;
288 $cv
289 };
290
291 *{"$name\_sync"} = sub {
292 splice @_, 1, 0, (my $cv = AnyEvent->condvar); 308 splice @_, 1, 0, (my $cv = AnyEvent->condvar);
293 &$sub; 309 &$sub;
294 $cv->recv 310 $cv->recv
295 }; 311 };
296}
297 312
298=item $cv = $fcp->list_peers ([$with_metdata[, $with_volatile]]) 313 *{"$name\_"} = sub {
314 splice @_, 1, 0, pop || $NOP_CB;
315 &$sub;
316 };
317}
299 318
300=item $peers = $fcp->list_peers_sync ([$with_metdata[, $with_volatile]]) 319=item $peers = $fcp->list_peers ([$with_metdata[, $with_volatile]])
301 320
302=cut 321=cut
303 322
304_txn list_peers => sub { 323_txn list_peers => sub {
305 my ($self, $cv, $with_metadata, $with_volatile) = @_; 324 my ($self, $cv, $with_metadata, $with_volatile) = @_;
321 } 340 }
322 }, 341 },
323 ); 342 );
324}; 343};
325 344
326=item $cv = $fcp->list_peer_notes ($node_identifier)
327
328=item $notes = $fcp->list_peer_notes_sync ($node_identifier) 345=item $notes = $fcp->list_peer_notes ($node_identifier)
329 346
330=cut 347=cut
331 348
332_txn list_peer_notes => sub { 349_txn list_peer_notes => sub {
333 my ($self, $cv, $node_identifier) = @_; 350 my ($self, $cv, $node_identifier) = @_;
341 1 358 1
342 }, 359 },
343 ); 360 );
344}; 361};
345 362
346=item $cv = $fcp->watch_global ($enabled[, $verbosity_mask])
347
348=item $fcp->watch_global_sync ($enabled[, $verbosity_mask]) 363=item $fcp->watch_global ($enabled[, $verbosity_mask])
349 364
350=cut 365=cut
351 366
352_txn watch_global => sub { 367_txn watch_global => sub {
353 my ($self, $cv, $enabled, $verbosity_mask) = @_; 368 my ($self, $cv, $enabled, $verbosity_mask) = @_;
358 ); 373 );
359 374
360 $cv->(); 375 $cv->();
361}; 376};
362 377
363=item $cv = $fcp->list_persistent_requests
364
365=item $reqs = $fcp->list_persistent_requests_sync 378=item $reqs = $fcp->list_persistent_requests
366 379
367=cut 380=cut
368 381
369_txn list_persistent_requests => sub { 382_txn list_persistent_requests => sub {
370 my ($self, $cv) = @_; 383 my ($self, $cv) = @_;
371 384
372 $self->serialise (list_persistent_requests => sub { 385 $self->serialise (list_persistent_requests => sub {
373 my ($self, $guard) = @_; 386 my ($self, $guard) = @_;
374 387
375 my %res; 388 my @res;
376 389
377 $self->send_msg ("list_persistent_requests"); 390 $self->send_msg ("list_persistent_requests");
378 391
379 $self->on (sub { 392 $self->on (sub {
380 my ($self, $type, $kv, $rdata) = @_; 393 my ($self, $type, $kv, $rdata) = @_;
381 394
382 $guard if 0; 395 $guard if 0;
383 396
384 if ($type eq "end_list_persistent_requests") { 397 if ($type eq "end_list_persistent_requests") {
385 $cv->(\%res); 398 $cv->(\@res);
386 return; 399 return;
387 } else { 400 } else {
388 my $id = $kv->{identifier}; 401 my $id = $kv->{identifier};
389 402
390 if ($type =~ /^persistent_(get|put|put_dir)$/) { 403 if ($type =~ /^persistent_(get|put|put_dir)$/) {
391 $res{$id} = { 404 push @res, [$type, $kv];
392 type => $1,
393 %{ $res{$id} },
394 %$kv,
395 };
396 } elsif ($type eq "simple_progress") {
397 delete $kv->{pkt_type}; # save memory
398 push @{ $res{delete $kv->{identifier}}{simple_progress} }, $kv;
399 } else {
400 $res{delete $kv->{identifier}}{delete $kv->{pkt_type}} = $kv;
401 } 405 }
402 } 406 }
403 407
404 1 408 1
405 }); 409 });
406 }); 410 });
407}; 411};
408 412
409=item $cv = $fcp->remove_request ($global, $identifier)
410
411=item $status = $fcp->remove_request_sync ($global, $identifier) 413=item $status = $fcp->remove_request ($global, $identifier)
412 414
413=cut 415=cut
414 416
415_txn remove_request => sub { 417_txn remove_request => sub {
416 my ($self, $cv, $global, $identifier) = @_; 418 my ($self, $cv, $global, $identifier) = @_;
425 1 427 1
426 }, 428 },
427 ); 429 );
428}; 430};
429 431
430=item $cv = $fcp->modify_persistent_request ($global, $identifier[, $client_token[, $priority_class]]) 432=item $sync = $fcp->modify_persistent_request ($global, $identifier[, $client_token[, $priority_class]])
431
432=item $sync = $fcp->modify_persistent_request_sync ($global, $identifier[, $client_token[, $priority_class]])
433 433
434=cut 434=cut
435 435
436_txn modify_persistent_request => sub { 436_txn modify_persistent_request => sub {
437 my ($self, $cv, $global, $identifier, $client_token, $priority_class) = @_; 437 my ($self, $cv, $global, $identifier, $client_token, $priority_class) = @_;
448 1 448 1
449 }, 449 },
450 ); 450 );
451}; 451};
452 452
453=item $cv = $fcp->get_plugin_info ($name, $detailed)
454
455=item $info = $fcp->get_plugin_info_sync ($name, $detailed) 453=item $info = $fcp->get_plugin_info ($name, $detailed)
456 454
457=cut 455=cut
458 456
459_txn get_plugin_info => sub { 457_txn get_plugin_info => sub {
460 my ($self, $cv, $name, $detailed) = @_; 458 my ($self, $cv, $name, $detailed) = @_;
469 1 467 1
470 }, 468 },
471 ); 469 );
472}; 470};
473 471
474=item $cv = $fcp->client_get ($uri, $identifier, %kv)
475
476=item $status = $fcp->client_get_sync ($uri, $identifier, %kv) 472=item $status = $fcp->client_get ($uri, $identifier, %kv)
477 473
478%kv can contain (L<http://wiki.freenetproject.org/FCP2p0ClientGet>). 474%kv can contain (L<http://wiki.freenetproject.org/FCP2p0ClientGet>).
479 475
480ignore_ds, ds_only, verbosity, max_size, max_temp_size, max_retries, 476ignore_ds, ds_only, verbosity, max_size, max_temp_size, max_retries,
481priority_class, persistence, client_token, global, return_type, 477priority_class, persistence, client_token, global, return_type,
488 484
489 $self->send_msg (client_get => 485 $self->send_msg (client_get =>
490 %kv, 486 %kv,
491 uri => $uri, 487 uri => $uri,
492 identifier => $identifier, 488 identifier => $identifier,
493 id_cb => sub { 489 );
490};
491
492=item $status = $fcp->remove_request ($identifier[, $global])
493
494Remove the request with the given isdentifier. Returns true if successful,
495false on error.
496
497=cut
498
499_txn remove_request => sub {
500 my ($self, $cv, $identifier, $global) = @_;
501
502 $self->serialise ($identifier => sub {
503 my ($self, $guard) = @_;
504
505 $self->send_msg (remove_request =>
506 identifier => $identifier,
507 global => $global ? "true" : "false",
508 );
509 $self->on (sub {
494 my ($self, $type, $kv, $rdata) = @_; 510 my ($self, $type, $kv, @extra) = @_;
495 511
512 if ($kv->{identifier} eq $identifier) {
513 if ($type eq "persistent_request_removed") {
496 $cv->($kv); 514 $cv->(1);
515 return;
516 } elsif ($type eq "protocol_error") {
517 $cv->(undef);
518 return;
519 }
520 }
521
497 1 522 1
498 }, 523 });
499 ); 524 });
500}; 525};
501 526
502=item $cv = $fcp->test_dda_sync ($local_directory, $remote_directory, $want_read, $want_write)
503
504=item ($can_read, $can_write) = $fcp->test_dda_sync ($local_directory, $remote_directory, $want_read, $want_write)) 527=item ($can_read, $can_write) = $fcp->test_dda ($local_directory, $remote_directory, $want_read, $want_write))
505 528
506The DDA test in FCP is probably the single most broken protocol - only 529The DDA test in FCP is probably the single most broken protocol - only
507one directory test can be outstanding at any time, and some guessing and 530one directory test can be outstanding at any time, and some guessing and
508heuristics are involved in mangling the paths. 531heuristics are involved in mangling the paths.
509 532
510This function combines C<TestDDARequest> and C<TestDDAResponse> in one 533This function combines C<TestDDARequest> and C<TestDDAResponse> in one
511request, handling file reading and writing as well. 534request, handling file reading and writing as well, and tries very hard to
535do the right thing.
536
537Both C<$local_directory> and C<$remote_directory> must specify the same
538directory - C<$local_directory> is the directory path on the client (where
539L<AnyEvent::FCP> runs) and C<$remote_directory> is the directory path on
540the server (where the freenet node runs). When both are running on the
541same node, the paths are generally identical.
542
543C<$want_read> and C<$want_write> should be set to a true value when you
544want to read (get) files or write (put) files, respectively.
545
546On error, an exception is thrown. Otherwise, C<$can_read> and
547C<$can_write> indicate whether you can reaqd or write to freenet via the
548directory.
512 549
513=cut 550=cut
514 551
515_txn test_dda => sub { 552_txn test_dda => sub {
516 my ($self, $cv, $local, $remote, $want_read, $want_write) = @_; 553 my ($self, $cv, $local, $remote, $want_read, $want_write) = @_;
542 } 579 }
543 580
544 my %response = (directory => $remote); 581 my %response = (directory => $remote);
545 582
546 if (length $kv->{read_filename}) { 583 if (length $kv->{read_filename}) {
547 warn "$local/$kv->{read_filename}";#d#
548 if (open my $fh, "<:raw", "$local/$kv->{read_filename}") { 584 if (open my $fh, "<:raw", "$local/$kv->{read_filename}") {
549 sysread $fh, my $buf, -s $fh; 585 sysread $fh, my $buf, -s $fh;
550 $response{read_content} = $buf; 586 $response{read_content} = $buf;
551 } 587 }
552 } 588 }
588 }); 624 });
589}; 625};
590 626
591=back 627=back
592 628
629=head2 REQUEST CACHE
630
631The C<AnyEvent::FCP> class keeps a request cache, where it caches all
632information from requests.
633
634For these messages, it will store a copy of the key-value pairs, together with a C<type> slot,
635in C<< $fcp->{req}{$identifier} >>:
636
637 persistent_get
638 persistent_put
639 persistent_put_dir
640
641This message updates the stored data:
642
643 persistent_request_modified
644
645This message will remove this entry:
646
647 persistent_request_removed
648
649These messages get merged into the cache entry, under their
650type, i.e. a C<simple_progress> message will be stored in C<<
651$fcp->{req}{$identifier}{simple_progress} >>:
652
653 simple_progress # get/put
654
655 uri_generated # put
656 generated_metadata # put
657 started_compression # put
658 finished_compression # put
659 put_failed # put
660 put_fetchable # put
661 put_successful # put
662
663 sending_to_network # get
664 compatibility_mode # get
665 expected_hashes # get
666 expected_mime # get
667 expected_data_length # get
668 get_failed # get
669 data_found # get
670 enter_finite_cooldown # get
671
672In addition, an event (basically a fake message) of type C<request_changed> is generated
673on every change, which will be called as C<< $cb->($fcp, $kv, $type) >>, where C<$type>
674is the type of the original message triggering the change,
675
676To fill this cache with the global queue and keep it updated,
677call C<watch_global> to subscribe to updates, followed by
678C<list_persistent_requests_sync>.
679
680 $fcp->watch_global_sync_; # do not wait
681 $fcp->list_persistent_requests; # wait
682
683To get a better idea of what is stored in the cache, here is an example of
684what might be stored in C<< $fcp->{req}{"Frost-gpl.txt"} >>:
685
686 {
687 identifier => "Frost-gpl.txt",
688 uri => 'CHK@Fnx5kzdrfE,EImdzaVyEWl,AAIC--8/gpl.txt',
689 binary_blob => "false",
690 global => "true",
691 max_retries => -1,
692 max_size => 9223372036854775807,
693 persistence => "forever",
694 priority_class => 3,
695 real_time => "false",
696 return_type => "direct",
697 started => "true",
698 type => "persistent_get",
699 verbosity => 2147483647,
700 sending_to_network => {
701 identifier => "Frost-gpl.txt",
702 global => "true",
703 },
704 compatibility_mode => {
705 identifier => "Frost-gpl.txt",
706 definitive => "true",
707 dont_compress => "false",
708 global => "true",
709 max => "COMPAT_1255",
710 min => "COMPAT_1255",
711 },
712 expected_hashes => {
713 identifier => "Frost-gpl.txt",
714 global => "true",
715 hashes => {
716 ed2k => "d83596f5ee3b7...",
717 md5 => "e0894e4a2a6...",
718 sha1 => "...",
719 sha256 => "...",
720 sha512 => "...",
721 tth => "...",
722 },
723 },
724 expected_mime => {
725 identifier => "Frost-gpl.txt",
726 global => "true",
727 metadata => { content_type => "application/rar" },
728 },
729 expected_data_length => {
730 identifier => "Frost-gpl.txt",
731 data_length => 37576,
732 global => "true",
733 },
734 simple_progress => {
735 identifier => "Frost-gpl.txt",
736 failed => 0,
737 fatally_failed => 0,
738 finalized_total => "true",
739 global => "true",
740 last_progress => 1438639282628,
741 required => 372,
742 succeeded => 102,
743 total => 747,
744 },
745 data_found => {
746 identifier => "Frost-gpl.txt",
747 completion_time => 1438663354026,
748 data_length => 37576,
749 global => "true",
750 metadata => { content_type => "image/jpeg" },
751 startup_time => 1438657196167,
752 },
753 }
754
593=head1 EXAMPLE PROGRAM 755=head1 EXAMPLE PROGRAM
594 756
595 use AnyEvent::FCP; 757 use AnyEvent::FCP;
596 758
597 my $fcp = new AnyEvent::FCP; 759 my $fcp = new AnyEvent::FCP;
598 760
599 # let us look at the global request list 761 # let us look at the global request list
600 $fcp->watch_global (1, 0); 762 $fcp->watch_global_ (1);
601 763
602 # list them, synchronously 764 # list them, synchronously
603 my $req = $fcp->list_persistent_requests_sync; 765 my $req = $fcp->list_persistent_requests;
604 766
605 # go through all requests 767 # go through all requests
768TODO
606 for my $req (values %$req) { 769 for my $req (values %$req) {
607 # skip jobs not directly-to-disk 770 # skip jobs not directly-to-disk
608 next unless $req->{return_type} eq "disk"; 771 next unless $req->{return_type} eq "disk";
609 # skip jobs not issued by FProxy 772 # skip jobs not issued by FProxy
610 next unless $req->{identifier} =~ /^FProxy:/; 773 next unless $req->{identifier} =~ /^FProxy:/;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines