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

Comparing Net-FCP/FCP.pm (file contents):
Revision 1.13 by root, Wed Sep 10 05:06:16 2003 UTC vs.
Revision 1.17 by root, Fri Sep 12 03:28:45 2003 UTC

35The import tag to use is named C<event=xyz>, e.g. C<event=Event>, 35The import tag to use is named C<event=xyz>, e.g. C<event=Event>,
36C<event=Glib> etc. 36C<event=Glib> etc.
37 37
38You should specify the event module to use only in the main program. 38You should specify the event module to use only in the main program.
39 39
40=head2 FREENET BASICS
41
42Ok, this section will not explain any freenet basics to you, just some
43problems I found that you might want to avoid:
44
45=over 4
46
47=item freenet URIs are _NOT_ URIs
48
49Whenever a "uri" is required by the protocol, freenet expects a kind of
50URI prefixed with the "freenet:" scheme, e.g. "freenet:CHK...". However,
51these are not URIs, as freeent fails to parse them correctly, that is, you
52must unescape an escaped characters ("%2c" => ",") yourself. Maybe in the
53future this library will do it for you, so watch out for this incompatible
54change.
55
56=item Numbers are in HEX
57
58Virtually every number in the FCP protocol is in hex. Be sure to use
59C<hex()> on all such numbers, as the module (currently) does nothing to
60convert these for you.
61
62=back
63
40=head2 THE Net::FCP CLASS 64=head2 THE Net::FCP CLASS
41 65
42=over 4 66=over 4
43 67
44=cut 68=cut
45 69
46package Net::FCP; 70package Net::FCP;
47 71
48use Carp; 72use Carp;
49 73
50$VERSION = 0.05; 74$VERSION = 0.07;
51 75
52no warnings; 76no warnings;
53 77
54our $EVENT = Net::FCP::Event::Auto::; 78our $EVENT = Net::FCP::Event::Auto::;
55$EVENT = Net::FCP::Event::Event;#d# 79$EVENT = Net::FCP::Event::Event;#d#
93 117
94 ( 118 (
95 version => { revision => 1 }, 119 version => { revision => 1 },
96 document => [ 120 document => [
97 { 121 {
98 "info.format" => "image/jpeg", 122 info => { format" => "image/jpeg" },
99 name => "background.jpg", 123 name => "background.jpg",
100 "redirect.target" => "freenet:CHK\@ZcagI,ra726bSw" 124 redirect => { target => "freenet:CHK\@ZcagI,ra726bSw" },
101 }, 125 },
102 { 126 {
103 "info.format" => "text/html", 127 info => { format" => "text/html" },
104 name => ".next", 128 name => ".next",
105 "redirect.target" => "freenet:SSK\@ilUPAgM/TFEE/3" 129 redirect => { target => "freenet:SSK\@ilUPAgM/TFEE/3" },
106 }, 130 },
107 { 131 {
108 "info.format" => "text/html", 132 info => { format" => "text/html" },
109 "redirect.target" => "freenet:CHK\@8M8Po8ucwI,8xA" 133 redirect => { target => "freenet:CHK\@8M8Po8ucwI,8xA" },
110 } 134 }
111 ] 135 ]
112 ) 136 )
113 137
114=cut 138=cut
125 my ($k, $v) = ($1, $2); 149 my ($k, $v) = ($1, $2);
126 my @p = split /\./, tolc $k, 3; 150 my @p = split /\./, tolc $k, 3;
127 151
128 $hdr->{$p[0]} = $v if @p == 1; # lamest code I ever wrote 152 $hdr->{$p[0]} = $v if @p == 1; # lamest code I ever wrote
129 $hdr->{$p[0]}{$p[1]} = $v if @p == 2; 153 $hdr->{$p[0]}{$p[1]} = $v if @p == 2;
130 $hdr->{$p[0]}{$p[1]}{$p[3]} = $v if @p == 3; 154 $hdr->{$p[0]}{$p[1]}{$p[2]} = $v if @p == 3;
131 die "FATAL: 4+ dot metadata" if @p >= 4; 155 die "FATAL: 4+ dot metadata" if @p >= 4;
132 } 156 }
133 157
134 if ($data =~ /\GEndPart\015?\012/gc) { 158 if ($data =~ /\GEndPart\015?\012/gc) {
135 # nop 159 # nop
136 } elsif ($data =~ /\GEnd\015?\012/gc) { 160 } elsif ($data =~ /\GEnd(\015?\012|$)/gc) {
137 last; 161 last;
138 } elsif ($data =~ /\G([A-Za-z0-9.\-]+)\015?\012/gcs) { 162 } elsif ($data =~ /\G([A-Za-z0-9.\-]+)\015?\012/gcs) {
139 push @{$meta->{tolc $1}}, $hdr = {}; 163 push @{$meta->{tolc $1}}, $hdr = {};
140 } elsif ($data =~ /\G(.*)/gcs) { 164 } elsif ($data =~ /\G(.*)/gcs) {
141 die "metadata format error ($1)"; 165 die "metadata format error ($1), please report this string: <<$data>>";
142 } 166 }
143 } 167 }
144 } 168 }
145 169
146 #$meta->{tail} = substr $data, pos $data; 170 #$meta->{tail} = substr $data, pos $data;
152 176
153Create a new virtual FCP connection to the given host and port (default 177Create a new virtual FCP connection to the given host and port (default
154127.0.0.1:8481, or the environment variables C<FREDHOST> and C<FREDPORT>). 178127.0.0.1:8481, or the environment variables C<FREDHOST> and C<FREDPORT>).
155 179
156Connections are virtual because no persistent physical connection is 180Connections are virtual because no persistent physical connection is
181established.
182
183=begin comment
184
157established. However, the existance of the node is checked by executing a 185However, the existance of the node is checked by executing a
158C<ClientHello> transaction. 186C<ClientHello> transaction.
187
188=end
159 189
160=cut 190=cut
161 191
162sub new { 192sub new {
163 my $class = shift; 193 my $class = shift;
213 my $txn = "Net::FCP::Txn::$type"->new(fcp => $self, type => tolc $type, attr => \%attr); 243 my $txn = "Net::FCP::Txn::$type"->new(fcp => $self, type => tolc $type, attr => \%attr);
214 244
215 $txn; 245 $txn;
216} 246}
217 247
218sub _txn($&) { 248{ # transactions
249
250my $txn = sub {
219 my ($name, $sub) = @_; 251 my ($name, $sub) = @_;
220 *{"$name\_txn"} = $sub; 252 *{"txn_$name"} = $sub;
221 *{$name} = sub { $sub->(@_)->result }; 253 *{$name} = sub { $sub->(@_)->result };
222} 254};
223 255
224=item $txn = $fcp->txn_client_hello 256=item $txn = $fcp->txn_client_hello
225 257
226=item $nodehello = $fcp->client_hello 258=item $nodehello = $fcp->client_hello
227 259
233 protocol => "1.2", 265 protocol => "1.2",
234 } 266 }
235 267
236=cut 268=cut
237 269
238_txn client_hello => sub { 270$txn->(client_hello => sub {
239 my ($self) = @_; 271 my ($self) = @_;
240 272
241 $self->txn ("client_hello"); 273 $self->txn ("client_hello");
242}; 274});
243 275
244=item $txn = $fcp->txn_client_info 276=item $txn = $fcp->txn_client_info
245 277
246=item $nodeinfo = $fcp->client_info 278=item $nodeinfo = $fcp->client_info
247 279
271 routing_time => "a5", 303 routing_time => "a5",
272 } 304 }
273 305
274=cut 306=cut
275 307
276_txn client_info => sub { 308$txn->(client_info => sub {
277 my ($self) = @_; 309 my ($self) = @_;
278 310
279 $self->txn ("client_info"); 311 $self->txn ("client_info");
280}; 312});
281 313
282=item $txn = $fcp->txn_generate_chk ($metadata, $data) 314=item $txn = $fcp->txn_generate_chk ($metadata, $data)
283 315
284=item $uri = $fcp->generate_chk ($metadata, $data) 316=item $uri = $fcp->generate_chk ($metadata, $data)
285 317
286Creates a new CHK, given the metadata and data. UNTESTED. 318Creates a new CHK, given the metadata and data. UNTESTED.
287 319
288=cut 320=cut
289 321
290_txn generate_chk => sub { 322$txn->(generate_chk => sub {
291 my ($self, $metadata, $data) = @_; 323 my ($self, $metadata, $data) = @_;
292 324
293 $self->txn (generate_chk => data => "$data$metadata", metadata_length => length $metadata); 325 $self->txn (generate_chk => data => "$metadata$data", metadata_length => length $metadata);
294}; 326});
295 327
296=item $txn = $fcp->txn_generate_svk_pair 328=item $txn = $fcp->txn_generate_svk_pair
297 329
298=item ($public, $private) = @{ $fcp->generate_svk_pair } 330=item ($public, $private) = @{ $fcp->generate_svk_pair }
299 331
304 "ZnmvMITaTXBMFGl4~jrjuyWxOWg" 336 "ZnmvMITaTXBMFGl4~jrjuyWxOWg"
305 ] 337 ]
306 338
307=cut 339=cut
308 340
309_txn generate_svk_pair => sub { 341$txn->(generate_svk_pair => sub {
310 my ($self) = @_; 342 my ($self) = @_;
311 343
312 $self->txn ("generate_svk_pair"); 344 $self->txn ("generate_svk_pair");
313}; 345});
314 346
315=item $txn = $fcp->txn_insert_private_key ($private) 347=item $txn = $fcp->txn_insert_private_key ($private)
316 348
317=item $uri = $fcp->insert_private_key ($private) 349=item $public = $fcp->insert_private_key ($private)
318 350
319Inserts a private key. $private can be either an insert URI (must start 351Inserts a private key. $private can be either an insert URI (must start
320with freenet:SSK@) or a raw private key (i.e. the private value you get back 352with C<freenet:SSK@>) or a raw private key (i.e. the private value you get
321from C<generate_svk_pair>). 353back from C<generate_svk_pair>).
322 354
323Returns the public key. 355Returns the public key.
324 356
325UNTESTED. 357UNTESTED.
326 358
327=cut 359=cut
328 360
329_txn insert_private_key => sub { 361$txn->(insert_private_key => sub {
330 my ($self, $privkey) = @_; 362 my ($self, $privkey) = @_;
331 363
332 $self->txn (invert_private_key => private => $privkey); 364 $self->txn (invert_private_key => private => $privkey);
333}; 365});
334 366
335=item $txn = $fcp->txn_get_size ($uri) 367=item $txn = $fcp->txn_get_size ($uri)
336 368
337=item $length = $fcp->get_size ($uri) 369=item $length = $fcp->get_size ($uri)
338 370
341 373
342UNTESTED. 374UNTESTED.
343 375
344=cut 376=cut
345 377
346_txn get_size => sub { 378$txn->(get_size => sub {
347 my ($self, $uri) = @_; 379 my ($self, $uri) = @_;
348 380
349 $self->txn (get_size => URI => $uri); 381 $self->txn (get_size => URI => $uri);
350}; 382});
351 383
352=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]]) 384=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]])
353 385
354=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal) 386=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal)
355 387
365 ) 397 )
366 }; 398 };
367 399
368=cut 400=cut
369 401
370_txn client_get => sub { 402$txn->(client_get => sub {
371 my ($self, $uri, $htl, $removelocal) = @_; 403 my ($self, $uri, $htl, $removelocal) = @_;
372 404
373 $self->txn (client_get => URI => $uri, hops_to_live => ($htl || 15), remove_local_key => $removelocal ? "true" : "false"); 405 $self->txn (client_get => URI => $uri, hops_to_live => (defined $htl ? $htl :15),
406 remove_local_key => $removelocal ? "true" : "false");
374}; 407});
375 408
409=item $txn = $fcp->txn_client_put ($uri, $metadata, $data, $htl, $removelocal)
410
411=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal);
412
413Insert a new key. If the client is inserting a CHK, the URI may be
414abbreviated as just CHK@. In this case, the node will calculate the
415CHK.
416
417C<$meta> can be a reference or a string (ONLY THE STRING CASE IS IMPLEMENTED!).
418
419THIS INTERFACE IS UNTESTED AND SUBJECT TO CHANGE.
420
421=cut
422
423$txn->(client_put => sub {
424 my ($self, $uri, $meta, $data, $htl, $removelocal) = @_;
425
426 $self->txn (client_put => URI => $uri, hops_to_live => (defined $htl ? $htl :15),
427 remove_local_key => $removelocal ? "true" : "false",
428 data => "$meta$data", metadata_length => length $meta);
429});
430
431} # transactions
432
376=item MISSING: ClientPut 433=item MISSING: (ClientPut), InsretKey
377 434
378=back 435=back
379 436
380=head2 THE Net::FCP::Txn CLASS 437=head2 THE Net::FCP::Txn CLASS
381 438
483 540
484sub userdata($$) { 541sub userdata($$) {
485 my ($self, $data) = @_; 542 my ($self, $data) = @_;
486 $self->{userdata} = $data; 543 $self->{userdata} = $data;
487 $self; 544 $self;
545}
546
547=item $txn->cancel (%attr)
548
549Cancels the operation with a C<cancel> exception anf the given attributes
550(consider at least giving the attribute C<reason>).
551
552UNTESTED.
553
554=cut
555
556sub cancel {
557 my ($self, %attr) = @_;
558 $self->throw (Net::FCP::Exception->new (cancel => { %attr }));
559 $self->set_result;
560 $self->eof;
488} 561}
489 562
490sub fh_ready_w { 563sub fh_ready_w {
491 my ($self) = @_; 564 my ($self) = @_;
492 565
532 } else { 605 } else {
533 $self->eof; 606 $self->eof;
534 } 607 }
535} 608}
536 609
537sub rcv_data {
538 my ($self, $chunk) = @_;
539
540 $self->{data} .= $chunk;
541
542 $self->progress ("data", { chunk => length $chunk, total => length $self->{data}, end => $self->{datalength} });
543}
544
545sub rcv { 610sub rcv {
546 my ($self, $type, $attr) = @_; 611 my ($self, $type, $attr) = @_;
547 612
548 $type = Net::FCP::tolc $type; 613 $type = Net::FCP::tolc $type;
549 614
557} 622}
558 623
559# used as a default exception thrower 624# used as a default exception thrower
560sub rcv_throw_exception { 625sub rcv_throw_exception {
561 my ($self, $attr, $type) = @_; 626 my ($self, $attr, $type) = @_;
562 $self->throw (new Net::FCP::Exception $type, $attr); 627 $self->throw (Net::FCP::Exception->new ($type, $attr));
563} 628}
564 629
565*rcv_failed = \&Net::FCP::Txn::rcv_throw_exception; 630*rcv_failed = \&Net::FCP::Txn::rcv_throw_exception;
566*rcv_format_error = \&Net::FCP::Txn::rcv_throw_exception; 631*rcv_format_error = \&Net::FCP::Txn::rcv_throw_exception;
567 632
568sub throw { 633sub throw {
569 my ($self, $exc) = @_; 634 my ($self, $exc) = @_;
570 635
571 $self->{exception} = $exc; 636 $self->{exception} = $exc;
572 $self->set_result (1); 637 $self->set_result;
573 $self->eof; # must be last to avoid loops 638 $self->eof; # must be last to avoid loops
574} 639}
575 640
576sub set_result { 641sub set_result {
577 my ($self, $result) = @_; 642 my ($self, $result) = @_;
589 delete $self->{w}; 654 delete $self->{w};
590 delete $self->{fh}; 655 delete $self->{fh};
591 656
592 delete $self->{fcp}{txn}{$self}; 657 delete $self->{fcp}{txn}{$self};
593 658
594 $self->set_result; # just in case 659 unless (exists $self->{result}) {
660 $self->throw (Net::FCP::Exception->new (short_data => {
661 reason => "unexpected eof or internal node error",
662 }));
663 }
595} 664}
596 665
597sub progress { 666sub progress {
598 my ($self, $type, $attr) = @_; 667 my ($self, $type, $attr) = @_;
599 $self->{fcp}->progress ($self, $type, $attr); 668 $self->{fcp}->progress ($self, $type, $attr);
652 721
653use base Net::FCP::Txn; 722use base Net::FCP::Txn;
654 723
655sub rcv_success { 724sub rcv_success {
656 my ($self, $attr) = @_; 725 my ($self, $attr) = @_;
657
658 $self->set_result ([$attr->{PublicKey}, $attr->{PrivateKey}]); 726 $self->set_result ([$attr->{PublicKey}, $attr->{PrivateKey}]);
659} 727}
660 728
661package Net::FCP::Txn::InvertPrivateKey; 729package Net::FCP::Txn::InsertPrivateKey;
662 730
663use base Net::FCP::Txn; 731use base Net::FCP::Txn;
664 732
665sub rcv_success { 733sub rcv_success {
666 my ($self, $attr) = @_; 734 my ($self, $attr) = @_;
667
668 $self->set_result ($attr->{PublicKey}); 735 $self->set_result ($attr->{PublicKey});
669} 736}
670 737
671package Net::FCP::Txn::GetSize; 738package Net::FCP::Txn::GetSize;
672 739
673use base Net::FCP::Txn; 740use base Net::FCP::Txn;
674 741
675sub rcv_success { 742sub rcv_success {
676 my ($self, $attr) = @_; 743 my ($self, $attr) = @_;
677
678 $self->set_result ($attr->{Length}); 744 $self->set_result ($attr->{Length});
679} 745}
680 746
681package Net::FCP::Txn::GetPut; 747package Net::FCP::Txn::GetPut;
682 748
701 767
702use base Net::FCP::Txn::GetPut; 768use base Net::FCP::Txn::GetPut;
703 769
704*rcv_data_not_found = \&Net::FCP::Txn::rcv_throw_exception; 770*rcv_data_not_found = \&Net::FCP::Txn::rcv_throw_exception;
705 771
706sub rcv_data_found { 772sub rcv_data {
707 my ($self, $attr, $type) = @_;
708
709 $self->progress ($type, $attr);
710
711 $self->{datalength} = hex $attr->{data_length};
712 $self->{metalength} = hex $attr->{metadata_length};
713}
714
715sub eof {
716 my ($self) = @_; 773 my ($self, $chunk) = @_;
774
775 $self->{data} .= $chunk;
776
777 $self->progress ("data", { chunk => length $chunk, total => length $self->{data}, end => $self->{datalength} });
717 778
718 if ($self->{datalength} == length $self->{data}) { 779 if ($self->{datalength} == length $self->{data}) {
719 my $data = delete $self->{data}; 780 my $data = delete $self->{data};
720 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, ""; 781 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, "";
721 782
722 $self->set_result ([$meta, $data]); 783 $self->set_result ([$meta, $data]);
723 } elsif (!exists $self->{result}) {
724 $self->throw (Net::FCP::Exception->new (short_data => {
725 reason => "unexpected eof or internal node error",
726 received => length $self->{data},
727 expected => $self->{datalength},
728 }));
729 } 784 }
785}
786
787sub rcv_data_found {
788 my ($self, $attr, $type) = @_;
789
790 $self->progress ($type, $attr);
791
792 $self->{datalength} = hex $attr->{data_length};
793 $self->{metalength} = hex $attr->{metadata_length};
730} 794}
731 795
732package Net::FCP::Txn::ClientPut; 796package Net::FCP::Txn::ClientPut;
733 797
734use base Net::FCP::Txn::GetPut; 798use base Net::FCP::Txn::GetPut;
743 807
744sub rcv_success { 808sub rcv_success {
745 my ($self, $attr, $type) = @_; 809 my ($self, $attr, $type) = @_;
746 $self->set_result ($attr); 810 $self->set_result ($attr);
747} 811}
812
813=back
814
815=head2 The Net::FCP::Exception CLASS
816
817Any unexpected (non-standard) responses that make it impossible to return
818the advertised result will result in an exception being thrown when the
819C<result> method is called.
820
821These exceptions are represented by objects of this class.
822
823=over 4
824
825=cut
748 826
749package Net::FCP::Exception; 827package Net::FCP::Exception;
750 828
751use overload 829use overload
752 '""' => sub { 830 '""' => sub {
753 "Net::FCP::Exception<<$_[0][0]," . (join ":", %{$_[0][1]}) . ">>\n"; 831 "Net::FCP::Exception<<$_[0][0]," . (join ":", %{$_[0][1]}) . ">>\n";
754 }; 832 };
755 833
834=item $exc = new Net::FCP::Exception $type, \%attr
835
836Create a new exception object of the given type (a string like
837C<route_not_found>), and a hashref containing additional attributes
838(usually the attributes of the message causing the exception).
839
840=cut
841
756sub new { 842sub new {
757 my ($class, $type, $attr) = @_; 843 my ($class, $type, $attr) = @_;
758 844
759 bless [Net::FCP::tolc $type, { %$attr }], $class; 845 bless [Net::FCP::tolc $type, { %$attr }], $class;
760} 846}
761 847
848=item $exc->type([$type])
849
850With no arguments, returns the exception type. Otherwise a boolean
851indicating wether the exception is of the given type is returned.
852
853=cut
854
855sub type {
856 my ($self, $type) = @_;
857
858 @_ >= 2
859 ? $self->[0] eq $type
860 : $self->[0];
861}
862
863=item $exc->attr([$attr])
864
865With no arguments, returns the attributes. Otherwise the named attribute
866value is returned.
867
868=cut
869
870sub attr {
871 my ($self, $attr) = @_;
872
873 @_ >= 2
874 ? $self->[1]{$attr}
875 : $self->[1];
876}
877
762=back 878=back
763 879
764=head1 SEE ALSO 880=head1 SEE ALSO
765 881
766L<http://freenet.sf.net>. 882L<http://freenet.sf.net>.

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines