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.19 by root, Sun Sep 14 09:48:01 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.08;
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) {
165 print STDERR "metadata format error ($1), please report this string: <<$data>>";
141 die "metadata format error ($1)"; 166 die "metadata format error";
142 } 167 }
143 } 168 }
144 } 169 }
145 170
146 #$meta->{tail} = substr $data, pos $data; 171 #$meta->{tail} = substr $data, pos $data;
152 177
153Create a new virtual FCP connection to the given host and port (default 178Create 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>). 179127.0.0.1:8481, or the environment variables C<FREDHOST> and C<FREDPORT>).
155 180
156Connections are virtual because no persistent physical connection is 181Connections are virtual because no persistent physical connection is
182established.
183
184=begin comment
185
157established. However, the existance of the node is checked by executing a 186However, the existance of the node is checked by executing a
158C<ClientHello> transaction. 187C<ClientHello> transaction.
188
189=end
159 190
160=cut 191=cut
161 192
162sub new { 193sub new {
163 my $class = shift; 194 my $class = shift;
172 $self; 203 $self;
173} 204}
174 205
175sub progress { 206sub progress {
176 my ($self, $txn, $type, $attr) = @_; 207 my ($self, $txn, $type, $attr) = @_;
177 warn "progress<$txn,$type," . (join ":", %$attr) . ">\n"; 208 #warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
178} 209}
179 210
180=item $txn = $fcp->txn(type => attr => val,...) 211=item $txn = $fcp->txn(type => attr => val,...)
181 212
182The low-level interface to transactions. Don't use it. 213The low-level interface to transactions. Don't use it.
213 my $txn = "Net::FCP::Txn::$type"->new(fcp => $self, type => tolc $type, attr => \%attr); 244 my $txn = "Net::FCP::Txn::$type"->new(fcp => $self, type => tolc $type, attr => \%attr);
214 245
215 $txn; 246 $txn;
216} 247}
217 248
218sub _txn($&) { 249{ # transactions
250
251my $txn = sub {
219 my ($name, $sub) = @_; 252 my ($name, $sub) = @_;
220 *{"$name\_txn"} = $sub; 253 *{"txn_$name"} = $sub;
221 *{$name} = sub { $sub->(@_)->result }; 254 *{$name} = sub { $sub->(@_)->result };
222} 255};
223 256
224=item $txn = $fcp->txn_client_hello 257=item $txn = $fcp->txn_client_hello
225 258
226=item $nodehello = $fcp->client_hello 259=item $nodehello = $fcp->client_hello
227 260
233 protocol => "1.2", 266 protocol => "1.2",
234 } 267 }
235 268
236=cut 269=cut
237 270
238_txn client_hello => sub { 271$txn->(client_hello => sub {
239 my ($self) = @_; 272 my ($self) = @_;
240 273
241 $self->txn ("client_hello"); 274 $self->txn ("client_hello");
242}; 275});
243 276
244=item $txn = $fcp->txn_client_info 277=item $txn = $fcp->txn_client_info
245 278
246=item $nodeinfo = $fcp->client_info 279=item $nodeinfo = $fcp->client_info
247 280
271 routing_time => "a5", 304 routing_time => "a5",
272 } 305 }
273 306
274=cut 307=cut
275 308
276_txn client_info => sub { 309$txn->(client_info => sub {
277 my ($self) = @_; 310 my ($self) = @_;
278 311
279 $self->txn ("client_info"); 312 $self->txn ("client_info");
280}; 313});
281 314
282=item $txn = $fcp->txn_generate_chk ($metadata, $data) 315=item $txn = $fcp->txn_generate_chk ($metadata, $data)
283 316
284=item $uri = $fcp->generate_chk ($metadata, $data) 317=item $uri = $fcp->generate_chk ($metadata, $data)
285 318
286Creates a new CHK, given the metadata and data. UNTESTED. 319Creates a new CHK, given the metadata and data. UNTESTED.
287 320
288=cut 321=cut
289 322
290_txn generate_chk => sub { 323$txn->(generate_chk => sub {
291 my ($self, $metadata, $data) = @_; 324 my ($self, $metadata, $data) = @_;
292 325
293 $self->txn (generate_chk => data => "$data$metadata", metadata_length => length $metadata); 326 $self->txn (generate_chk => data => "$metadata$data", metadata_length => length $metadata);
294}; 327});
295 328
296=item $txn = $fcp->txn_generate_svk_pair 329=item $txn = $fcp->txn_generate_svk_pair
297 330
298=item ($public, $private) = @{ $fcp->generate_svk_pair } 331=item ($public, $private) = @{ $fcp->generate_svk_pair }
299 332
304 "ZnmvMITaTXBMFGl4~jrjuyWxOWg" 337 "ZnmvMITaTXBMFGl4~jrjuyWxOWg"
305 ] 338 ]
306 339
307=cut 340=cut
308 341
309_txn generate_svk_pair => sub { 342$txn->(generate_svk_pair => sub {
310 my ($self) = @_; 343 my ($self) = @_;
311 344
312 $self->txn ("generate_svk_pair"); 345 $self->txn ("generate_svk_pair");
313}; 346});
314 347
315=item $txn = $fcp->txn_insert_private_key ($private) 348=item $txn = $fcp->txn_insert_private_key ($private)
316 349
317=item $uri = $fcp->insert_private_key ($private) 350=item $public = $fcp->insert_private_key ($private)
318 351
319Inserts a private key. $private can be either an insert URI (must start 352Inserts 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 353with C<freenet:SSK@>) or a raw private key (i.e. the private value you get
321from C<generate_svk_pair>). 354back from C<generate_svk_pair>).
322 355
323Returns the public key. 356Returns the public key.
324 357
325UNTESTED. 358UNTESTED.
326 359
327=cut 360=cut
328 361
329_txn insert_private_key => sub { 362$txn->(insert_private_key => sub {
330 my ($self, $privkey) = @_; 363 my ($self, $privkey) = @_;
331 364
332 $self->txn (invert_private_key => private => $privkey); 365 $self->txn (invert_private_key => private => $privkey);
333}; 366});
334 367
335=item $txn = $fcp->txn_get_size ($uri) 368=item $txn = $fcp->txn_get_size ($uri)
336 369
337=item $length = $fcp->get_size ($uri) 370=item $length = $fcp->get_size ($uri)
338 371
341 374
342UNTESTED. 375UNTESTED.
343 376
344=cut 377=cut
345 378
346_txn get_size => sub { 379$txn->(get_size => sub {
347 my ($self, $uri) = @_; 380 my ($self, $uri) = @_;
348 381
349 $self->txn (get_size => URI => $uri); 382 $self->txn (get_size => URI => $uri);
350}; 383});
351 384
352=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]]) 385=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]])
353 386
354=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal) 387=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal)
355 388
365 ) 398 )
366 }; 399 };
367 400
368=cut 401=cut
369 402
370_txn client_get => sub { 403$txn->(client_get => sub {
371 my ($self, $uri, $htl, $removelocal) = @_; 404 my ($self, $uri, $htl, $removelocal) = @_;
372 405
373 $self->txn (client_get => URI => $uri, hops_to_live => ($htl || 15), remove_local_key => $removelocal ? "true" : "false"); 406 $self->txn (client_get => URI => $uri, hops_to_live => (defined $htl ? $htl :15),
407 remove_local_key => $removelocal ? "true" : "false");
374}; 408});
375 409
410=item $txn = $fcp->txn_client_put ($uri, $metadata, $data, $htl, $removelocal)
411
412=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal);
413
414Insert a new key. If the client is inserting a CHK, the URI may be
415abbreviated as just CHK@. In this case, the node will calculate the
416CHK.
417
418C<$meta> can be a reference or a string (ONLY THE STRING CASE IS IMPLEMENTED!).
419
420THIS INTERFACE IS UNTESTED AND SUBJECT TO CHANGE.
421
422=cut
423
424$txn->(client_put => sub {
425 my ($self, $uri, $meta, $data, $htl, $removelocal) = @_;
426
427 $self->txn (client_put => URI => $uri, hops_to_live => (defined $htl ? $htl :15),
428 remove_local_key => $removelocal ? "true" : "false",
429 data => "$meta$data", metadata_length => length $meta);
430});
431
432} # transactions
433
376=item MISSING: ClientPut 434=item MISSING: (ClientPut), InsretKey
377 435
378=back 436=back
379 437
380=head2 THE Net::FCP::Txn CLASS 438=head2 THE Net::FCP::Txn CLASS
381 439
483 541
484sub userdata($$) { 542sub userdata($$) {
485 my ($self, $data) = @_; 543 my ($self, $data) = @_;
486 $self->{userdata} = $data; 544 $self->{userdata} = $data;
487 $self; 545 $self;
546}
547
548=item $txn->cancel (%attr)
549
550Cancels the operation with a C<cancel> exception anf the given attributes
551(consider at least giving the attribute C<reason>).
552
553UNTESTED.
554
555=cut
556
557sub cancel {
558 my ($self, %attr) = @_;
559 $self->throw (Net::FCP::Exception->new (cancel => { %attr }));
560 $self->set_result;
561 $self->eof;
488} 562}
489 563
490sub fh_ready_w { 564sub fh_ready_w {
491 my ($self) = @_; 565 my ($self) = @_;
492 566
532 } else { 606 } else {
533 $self->eof; 607 $self->eof;
534 } 608 }
535} 609}
536 610
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 { 611sub rcv {
546 my ($self, $type, $attr) = @_; 612 my ($self, $type, $attr) = @_;
547 613
548 $type = Net::FCP::tolc $type; 614 $type = Net::FCP::tolc $type;
549 615
557} 623}
558 624
559# used as a default exception thrower 625# used as a default exception thrower
560sub rcv_throw_exception { 626sub rcv_throw_exception {
561 my ($self, $attr, $type) = @_; 627 my ($self, $attr, $type) = @_;
562 $self->throw (new Net::FCP::Exception $type, $attr); 628 $self->throw (Net::FCP::Exception->new ($type, $attr));
563} 629}
564 630
565*rcv_failed = \&Net::FCP::Txn::rcv_throw_exception; 631*rcv_failed = \&Net::FCP::Txn::rcv_throw_exception;
566*rcv_format_error = \&Net::FCP::Txn::rcv_throw_exception; 632*rcv_format_error = \&Net::FCP::Txn::rcv_throw_exception;
567 633
568sub throw { 634sub throw {
569 my ($self, $exc) = @_; 635 my ($self, $exc) = @_;
570 636
571 $self->{exception} = $exc; 637 $self->{exception} = $exc;
572 $self->set_result (1); 638 $self->set_result;
573 $self->eof; # must be last to avoid loops 639 $self->eof; # must be last to avoid loops
574} 640}
575 641
576sub set_result { 642sub set_result {
577 my ($self, $result) = @_; 643 my ($self, $result) = @_;
589 delete $self->{w}; 655 delete $self->{w};
590 delete $self->{fh}; 656 delete $self->{fh};
591 657
592 delete $self->{fcp}{txn}{$self}; 658 delete $self->{fcp}{txn}{$self};
593 659
594 $self->set_result; # just in case 660 unless (exists $self->{result}) {
661 $self->throw (Net::FCP::Exception->new (short_data => {
662 reason => "unexpected eof or internal node error",
663 }));
664 }
595} 665}
596 666
597sub progress { 667sub progress {
598 my ($self, $type, $attr) = @_; 668 my ($self, $type, $attr) = @_;
599 $self->{fcp}->progress ($self, $type, $attr); 669 $self->{fcp}->progress ($self, $type, $attr);
652 722
653use base Net::FCP::Txn; 723use base Net::FCP::Txn;
654 724
655sub rcv_success { 725sub rcv_success {
656 my ($self, $attr) = @_; 726 my ($self, $attr) = @_;
657
658 $self->set_result ([$attr->{PublicKey}, $attr->{PrivateKey}]); 727 $self->set_result ([$attr->{PublicKey}, $attr->{PrivateKey}]);
659} 728}
660 729
661package Net::FCP::Txn::InvertPrivateKey; 730package Net::FCP::Txn::InsertPrivateKey;
662 731
663use base Net::FCP::Txn; 732use base Net::FCP::Txn;
664 733
665sub rcv_success { 734sub rcv_success {
666 my ($self, $attr) = @_; 735 my ($self, $attr) = @_;
667
668 $self->set_result ($attr->{PublicKey}); 736 $self->set_result ($attr->{PublicKey});
669} 737}
670 738
671package Net::FCP::Txn::GetSize; 739package Net::FCP::Txn::GetSize;
672 740
673use base Net::FCP::Txn; 741use base Net::FCP::Txn;
674 742
675sub rcv_success { 743sub rcv_success {
676 my ($self, $attr) = @_; 744 my ($self, $attr) = @_;
677
678 $self->set_result ($attr->{Length}); 745 $self->set_result ($attr->{Length});
679} 746}
680 747
681package Net::FCP::Txn::GetPut; 748package Net::FCP::Txn::GetPut;
682 749
701 768
702use base Net::FCP::Txn::GetPut; 769use base Net::FCP::Txn::GetPut;
703 770
704*rcv_data_not_found = \&Net::FCP::Txn::rcv_throw_exception; 771*rcv_data_not_found = \&Net::FCP::Txn::rcv_throw_exception;
705 772
706sub rcv_data_found { 773sub 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) = @_; 774 my ($self, $chunk) = @_;
775
776 $self->{data} .= $chunk;
777
778 $self->progress ("data", { chunk => length $chunk, received => length $self->{data}, total => $self->{datalength} });
717 779
718 if ($self->{datalength} == length $self->{data}) { 780 if ($self->{datalength} == length $self->{data}) {
719 my $data = delete $self->{data}; 781 my $data = delete $self->{data};
720 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, ""; 782 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, "";
721 783
722 $self->set_result ([$meta, $data]); 784 $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 } 785 }
786}
787
788sub rcv_data_found {
789 my ($self, $attr, $type) = @_;
790
791 $self->progress ($type, $attr);
792
793 $self->{datalength} = hex $attr->{data_length};
794 $self->{metalength} = hex $attr->{metadata_length};
730} 795}
731 796
732package Net::FCP::Txn::ClientPut; 797package Net::FCP::Txn::ClientPut;
733 798
734use base Net::FCP::Txn::GetPut; 799use base Net::FCP::Txn::GetPut;
743 808
744sub rcv_success { 809sub rcv_success {
745 my ($self, $attr, $type) = @_; 810 my ($self, $attr, $type) = @_;
746 $self->set_result ($attr); 811 $self->set_result ($attr);
747} 812}
813
814=back
815
816=head2 The Net::FCP::Exception CLASS
817
818Any unexpected (non-standard) responses that make it impossible to return
819the advertised result will result in an exception being thrown when the
820C<result> method is called.
821
822These exceptions are represented by objects of this class.
823
824=over 4
825
826=cut
748 827
749package Net::FCP::Exception; 828package Net::FCP::Exception;
750 829
751use overload 830use overload
752 '""' => sub { 831 '""' => sub {
753 "Net::FCP::Exception<<$_[0][0]," . (join ":", %{$_[0][1]}) . ">>\n"; 832 "Net::FCP::Exception<<$_[0][0]," . (join ":", %{$_[0][1]}) . ">>\n";
754 }; 833 };
755 834
835=item $exc = new Net::FCP::Exception $type, \%attr
836
837Create a new exception object of the given type (a string like
838C<route_not_found>), and a hashref containing additional attributes
839(usually the attributes of the message causing the exception).
840
841=cut
842
756sub new { 843sub new {
757 my ($class, $type, $attr) = @_; 844 my ($class, $type, $attr) = @_;
758 845
759 bless [Net::FCP::tolc $type, { %$attr }], $class; 846 bless [Net::FCP::tolc $type, { %$attr }], $class;
760} 847}
761 848
849=item $exc->type([$type])
850
851With no arguments, returns the exception type. Otherwise a boolean
852indicating wether the exception is of the given type is returned.
853
854=cut
855
856sub type {
857 my ($self, $type) = @_;
858
859 @_ >= 2
860 ? $self->[0] eq $type
861 : $self->[0];
862}
863
864=item $exc->attr([$attr])
865
866With no arguments, returns the attributes. Otherwise the named attribute
867value is returned.
868
869=cut
870
871sub attr {
872 my ($self, $attr) = @_;
873
874 @_ >= 2
875 ? $self->[1]{$attr}
876 : $self->[1];
877}
878
762=back 879=back
763 880
764=head1 SEE ALSO 881=head1 SEE ALSO
765 882
766L<http://freenet.sf.net>. 883L<http://freenet.sf.net>.

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines