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.22 by root, Wed Sep 17 05:05:33 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
40If no event model has been specified, FCP tries to autodetect it on first
41use (e.g. first transaction), in this order: Coro, Event, Glib, Tk.
42
43=head2 FREENET BASICS
44
45Ok, this section will not explain any freenet basics to you, just some
46problems I found that you might want to avoid:
47
48=over 4
49
50=item freenet URIs are _NOT_ URIs
51
52Whenever a "uri" is required by the protocol, freenet expects a kind of
53URI prefixed with the "freenet:" scheme, e.g. "freenet:CHK...". However,
54these are not URIs, as freeent fails to parse them correctly, that is, you
55must unescape an escaped characters ("%2c" => ",") yourself. Maybe in the
56future this library will do it for you, so watch out for this incompatible
57change.
58
59=item Numbers are in HEX
60
61Virtually every number in the FCP protocol is in hex. Be sure to use
62C<hex()> on all such numbers, as the module (currently) does nothing to
63convert these for you.
64
65=back
66
40=head2 THE Net::FCP CLASS 67=head2 THE Net::FCP CLASS
41 68
42=over 4 69=over 4
43 70
44=cut 71=cut
45 72
46package Net::FCP; 73package Net::FCP;
47 74
48use Carp; 75use Carp;
49 76
50$VERSION = 0.05; 77$VERSION = 0.5;
51 78
52no warnings; 79no warnings;
53 80
54our $EVENT = Net::FCP::Event::Auto::; 81our $EVENT = Net::FCP::Event::Auto::;
55$EVENT = Net::FCP::Event::Event;#d#
56 82
57sub import { 83sub import {
58 shift; 84 shift;
59 85
60 for (@_) { 86 for (@_) {
61 if (/^event=(\w+)$/) { 87 if (/^event=(\w+)$/) {
62 $EVENT = "Net::FCP::Event::$1"; 88 $EVENT = "Net::FCP::Event::$1";
89 eval "require $EVENT";
63 } 90 }
64 } 91 }
65 eval "require $EVENT";
66 die $@ if $@; 92 die $@ if $@;
67} 93}
68 94
69sub touc($) { 95sub touc($) {
70 local $_ = shift; 96 local $_ = shift;
81 107
82=item $meta = Net::FCP::parse_metadata $string 108=item $meta = Net::FCP::parse_metadata $string
83 109
84Parse a metadata string and return it. 110Parse a metadata string and return it.
85 111
86The metadata will be a hashref with key C<version> (containing 112The metadata will be a hashref with key C<version> (containing the
87the mandatory version header entries). 113mandatory version header entries) and key C<raw> containing the original
114metadata string.
88 115
89All other headers are represented by arrayrefs (they can be repeated). 116All other headers are represented by arrayrefs (they can be repeated).
90 117
91Since this is confusing, here is a rather verbose example of a parsed 118Since this description is confusing, here is a rather verbose example of a
92manifest: 119parsed manifest:
93 120
94 ( 121 (
122 raw => "Version...",
95 version => { revision => 1 }, 123 version => { revision => 1 },
96 document => [ 124 document => [
97 { 125 {
98 "info.format" => "image/jpeg", 126 info => { format" => "image/jpeg" },
99 name => "background.jpg", 127 name => "background.jpg",
100 "redirect.target" => "freenet:CHK\@ZcagI,ra726bSw" 128 redirect => { target => "freenet:CHK\@ZcagI,ra726bSw" },
101 }, 129 },
102 { 130 {
103 "info.format" => "text/html", 131 info => { format" => "text/html" },
104 name => ".next", 132 name => ".next",
105 "redirect.target" => "freenet:SSK\@ilUPAgM/TFEE/3" 133 redirect => { target => "freenet:SSK\@ilUPAgM/TFEE/3" },
106 }, 134 },
107 { 135 {
108 "info.format" => "text/html", 136 info => { format" => "text/html" },
109 "redirect.target" => "freenet:CHK\@8M8Po8ucwI,8xA" 137 redirect => { target => "freenet:CHK\@8M8Po8ucwI,8xA" },
110 } 138 }
111 ] 139 ]
112 ) 140 )
113 141
114=cut 142=cut
115 143
116sub parse_metadata { 144sub parse_metadata {
117 my $meta;
118
119 my $data = shift; 145 my $data = shift;
146 my $meta = { raw => $data };
147
120 if ($data =~ /^Version\015?\012/gc) { 148 if ($data =~ /^Version\015?\012/gc) {
121 my $hdr = $meta->{version} = {}; 149 my $hdr = $meta->{version} = {};
122 150
123 for (;;) { 151 for (;;) {
124 while ($data =~ /\G([^=\015\012]+)=([^\015\012]*)\015?\012/gc) { 152 while ($data =~ /\G([^=\015\012]+)=([^\015\012]*)\015?\012/gc) {
125 my ($k, $v) = ($1, $2); 153 my ($k, $v) = ($1, $2);
126 my @p = split /\./, tolc $k, 3; 154 my @p = split /\./, tolc $k, 3;
127 155
128 $hdr->{$p[0]} = $v if @p == 1; # lamest code I ever wrote 156 $hdr->{$p[0]} = $v if @p == 1; # lamest code I ever wrote
129 $hdr->{$p[0]}{$p[1]} = $v if @p == 2; 157 $hdr->{$p[0]}{$p[1]} = $v if @p == 2;
130 $hdr->{$p[0]}{$p[1]}{$p[3]} = $v if @p == 3; 158 $hdr->{$p[0]}{$p[1]}{$p[2]} = $v if @p == 3;
131 die "FATAL: 4+ dot metadata" if @p >= 4; 159 die "FATAL: 4+ dot metadata" if @p >= 4;
132 } 160 }
133 161
134 if ($data =~ /\GEndPart\015?\012/gc) { 162 if ($data =~ /\GEndPart\015?\012/gc) {
135 # nop 163 # nop
136 } elsif ($data =~ /\GEnd\015?\012/gc) { 164 } elsif ($data =~ /\GEnd(\015?\012|$)/gc) {
137 last; 165 last;
138 } elsif ($data =~ /\G([A-Za-z0-9.\-]+)\015?\012/gcs) { 166 } elsif ($data =~ /\G([A-Za-z0-9.\-]+)\015?\012/gcs) {
139 push @{$meta->{tolc $1}}, $hdr = {}; 167 push @{$meta->{tolc $1}}, $hdr = {};
140 } elsif ($data =~ /\G(.*)/gcs) { 168 } elsif ($data =~ /\G(.*)/gcs) {
169 print STDERR "metadata format error ($1), please report this string: <<$data>>";
141 die "metadata format error ($1)"; 170 die "metadata format error";
142 } 171 }
143 } 172 }
144 } 173 }
145 174
146 #$meta->{tail} = substr $data, pos $data; 175 #$meta->{tail} = substr $data, pos $data;
152 181
153Create a new virtual FCP connection to the given host and port (default 182Create 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>). 183127.0.0.1:8481, or the environment variables C<FREDHOST> and C<FREDPORT>).
155 184
156Connections are virtual because no persistent physical connection is 185Connections are virtual because no persistent physical connection is
186established.
187
188=begin comment
189
157established. However, the existance of the node is checked by executing a 190However, the existance of the node is checked by executing a
158C<ClientHello> transaction. 191C<ClientHello> transaction.
192
193=end
159 194
160=cut 195=cut
161 196
162sub new { 197sub new {
163 my $class = shift; 198 my $class = shift;
172 $self; 207 $self;
173} 208}
174 209
175sub progress { 210sub progress {
176 my ($self, $txn, $type, $attr) = @_; 211 my ($self, $txn, $type, $attr) = @_;
177 warn "progress<$txn,$type," . (join ":", %$attr) . ">\n"; 212 #warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
178} 213}
179 214
180=item $txn = $fcp->txn(type => attr => val,...) 215=item $txn = $fcp->txn(type => attr => val,...)
181 216
182The low-level interface to transactions. Don't use it. 217The low-level interface to transactions. Don't use it.
213 my $txn = "Net::FCP::Txn::$type"->new(fcp => $self, type => tolc $type, attr => \%attr); 248 my $txn = "Net::FCP::Txn::$type"->new(fcp => $self, type => tolc $type, attr => \%attr);
214 249
215 $txn; 250 $txn;
216} 251}
217 252
218sub _txn($&) { 253{ # transactions
254
255my $txn = sub {
219 my ($name, $sub) = @_; 256 my ($name, $sub) = @_;
220 *{"$name\_txn"} = $sub; 257 *{"txn_$name"} = $sub;
221 *{$name} = sub { $sub->(@_)->result }; 258 *{$name} = sub { $sub->(@_)->result };
222} 259};
223 260
224=item $txn = $fcp->txn_client_hello 261=item $txn = $fcp->txn_client_hello
225 262
226=item $nodehello = $fcp->client_hello 263=item $nodehello = $fcp->client_hello
227 264
233 protocol => "1.2", 270 protocol => "1.2",
234 } 271 }
235 272
236=cut 273=cut
237 274
238_txn client_hello => sub { 275$txn->(client_hello => sub {
239 my ($self) = @_; 276 my ($self) = @_;
240 277
241 $self->txn ("client_hello"); 278 $self->txn ("client_hello");
242}; 279});
243 280
244=item $txn = $fcp->txn_client_info 281=item $txn = $fcp->txn_client_info
245 282
246=item $nodeinfo = $fcp->client_info 283=item $nodeinfo = $fcp->client_info
247 284
271 routing_time => "a5", 308 routing_time => "a5",
272 } 309 }
273 310
274=cut 311=cut
275 312
276_txn client_info => sub { 313$txn->(client_info => sub {
277 my ($self) = @_; 314 my ($self) = @_;
278 315
279 $self->txn ("client_info"); 316 $self->txn ("client_info");
280}; 317});
281 318
282=item $txn = $fcp->txn_generate_chk ($metadata, $data) 319=item $txn = $fcp->txn_generate_chk ($metadata, $data[, $cipher])
283 320
284=item $uri = $fcp->generate_chk ($metadata, $data) 321=item $uri = $fcp->generate_chk ($metadata, $data[, $cipher])
285 322
286Creates a new CHK, given the metadata and data. UNTESTED. 323Calculcates a CHK, given the metadata and data. C<$cipher> is either
324C<Rijndael> or C<Twofish>, with the latter being the default.
287 325
288=cut 326=cut
289 327
290_txn generate_chk => sub { 328$txn->(generate_chk => sub {
291 my ($self, $metadata, $data) = @_; 329 my ($self, $metadata, $data, $cipher) = @_;
292 330
293 $self->txn (generate_chk => data => "$data$metadata", metadata_length => length $metadata); 331 $self->txn (generate_chk =>
332 data => "$metadata$data",
333 metadata_length => length $metadata,
334 cipher => $cipher || "Twofish");
294}; 335});
295 336
296=item $txn = $fcp->txn_generate_svk_pair 337=item $txn = $fcp->txn_generate_svk_pair
297 338
298=item ($public, $private) = @{ $fcp->generate_svk_pair } 339=item ($public, $private) = @{ $fcp->generate_svk_pair }
299 340
304 "ZnmvMITaTXBMFGl4~jrjuyWxOWg" 345 "ZnmvMITaTXBMFGl4~jrjuyWxOWg"
305 ] 346 ]
306 347
307=cut 348=cut
308 349
309_txn generate_svk_pair => sub { 350$txn->(generate_svk_pair => sub {
310 my ($self) = @_; 351 my ($self) = @_;
311 352
312 $self->txn ("generate_svk_pair"); 353 $self->txn ("generate_svk_pair");
313}; 354});
314 355
315=item $txn = $fcp->txn_insert_private_key ($private) 356=item $txn = $fcp->txn_insert_private_key ($private)
316 357
317=item $uri = $fcp->insert_private_key ($private) 358=item $public = $fcp->insert_private_key ($private)
318 359
319Inserts a private key. $private can be either an insert URI (must start 360Inserts 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 361with C<freenet:SSK@>) or a raw private key (i.e. the private value you get
321from C<generate_svk_pair>). 362back from C<generate_svk_pair>).
322 363
323Returns the public key. 364Returns the public key.
324 365
325UNTESTED. 366UNTESTED.
326 367
327=cut 368=cut
328 369
329_txn insert_private_key => sub { 370$txn->(insert_private_key => sub {
330 my ($self, $privkey) = @_; 371 my ($self, $privkey) = @_;
331 372
332 $self->txn (invert_private_key => private => $privkey); 373 $self->txn (invert_private_key => private => $privkey);
333}; 374});
334 375
335=item $txn = $fcp->txn_get_size ($uri) 376=item $txn = $fcp->txn_get_size ($uri)
336 377
337=item $length = $fcp->get_size ($uri) 378=item $length = $fcp->get_size ($uri)
338 379
341 382
342UNTESTED. 383UNTESTED.
343 384
344=cut 385=cut
345 386
346_txn get_size => sub { 387$txn->(get_size => sub {
347 my ($self, $uri) = @_; 388 my ($self, $uri) = @_;
348 389
349 $self->txn (get_size => URI => $uri); 390 $self->txn (get_size => URI => $uri);
350}; 391});
351 392
352=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]]) 393=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]])
353 394
354=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal) 395=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal)
355 396
365 ) 406 )
366 }; 407 };
367 408
368=cut 409=cut
369 410
370_txn client_get => sub { 411$txn->(client_get => sub {
371 my ($self, $uri, $htl, $removelocal) = @_; 412 my ($self, $uri, $htl, $removelocal) = @_;
372 413
373 $self->txn (client_get => URI => $uri, hops_to_live => ($htl || 15), remove_local_key => $removelocal ? "true" : "false"); 414 $self->txn (client_get => URI => $uri, hops_to_live => (defined $htl ? $htl :15),
415 remove_local_key => $removelocal ? "true" : "false");
374}; 416});
375 417
418=item $txn = $fcp->txn_client_put ($uri, $metadata, $data, $htl, $removelocal)
419
420=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal);
421
422Insert a new key. If the client is inserting a CHK, the URI may be
423abbreviated as just CHK@. In this case, the node will calculate the
424CHK.
425
426C<$meta> can be a reference or a string (ONLY THE STRING CASE IS IMPLEMENTED!).
427
428THIS INTERFACE IS UNTESTED AND SUBJECT TO CHANGE.
429
430=cut
431
432$txn->(client_put => sub {
433 my ($self, $uri, $meta, $data, $htl, $removelocal) = @_;
434
435 $self->txn (client_put => URI => $uri, hops_to_live => (defined $htl ? $htl :15),
436 remove_local_key => $removelocal ? "true" : "false",
437 data => "$meta$data", metadata_length => length $meta);
438});
439
440} # transactions
441
376=item MISSING: ClientPut 442=item MISSING: (ClientPut), InsretKey
377 443
378=back 444=back
379 445
380=head2 THE Net::FCP::Txn CLASS 446=head2 THE Net::FCP::Txn CLASS
381 447
417 while (my ($k, $v) = each %{$self->{attr}}) { 483 while (my ($k, $v) = each %{$self->{attr}}) {
418 $attr .= (Net::FCP::touc $k) . "=$v\012" 484 $attr .= (Net::FCP::touc $k) . "=$v\012"
419 } 485 }
420 486
421 if (defined $data) { 487 if (defined $data) {
422 $attr .= "DataLength=" . (length $data) . "\012"; 488 $attr .= sprintf "DataLength=%x\012", length $data;
423 $data = "Data\012$data"; 489 $data = "Data\012$data";
424 } else { 490 } else {
425 $data = "EndMessage\012"; 491 $data = "EndMessage\012";
426 } 492 }
427 493
434 and !$!{EINPROGRESS} 500 and !$!{EINPROGRESS}
435 and Carp::croak "FCP::txn: unable to connect to $self->{fcp}{host}:$self->{fcp}{port}: $!\n"; 501 and Carp::croak "FCP::txn: unable to connect to $self->{fcp}{host}:$self->{fcp}{port}: $!\n";
436 502
437 $self->{sbuf} = 503 $self->{sbuf} =
438 "\x00\x00\x00\x02" 504 "\x00\x00\x00\x02"
439 . Net::FCP::touc $self->{type} 505 . (Net::FCP::touc $self->{type})
440 . "\012$attr$data"; 506 . "\012$attr$data";
441 507
442 #$fh->shutdown (1); # freenet buggy?, well, it's java... 508 #shutdown $fh, 1; # freenet buggy?, well, it's java...
443 509
444 $self->{fh} = $fh; 510 $self->{fh} = $fh;
445 511
446 $self->{w} = $EVENT->new_from_fh ($fh)->cb(sub { $self->fh_ready_w })->poll(0, 1, 1); 512 $self->{w} = $EVENT->new_from_fh ($fh)->cb(sub { $self->fh_ready_w })->poll(0, 1, 1);
447 513
483 549
484sub userdata($$) { 550sub userdata($$) {
485 my ($self, $data) = @_; 551 my ($self, $data) = @_;
486 $self->{userdata} = $data; 552 $self->{userdata} = $data;
487 $self; 553 $self;
554}
555
556=item $txn->cancel (%attr)
557
558Cancels the operation with a C<cancel> exception anf the given attributes
559(consider at least giving the attribute C<reason>).
560
561UNTESTED.
562
563=cut
564
565sub cancel {
566 my ($self, %attr) = @_;
567 $self->throw (Net::FCP::Exception->new (cancel => { %attr }));
568 $self->set_result;
569 $self->eof;
488} 570}
489 571
490sub fh_ready_w { 572sub fh_ready_w {
491 my ($self) = @_; 573 my ($self) = @_;
492 574
532 } else { 614 } else {
533 $self->eof; 615 $self->eof;
534 } 616 }
535} 617}
536 618
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 { 619sub rcv {
546 my ($self, $type, $attr) = @_; 620 my ($self, $type, $attr) = @_;
547 621
548 $type = Net::FCP::tolc $type; 622 $type = Net::FCP::tolc $type;
549 623
557} 631}
558 632
559# used as a default exception thrower 633# used as a default exception thrower
560sub rcv_throw_exception { 634sub rcv_throw_exception {
561 my ($self, $attr, $type) = @_; 635 my ($self, $attr, $type) = @_;
562 $self->throw (new Net::FCP::Exception $type, $attr); 636 $self->throw (Net::FCP::Exception->new ($type, $attr));
563} 637}
564 638
565*rcv_failed = \&Net::FCP::Txn::rcv_throw_exception; 639*rcv_failed = \&Net::FCP::Txn::rcv_throw_exception;
566*rcv_format_error = \&Net::FCP::Txn::rcv_throw_exception; 640*rcv_format_error = \&Net::FCP::Txn::rcv_throw_exception;
567 641
568sub throw { 642sub throw {
569 my ($self, $exc) = @_; 643 my ($self, $exc) = @_;
570 644
571 $self->{exception} = $exc; 645 $self->{exception} = $exc;
572 $self->set_result (1); 646 $self->set_result;
573 $self->eof; # must be last to avoid loops 647 $self->eof; # must be last to avoid loops
574} 648}
575 649
576sub set_result { 650sub set_result {
577 my ($self, $result) = @_; 651 my ($self, $result) = @_;
589 delete $self->{w}; 663 delete $self->{w};
590 delete $self->{fh}; 664 delete $self->{fh};
591 665
592 delete $self->{fcp}{txn}{$self}; 666 delete $self->{fcp}{txn}{$self};
593 667
594 $self->set_result; # just in case 668 unless (exists $self->{result}) {
669 $self->throw (Net::FCP::Exception->new (short_data => {
670 reason => "unexpected eof or internal node error",
671 }));
672 }
595} 673}
596 674
597sub progress { 675sub progress {
598 my ($self, $type, $attr) = @_; 676 my ($self, $type, $attr) = @_;
599 $self->{fcp}->progress ($self, $type, $attr); 677 $self->{fcp}->progress ($self, $type, $attr);
643use base Net::FCP::Txn; 721use base Net::FCP::Txn;
644 722
645sub rcv_success { 723sub rcv_success {
646 my ($self, $attr) = @_; 724 my ($self, $attr) = @_;
647 725
648 $self->set_result ($attr); 726 $self->set_result ($attr->{uri});
649} 727}
650 728
651package Net::FCP::Txn::GenerateSVKPair; 729package Net::FCP::Txn::GenerateSVKPair;
652 730
653use base Net::FCP::Txn; 731use base Net::FCP::Txn;
654 732
655sub rcv_success { 733sub rcv_success {
656 my ($self, $attr) = @_; 734 my ($self, $attr) = @_;
657
658 $self->set_result ([$attr->{PublicKey}, $attr->{PrivateKey}]); 735 $self->set_result ([$attr->{PublicKey}, $attr->{PrivateKey}]);
659} 736}
660 737
661package Net::FCP::Txn::InvertPrivateKey; 738package Net::FCP::Txn::InsertPrivateKey;
662 739
663use base Net::FCP::Txn; 740use base Net::FCP::Txn;
664 741
665sub rcv_success { 742sub rcv_success {
666 my ($self, $attr) = @_; 743 my ($self, $attr) = @_;
667
668 $self->set_result ($attr->{PublicKey}); 744 $self->set_result ($attr->{PublicKey});
669} 745}
670 746
671package Net::FCP::Txn::GetSize; 747package Net::FCP::Txn::GetSize;
672 748
673use base Net::FCP::Txn; 749use base Net::FCP::Txn;
674 750
675sub rcv_success { 751sub rcv_success {
676 my ($self, $attr) = @_; 752 my ($self, $attr) = @_;
677
678 $self->set_result ($attr->{Length}); 753 $self->set_result ($attr->{Length});
679} 754}
680 755
681package Net::FCP::Txn::GetPut; 756package Net::FCP::Txn::GetPut;
682 757
701 776
702use base Net::FCP::Txn::GetPut; 777use base Net::FCP::Txn::GetPut;
703 778
704*rcv_data_not_found = \&Net::FCP::Txn::rcv_throw_exception; 779*rcv_data_not_found = \&Net::FCP::Txn::rcv_throw_exception;
705 780
706sub rcv_data_found { 781sub 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) = @_; 782 my ($self, $chunk) = @_;
783
784 $self->{data} .= $chunk;
785
786 $self->progress ("data", { chunk => length $chunk, received => length $self->{data}, total => $self->{datalength} });
717 787
718 if ($self->{datalength} == length $self->{data}) { 788 if ($self->{datalength} == length $self->{data}) {
719 my $data = delete $self->{data}; 789 my $data = delete $self->{data};
720 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, ""; 790 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, "";
721 791
722 $self->set_result ([$meta, $data]); 792 $self->set_result ([$meta, $data]);
723 } elsif (!exists $self->{result}) { 793 $self->eof;
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 } 794 }
795}
796
797sub rcv_data_found {
798 my ($self, $attr, $type) = @_;
799
800 $self->progress ($type, $attr);
801
802 $self->{datalength} = hex $attr->{data_length};
803 $self->{metalength} = hex $attr->{metadata_length};
730} 804}
731 805
732package Net::FCP::Txn::ClientPut; 806package Net::FCP::Txn::ClientPut;
733 807
734use base Net::FCP::Txn::GetPut; 808use base Net::FCP::Txn::GetPut;
744sub rcv_success { 818sub rcv_success {
745 my ($self, $attr, $type) = @_; 819 my ($self, $attr, $type) = @_;
746 $self->set_result ($attr); 820 $self->set_result ($attr);
747} 821}
748 822
823=back
824
825=head2 The Net::FCP::Exception CLASS
826
827Any unexpected (non-standard) responses that make it impossible to return
828the advertised result will result in an exception being thrown when the
829C<result> method is called.
830
831These exceptions are represented by objects of this class.
832
833=over 4
834
835=cut
836
749package Net::FCP::Exception; 837package Net::FCP::Exception;
750 838
751use overload 839use overload
752 '""' => sub { 840 '""' => sub {
753 "Net::FCP::Exception<<$_[0][0]," . (join ":", %{$_[0][1]}) . ">>\n"; 841 "Net::FCP::Exception<<$_[0][0]," . (join ":", %{$_[0][1]}) . ">>";
754 }; 842 };
843
844=item $exc = new Net::FCP::Exception $type, \%attr
845
846Create a new exception object of the given type (a string like
847C<route_not_found>), and a hashref containing additional attributes
848(usually the attributes of the message causing the exception).
849
850=cut
755 851
756sub new { 852sub new {
757 my ($class, $type, $attr) = @_; 853 my ($class, $type, $attr) = @_;
758 854
759 bless [Net::FCP::tolc $type, { %$attr }], $class; 855 bless [Net::FCP::tolc $type, { %$attr }], $class;
760} 856}
761 857
858=item $exc->type([$type])
859
860With no arguments, returns the exception type. Otherwise a boolean
861indicating wether the exception is of the given type is returned.
862
863=cut
864
865sub type {
866 my ($self, $type) = @_;
867
868 @_ >= 2
869 ? $self->[0] eq $type
870 : $self->[0];
871}
872
873=item $exc->attr([$attr])
874
875With no arguments, returns the attributes. Otherwise the named attribute
876value is returned.
877
878=cut
879
880sub attr {
881 my ($self, $attr) = @_;
882
883 @_ >= 2
884 ? $self->[1]{$attr}
885 : $self->[1];
886}
887
762=back 888=back
763 889
764=head1 SEE ALSO 890=head1 SEE ALSO
765 891
766L<http://freenet.sf.net>. 892L<http://freenet.sf.net>.
772 Marc Lehmann <pcg@goof.com> 898 Marc Lehmann <pcg@goof.com>
773 http://www.goof.com/pcg/marc/ 899 http://www.goof.com/pcg/marc/
774 900
775=cut 901=cut
776 902
903package Net::FCP::Event::Auto;
904
905my @models = (
906 [Coro => Coro::Event:: ],
907 [Event => Event::],
908 [Glib => Glib:: ],
909 [Tk => Tk::],
910);
911
912sub AUTOLOAD {
913 $AUTOLOAD =~ s/.*://;
914
915 for (@models) {
916 my ($model, $package) = @$_;
917 if (defined ${"$package\::VERSION"}) {
918 $EVENT = "Net::FCP::Event::$model";
919 eval "require $EVENT"; die if $@;
920 goto &{"$EVENT\::$AUTOLOAD"};
921 }
922 }
923
924 for (@models) {
925 my ($model, $package) = @$_;
926 $EVENT = "Net::FCP::Event::$model";
927 if (eval "require $EVENT") {
928 goto &{"$EVENT\::$AUTOLOAD"};
929 }
930 }
931
932 die "No event module selected for Net::FCP and autodetect failed. Install any of these: Coro, Event, Glib or Tk.";
933}
934
7771; 9351;
778 936

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines