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

Comparing cvsroot/Net-FCP/FCP.pm (file contents):
Revision 1.6 by root, Mon Sep 8 00:36:44 2003 UTC vs.
Revision 1.9 by root, Tue Sep 9 06:13:18 2003 UTC

17of what the messages do. I am too lazy to document all this here. 17of what the messages do. I am too lazy to document all this here.
18 18
19=head1 WARNING 19=head1 WARNING
20 20
21This module is alpha. While it probably won't destroy (much :) of your 21This module is alpha. While it probably won't destroy (much :) of your
22data, it currently works only with the Event module (alkthough the event 22data, it currently falls short of what it should provide (intelligent uri
23mechanism is fully pluggable). 23following, splitfile downloads, healing...)
24
25=head2 IMPORT TAGS
26
27Nothing much can be "imported" from this module right now. There are,
28however, certain "import tags" that can be used to select the event model
29to be used.
30
31Event models are implemented as modules under the C<Net::FCP::Event::xyz>
32class, where C<xyz> is the event model to use. The default is C<Event> (or
33later C<Auto>).
34
35The import tag to use is named C<event=xyz>, e.g. C<event=Event>,
36C<event=Glib> etc.
37
38You should specify the event module to use only in the main program.
24 39
25=head2 THE Net::FCP CLASS 40=head2 THE Net::FCP CLASS
26 41
27=over 4 42=over 4
28 43
31package Net::FCP; 46package Net::FCP;
32 47
33use Carp; 48use Carp;
34use IO::Socket::INET; 49use IO::Socket::INET;
35 50
36$VERSION = 0.03; 51$VERSION = 0.04;
37 52
38sub event_reg_cb { 53our $EVENT = Net::FCP::Event::Auto::;
39 my ($obj) = @_; 54$EVENT = Net::FCP::Event::Event::;#d#
40 require Event;
41 55
42 $obj->{eventdata} = Event->io ( 56sub import {
43 fd => $obj->{fh}, 57 shift;
44 poll => 'r', 58
45 cb => sub { 59 for (@_) {
46 $obj->fh_ready; 60 if (/^event=(\w+)$/) {
61 $EVENT = "Net::FCP::Event::$1";
47 }, 62 }
48 ); 63 }
64 eval "require $EVENT";
49} 65}
50
51sub event_unreg_cb {
52 $_[0]{eventdata}
53 and (delete $_[0]{eventdata})->cancel;
54}
55
56sub event_wait_cb {
57 Event::one_event();
58}
59
60$regcb = \&event_reg_cb;
61$unregcb = \&event_unreg_cb;
62$waitcb = \&event_wait_cb;
63 66
64sub touc($) { 67sub touc($) {
65 local $_ = shift; 68 local $_ = shift;
66 1 while s/((?:^|_)(?:svk|chk|uri)(?:_|$))/\U$1/; 69 1 while s/((?:^|_)(?:svk|chk|uri)(?:_|$))/\U$1/;
67 s/(?:^|_)(.)/\U$1/g; 70 s/(?:^|_)(.)/\U$1/g;
72 local $_ = shift; 75 local $_ = shift;
73 s/(?<=[a-z])(?=[A-Z])/_/g; 76 s/(?<=[a-z])(?=[A-Z])/_/g;
74 lc $_; 77 lc $_;
75} 78}
76 79
80=item $meta = Net::FCP::parse_metadata $string
81
82Parse a metadata string and return it.
83
84The metadata will be a hashref with key C<version> (containing
85the mandatory version header entries).
86
87All other headers are represented by arrayrefs (they can be repeated).
88
89Since this is confusing, here is a rather verbose example of a parsed
90manifest:
91
92 (
93 version => { revision => 1 },
94 document => [
95 {
96 "info.format" => "image/jpeg",
97 name => "background.jpg",
98 "redirect.target" => "freenet:CHK\@ZcagI,ra726bSw"
99 },
100 {
101 "info.format" => "text/html",
102 name => ".next",
103 "redirect.target" => "freenet:SSK\@ilUPAgM/TFEE/3"
104 },
105 {
106 "info.format" => "text/html",
107 "redirect.target" => "freenet:CHK\@8M8Po8ucwI,8xA"
108 }
109 ]
110 )
111
112=cut
113
114sub parse_metadata {
115 my $meta;
116
117 my $data = shift;
118 if ($data =~ /^Version\015?\012/gc) {
119 my $hdr = $meta->{version} = {};
120
121 for (;;) {
122 while ($data =~ /\G([^=\015\012]+)=([^\015\012]*)\015?\012/gc) {
123 my ($k, $v) = ($1, $2);
124 $hdr->{tolc $k} = $v;
125 }
126
127 if ($data =~ /\GEndPart\015?\012/gc) {
128 } elsif ($data =~ /\GEnd\015?\012/gc) {
129 last;
130 } elsif ($data =~ /\G([A-Za-z0-9.\-]+)\015?\012/gcs) {
131 push @{$meta->{tolc $1}}, $hdr = {};
132 } elsif ($data =~ /\G(.*)/gcs) {
133 die "metadata format error ($1)";
134 }
135 }
136 }
137
138 #$meta->{tail} = substr $data, pos $data;
139
140 $meta;
141}
142
77=item $fcp = new Net::FCP [host => $host][, port => $port] 143=item $fcp = new Net::FCP [host => $host][, port => $port]
78 144
79Create a new virtual FCP connection to the given host and port (default 145Create a new virtual FCP connection to the given host and port (default
80127.0.0.1:8481, or the environment variables C<FREDHOST> and C<FREDPORT>). 146127.0.0.1:8481, or the environment variables C<FREDHOST> and C<FREDPORT>).
81 147
94 160
95 $self->{nodehello} = $self->client_hello 161 $self->{nodehello} = $self->client_hello
96 or croak "unable to get nodehello from node\n"; 162 or croak "unable to get nodehello from node\n";
97 163
98 $self; 164 $self;
165}
166
167sub progress {
168 my ($self, $txn, $type, $attr) = @_;
169 warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
99} 170}
100 171
101=item $txn = $fcp->txn(type => attr => val,...) 172=item $txn = $fcp->txn(type => attr => val,...)
102 173
103The low-level interface to transactions. Don't use it. 174The low-level interface to transactions. Don't use it.
187=cut 258=cut
188 259
189_txn generate_chk => sub { 260_txn generate_chk => sub {
190 my ($self, $metadata, $data) = @_; 261 my ($self, $metadata, $data) = @_;
191 262
192 $self->txn (generate_chk => data => "$data$metadata", meta_data_length => length $metadata); 263 $self->txn (generate_chk => data => "$data$metadata", metadata_length => length $metadata);
193}; 264};
194 265
195=item $txn = $fcp->txn_generate_svk_pair 266=item $txn = $fcp->txn_generate_svk_pair
196 267
197=item ($public, $private) = @{ $fcp->generate_svk_pair } 268=item ($public, $private) = @{ $fcp->generate_svk_pair }
248 $self->txn (get_size => URI => $uri); 319 $self->txn (get_size => URI => $uri);
249}; 320};
250 321
251=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]]) 322=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]])
252 323
253=item ($data, $metadata) = @{ $fcp->client_get ($uri, $htl, $removelocal) 324=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal)
254 325
255Fetches a (small, as it should fit into memory) file from freenet. 326Fetches a (small, as it should fit into memory) file from
327freenet. C<$meta> is the metadata (as returned by C<parse_metadata> or
328C<undef>).
256 329
257Due to the overhead, a better method to download big fiels should be used. 330Due to the overhead, a better method to download big files should be used.
258 331
259 my ($data, $meta) = @{ 332 my ($meta, $data) = @{
260 $fcp->client_get ( 333 $fcp->client_get (
261 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w" 334 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w"
262 ) 335 )
263 }; 336 };
264 337
337 410
338 #$fh->shutdown (1); # freenet buggy?, well, it's java... 411 #$fh->shutdown (1); # freenet buggy?, well, it's java...
339 412
340 $self->{fh} = $fh; 413 $self->{fh} = $fh;
341 414
342 $Net::FCP::regcb->($self); 415 $EVENT->reg_r_cb ($self);
343 416
344 $self; 417 $self;
418}
419
420=item $userdata = $txn->userdata ([$userdata])
421
422Get and/or set user-specific data. This is useful in progress callbacks.
423
424=cut
425
426sub userdata($;$) {
427 my ($self, $data) = @_;
428 $self->{userdata} = $data if @_ >= 2;
429 $self->{userdata};
345} 430}
346 431
347sub fh_ready { 432sub fh_ready {
348 my ($self) = @_; 433 my ($self) = @_;
349 434
355 } else { 440 } else {
356 last; 441 last;
357 } 442 }
358 } elsif ($self->{buf} =~ s/^DataChunk\015?\012Length=([0-9a-fA-F]+)\015?\012Data\015?\012//) { 443 } elsif ($self->{buf} =~ s/^DataChunk\015?\012Length=([0-9a-fA-F]+)\015?\012Data\015?\012//) {
359 $self->{datalen} = hex $1; 444 $self->{datalen} = hex $1;
360 } elsif ($self->{buf} =~ s/^([a-zA-Z]+)\015?\012(.*?)\015?\012EndMessage\015?\012//s) { 445 } elsif ($self->{buf} =~ s/^([a-zA-Z]+)\015?\012(?:(.+?)\015?\012)?EndMessage\015?\012//s) {
361 $self->rcv ($1, { 446 $self->rcv ($1, {
362 map { my ($a, $b) = split /=/, $_, 2; ((Net::FCP::tolc $a), $b) } 447 map { my ($a, $b) = split /=/, $_, 2; ((Net::FCP::tolc $a), $b) }
363 split /\015?\012/, $2 448 split /\015?\012/, $2
364 }); 449 });
365 } else { 450 } else {
366 last; 451 last;
367 } 452 }
368 } 453 }
369 } else { 454 } else {
370 $Net::FCP::unregcb->($self); 455 $EVENT->unreg_r_cb ($self);
371 delete $self->{fh}; 456 delete $self->{fh};
372 $self->eof; 457 $self->eof;
373 } 458 }
374} 459}
375 460
376sub rcv_data { 461sub rcv_data {
377 my ($self, $chunk) = @_; 462 my ($self, $chunk) = @_;
378 463
379 $self->{data} .= $chunk; 464 $self->{data} .= $chunk;
465
466 $self->progress ("data", { chunk => length $chunk, total => length $self->{data}, end => $self->{datalength} });
380} 467}
381 468
382sub rcv { 469sub rcv {
383 my ($self, $type, $attr) = @_; 470 my ($self, $type, $attr) = @_;
384 471
391 } else { 478 } else {
392 warn "received unexpected reply type '$type' for '$self->{type}', ignoring\n"; 479 warn "received unexpected reply type '$type' for '$self->{type}', ignoring\n";
393 } 480 }
394} 481}
395 482
483sub throw {
484 my ($self, $exc) = @_;
485
486 $self->{exception} = $exc;
487 $self->set_result (1);
488}
489
396sub set_result { 490sub set_result {
397 my ($self, $result) = @_; 491 my ($self, $result) = @_;
398 492
399 $self->{result} = $result unless exists $self->{result}; 493 $self->{result} = $result unless exists $self->{result};
400} 494}
402sub eof { 496sub eof {
403 my ($self) = @_; 497 my ($self) = @_;
404 $self->set_result; 498 $self->set_result;
405} 499}
406 500
501sub progress {
502 my ($self, $type, $attr) = @_;
503 $self->{fcp}->progress ($self, $type, $attr);
504}
505
407=item $result = $txn->result 506=item $result = $txn->result
408 507
409Waits until a result is available and then returns it. 508Waits until a result is available and then returns it.
410 509
411This waiting is (depending on your event model) not very efficient, as it 510This waiting is (depending on your event model) not very efficient, as it
414=cut 513=cut
415 514
416sub result { 515sub result {
417 my ($self) = @_; 516 my ($self) = @_;
418 517
419 $Net::FCP::waitcb->() while !exists $self->{result}; 518 $EVENT->wait_event while !exists $self->{result};
519
520 die $self->{exception} if $self->{exception};
420 521
421 return $self->{result}; 522 return $self->{result};
422} 523}
423 524
424sub DESTROY { 525sub DESTROY {
425 $Net::FCP::unregcb->($_[0]); 526 $EVENT->unreg_r_cb ($_[0]);
527 #$EVENT->unreg_w_cb ($_[0]);
426} 528}
427 529
428package Net::FCP::Txn::ClientHello; 530package Net::FCP::Txn::ClientHello;
429 531
430use base Net::FCP::Txn; 532use base Net::FCP::Txn;
488package Net::FCP::Txn::ClientGet; 590package Net::FCP::Txn::ClientGet;
489 591
490use base Net::FCP::Txn; 592use base Net::FCP::Txn;
491 593
492sub rcv_data_found { 594sub rcv_data_found {
493 my ($self, $attr) = @_; 595 my ($self, $attr, $type) = @_;
596
597 $self->progress ($type, $attr);
494 598
495 $self->{datalength} = hex $attr->{data_length}; 599 $self->{datalength} = hex $attr->{data_length};
496 $self->{metalength} = hex $attr->{meta_data_length}; 600 $self->{metalength} = hex $attr->{metadata_length};
601}
602
603sub rcv_route_not_found {
604 my ($self, $attr, $type) = @_;
605
606 $self->throw (new Net::FCP::Exception $type, $attr);
607}
608
609sub rcv_data_not_found {
610 my ($self, $attr, $type) = @_;
611
612 $self->throw (new Net::FCP::Exception $type, $attr);
613}
614
615sub rcv_format_error {
616 my ($self, $attr, $type) = @_;
617
618 $self->throw (new Net::FCP::Exception $type, $attr);
619}
620
621sub rcv_restarted {
622 my ($self, $attr, $type) = @_;
623 $self->progress ($type, $attr);
497} 624}
498 625
499sub eof { 626sub eof {
500 my ($self) = @_; 627 my ($self) = @_;
501 #use PApp::Util; warn PApp::Util::dumpval $self; 628
502 my $data = delete $self->{data}; 629 my $data = delete $self->{data};
630 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, "";
631
503 $self->set_result ([ 632 $self->set_result ([$meta, $data]);
504 (substr $data, 0, $self->{datalength}-$self->{metalength}), 633}
505 (substr $data, $self->{datalength}-$self->{metalength}), 634
506 ]); 635package Net::FCP::Exception;
636
637use overload
638 '""' => sub {
639 "Net::FCP::Exception<<$_[0][0]," . (join ":", %{$_[0][1]}) . ">>\n";
640 };
641
642sub new {
643 my ($class, $type, $attr) = @_;
644
645 bless [$type, { %$attr }], $class;
507} 646}
508 647
509=back 648=back
510 649
511=head1 SEE ALSO 650=head1 SEE ALSO

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines