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.27 by root, Thu May 13 15:41:01 2004 UTC vs.
Revision 1.39 by root, Tue Nov 28 15:18:17 2006 UTC

13 13
14=head1 DESCRIPTION 14=head1 DESCRIPTION
15 15
16See L<http://freenet.sourceforge.net/index.php?page=fcp> for a description 16See L<http://freenet.sourceforge.net/index.php?page=fcp> for a description
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
19The module uses L<AnyEvent> to find a suitable Event module.
18 20
19=head1 WARNING 21=head1 WARNING
20 22
21This module is alpha. While it probably won't destroy (much :) of your 23This module is alpha. While it probably won't destroy (much :) of your
22data, it currently falls short of what it should provide (intelligent uri 24data, it currently falls short of what it should provide (intelligent uri
23following, splitfile downloads, healing...) 25following, splitfile downloads, healing...)
24 26
25=head2 IMPORT TAGS 27=head2 IMPORT TAGS
26 28
27Nothing much can be "imported" from this module right now. There are, 29Nothing much can be "imported" from this module right now.
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.
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 30
43=head2 FREENET BASICS 31=head2 FREENET BASICS
44 32
45Ok, this section will not explain any freenet basics to you, just some 33Ok, this section will not explain any freenet basics to you, just some
46problems I found that you might want to avoid: 34problems I found that you might want to avoid:
72 60
73package Net::FCP; 61package Net::FCP;
74 62
75use Carp; 63use Carp;
76 64
77$VERSION = 0.6; 65$VERSION = '1.0';
78 66
79no warnings; 67no warnings;
80 68
81our $EVENT = Net::FCP::Event::Auto::; 69use AnyEvent;
82 70
83sub import { 71use Net::FCP::Metadata;
84 shift; 72use Net::FCP::Util qw(tolc touc xeh);
85
86 for (@_) {
87 if (/^event=(\w+)$/) {
88 $EVENT = "Net::FCP::Event::$1";
89 eval "require $EVENT";
90 }
91 }
92 die $@ if $@;
93}
94
95sub touc($) {
96 local $_ = shift;
97 1 while s/((?:^|_)(?:svk|chk|uri)(?:_|$))/\U$1/;
98 s/(?:^|_)(.)/\U$1/g;
99 $_;
100}
101
102sub tolc($) {
103 local $_ = shift;
104 1 while s/(SVK|CHK|URI)([^_])/$1\_$2/i;
105 1 while s/([^_])(SVK|CHK|URI)/$1\_$2/i;
106 s/(?<=[a-z])(?=[A-Z])/_/g;
107 lc $_;
108}
109
110# the opposite of hex
111sub xeh($) {
112 sprintf "%x", $_[0];
113}
114
115=item $meta = Net::FCP::parse_metadata $string
116
117Parse a metadata string and return it.
118
119The metadata will be a hashref with key C<version> (containing the
120mandatory version header entries) and key C<raw> containing the original
121metadata string.
122
123All other headers are represented by arrayrefs (they can be repeated).
124
125Since this description is confusing, here is a rather verbose example of a
126parsed manifest:
127
128 (
129 raw => "Version...",
130 version => { revision => 1 },
131 document => [
132 {
133 info => { format" => "image/jpeg" },
134 name => "background.jpg",
135 redirect => { target => "freenet:CHK\@ZcagI,ra726bSw" },
136 },
137 {
138 info => { format" => "text/html" },
139 name => ".next",
140 redirect => { target => "freenet:SSK\@ilUPAgM/TFEE/3" },
141 },
142 {
143 info => { format" => "text/html" },
144 redirect => { target => "freenet:CHK\@8M8Po8ucwI,8xA" },
145 }
146 ]
147 )
148
149=cut
150
151sub parse_metadata {
152 my $data = shift;
153 my $meta = { raw => $data };
154
155 if ($data =~ /^Version\015?\012/gc) {
156 my $hdr = $meta->{version} = {};
157
158 for (;;) {
159 while ($data =~ /\G([^=\015\012]+)=([^\015\012]*)\015?\012/gc) {
160 my ($k, $v) = ($1, $2);
161 my @p = split /\./, tolc $k, 3;
162
163 $hdr->{$p[0]} = $v if @p == 1; # lamest code I ever wrote
164 $hdr->{$p[0]}{$p[1]} = $v if @p == 2;
165 $hdr->{$p[0]}{$p[1]}{$p[2]} = $v if @p == 3;
166 die "FATAL: 4+ dot metadata" if @p >= 4;
167 }
168
169 if ($data =~ /\GEndPart\015?\012/gc) {
170 # nop
171 } elsif ($data =~ /\GEnd(\015?\012|$)/gc) {
172 last;
173 } elsif ($data =~ /\G([A-Za-z0-9.\-]+)\015?\012/gcs) {
174 push @{$meta->{tolc $1}}, $hdr = {};
175 } elsif ($data =~ /\G(.*)/gcs) {
176 print STDERR "metadata format error ($1), please report this string: <<$data>>";
177 die "metadata format error";
178 }
179 }
180 }
181
182 #$meta->{tail} = substr $data, pos $data;
183
184 $meta;
185}
186 73
187=item $fcp = new Net::FCP [host => $host][, port => $port][, progress => \&cb] 74=item $fcp = new Net::FCP [host => $host][, port => $port][, progress => \&cb]
188 75
189Create a new virtual FCP connection to the given host and port (default 76Create a new virtual FCP connection to the given host and port (default
190127.0.0.1:8481, or the environment variables C<FREDHOST> and C<FREDPORT>). 77127.0.0.1:8481, or the environment variables C<FREDHOST> and C<FREDPORT>).
200 my ($self, $txn, $type, $attr) = @_; 87 my ($self, $txn, $type, $attr) = @_;
201 88
202 warn "progress<$txn,$type," . (join ":", %$attr) . ">\n"; 89 warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
203 } 90 }
204 91
205=begin comment
206
207However, the existance of the node is checked by executing a
208C<ClientHello> transaction.
209
210=end
211
212=cut 92=cut
213 93
214sub new { 94sub new {
215 my $class = shift; 95 my $class = shift;
216 my $self = bless { @_ }, $class; 96 my $self = bless { @_ }, $class;
217 97
218 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1"; 98 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1";
219 $self->{port} ||= $ENV{FREDPORT} || 8481; 99 $self->{port} ||= $ENV{FREDPORT} || 8481;
220 100
221 #$self->{nodehello} = $self->client_hello
222 # or croak "unable to get nodehello from node\n";
223
224 $self; 101 $self;
225} 102}
226 103
227sub progress { 104sub progress {
228 my ($self, $txn, $type, $attr) = @_; 105 my ($self, $txn, $type, $attr) = @_;
229 106
230 $self->{progress}->($self, $txn, $type, $attr) 107 $self->{progress}->($self, $txn, $type, $attr)
231 if $self->{progress}; 108 if $self->{progress};
232 #warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
233} 109}
234 110
235=item $txn = $fcp->txn(type => attr => val,...) 111=item $txn = $fcp->txn (type => attr => val,...)
236 112
237The low-level interface to transactions. Don't use it. 113The low-level interface to transactions. Don't use it unless you have
238 114"special needs". Instead, use predefiend transactions like this:
239Here are some examples of using transactions:
240 115
241The blocking case, no (visible) transactions involved: 116The blocking case, no (visible) transactions involved:
242 117
243 my $nodehello = $fcp->client_hello; 118 my $nodehello = $fcp->client_hello;
244 119
263sub txn { 138sub txn {
264 my ($self, $type, %attr) = @_; 139 my ($self, $type, %attr) = @_;
265 140
266 $type = touc $type; 141 $type = touc $type;
267 142
268 my $txn = "Net::FCP::Txn::$type"->new(fcp => $self, type => tolc $type, attr => \%attr); 143 my $txn = "Net::FCP::Txn::$type"->new (fcp => $self, type => tolc $type, attr => \%attr);
269 144
270 $txn; 145 $txn;
271} 146}
272 147
273{ # transactions 148{ # transactions
346=cut 221=cut
347 222
348$txn->(generate_chk => sub { 223$txn->(generate_chk => sub {
349 my ($self, $metadata, $data, $cipher) = @_; 224 my ($self, $metadata, $data, $cipher) = @_;
350 225
226 $metadata = Net::FCP::Metadata::build_metadata $metadata;
227
351 $self->txn (generate_chk => 228 $self->txn (generate_chk =>
352 data => "$metadata$data", 229 data => "$metadata$data",
353 metadata_length => xeh length $metadata, 230 metadata_length => xeh length $metadata,
354 cipher => $cipher || "Twofish"); 231 cipher => $cipher || "Twofish");
355}); 232});
356 233
357=item $txn = $fcp->txn_generate_svk_pair 234=item $txn = $fcp->txn_generate_svk_pair
358 235
359=item ($public, $private) = @{ $fcp->generate_svk_pair } 236=item ($public, $private, $crypto) = @{ $fcp->generate_svk_pair }
360 237
361Creates a new SVK pair. Returns an arrayref. 238Creates a new SVK pair. Returns an arrayref with the public key, the
239private key and a crypto key, which is just additional entropy.
362 240
363 [ 241 [
364 "hKs0-WDQA4pVZyMPKNFsK1zapWY", 242 "acLx4dux9fvvABH15Gk6~d3I-yw",
365 "ZnmvMITaTXBMFGl4~jrjuyWxOWg" 243 "cPoDkDMXDGSMM32plaPZDhJDxSs",
244 "BH7LXCov0w51-y9i~BoB3g",
366 ] 245 ]
246
247A private key (for inserting) can be constructed like this:
248
249 SSK@<private_key>,<crypto_key>/<name>
250
251It can be used to insert data. The corresponding public key looks like this:
252
253 SSK@<public_key>PAgM,<crypto_key>/<name>
254
255Watch out for the C<PAgM>-part!
367 256
368=cut 257=cut
369 258
370$txn->(generate_svk_pair => sub { 259$txn->(generate_svk_pair => sub {
371 my ($self) = @_; 260 my ($self) = @_;
372 261
373 $self->txn ("generate_svk_pair"); 262 $self->txn ("generate_svk_pair");
374}); 263});
375 264
376=item $txn = $fcp->txn_insert_private_key ($private) 265=item $txn = $fcp->txn_invert_private_key ($private)
377 266
378=item $public = $fcp->insert_private_key ($private) 267=item $public = $fcp->invert_private_key ($private)
379 268
380Inserts a private key. $private can be either an insert URI (must start 269Inverts a private key (returns the public key). C<$private> can be either
381with C<freenet:SSK@>) or a raw private key (i.e. the private value you get 270an insert URI (must start with C<freenet:SSK@>) or a raw private key (i.e.
382back from C<generate_svk_pair>). 271the private value you get back from C<generate_svk_pair>).
383 272
384Returns the public key. 273Returns the public key.
385 274
386UNTESTED.
387
388=cut 275=cut
389 276
390$txn->(insert_private_key => sub { 277$txn->(invert_private_key => sub {
391 my ($self, $privkey) = @_; 278 my ($self, $privkey) = @_;
392 279
393 $self->txn (invert_private_key => private => $privkey); 280 $self->txn (invert_private_key => private => $privkey);
394}); 281});
395 282
398=item $length = $fcp->get_size ($uri) 285=item $length = $fcp->get_size ($uri)
399 286
400Finds and returns the size (rounded up to the nearest power of two) of the 287Finds and returns the size (rounded up to the nearest power of two) of the
401given document. 288given document.
402 289
403UNTESTED.
404
405=cut 290=cut
406 291
407$txn->(get_size => sub { 292$txn->(get_size => sub {
408 my ($self, $uri) = @_; 293 my ($self, $uri) = @_;
409 294
412 297
413=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]]) 298=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]])
414 299
415=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal) 300=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal)
416 301
417Fetches a (small, as it should fit into memory) file from 302Fetches a (small, as it should fit into memory) key content block from
418freenet. C<$meta> is the metadata (as returned by C<parse_metadata> or 303freenet. C<$meta> is a C<Net::FCP::Metadata> object or C<undef>).
419C<undef>).
420 304
421The C<$uri> should begin with C<freenet:>, but the scheme is currently 305The C<$uri> should begin with C<freenet:>, but the scheme is currently
422added, if missing. 306added, if missing.
423
424Due to the overhead, a better method to download big files should be used.
425 307
426 my ($meta, $data) = @{ 308 my ($meta, $data) = @{
427 $fcp->client_get ( 309 $fcp->client_get (
428 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w" 310 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w"
429 ) 311 )
432=cut 314=cut
433 315
434$txn->(client_get => sub { 316$txn->(client_get => sub {
435 my ($self, $uri, $htl, $removelocal) = @_; 317 my ($self, $uri, $htl, $removelocal) = @_;
436 318
437 $uri =~ s/^freenet://; 319 $uri =~ s/^freenet://; $uri = "freenet:$uri";
438 $uri = "freenet:$uri";
439 320
440 $self->txn (client_get => URI => $uri, hops_to_live => xeh (defined $htl ? $htl : 15), 321 $self->txn (client_get => URI => $uri, hops_to_live => xeh (defined $htl ? $htl : 15),
441 remove_local_key => $removelocal ? "true" : "false"); 322 remove_local_key => $removelocal ? "true" : "false");
442}); 323});
443 324
445 326
446=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal); 327=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal);
447 328
448Insert a new key. If the client is inserting a CHK, the URI may be 329Insert a new key. If the client is inserting a CHK, the URI may be
449abbreviated as just CHK@. In this case, the node will calculate the 330abbreviated as just CHK@. In this case, the node will calculate the
450CHK. 331CHK. If the key is a private SSK key, the node will calculcate the public
332key and the resulting public URI.
451 333
452C<$meta> can be a reference or a string (ONLY THE STRING CASE IS IMPLEMENTED!). 334C<$meta> can be a hash reference (same format as returned by
335C<Net::FCP::parse_metadata>) or a string.
453 336
454THIS INTERFACE IS UNTESTED AND SUBJECT TO CHANGE. 337The result is an arrayref with the keys C<uri>, C<public_key> and C<private_key>.
455 338
456=cut 339=cut
457 340
458$txn->(client_put => sub { 341$txn->(client_put => sub {
459 my ($self, $uri, $meta, $data, $htl, $removelocal) = @_; 342 my ($self, $uri, $metadata, $data, $htl, $removelocal) = @_;
460 343
461 $self->txn (client_put => URI => $uri, xeh (defined $htl ? $htl : 15), 344 $metadata = Net::FCP::Metadata::build_metadata $metadata;
345 $uri =~ s/^freenet://; $uri = "freenet:$uri";
346
347 $self->txn (client_put => URI => $uri,
348 hops_to_live => xeh (defined $htl ? $htl : 15),
462 remove_local_key => $removelocal ? "true" : "false", 349 remove_local_key => $removelocal ? "true" : "false",
463 data => "$meta$data", metadata_length => xeh length $meta); 350 data => "$metadata$data", metadata_length => xeh length $metadata);
464}); 351});
465 352
466} # transactions 353} # transactions
467
468=item MISSING: (ClientPut), InsertKey
469 354
470=back 355=back
471 356
472=head2 THE Net::FCP::Txn CLASS 357=head2 THE Net::FCP::Txn CLASS
473 358
497 382
498sub new { 383sub new {
499 my $class = shift; 384 my $class = shift;
500 my $self = bless { @_ }, $class; 385 my $self = bless { @_ }, $class;
501 386
502 $self->{signal} = $EVENT->new_signal; 387 $self->{signal} = AnyEvent->condvar;
503 388
504 $self->{fcp}{txn}{$self} = $self; 389 $self->{fcp}{txn}{$self} = $self;
505 390
506 my $attr = ""; 391 my $attr = "";
507 my $data = delete $self->{attr}{data}; 392 my $data = delete $self->{attr}{data};
519 404
520 socket my $fh, PF_INET, SOCK_STREAM, 0 405 socket my $fh, PF_INET, SOCK_STREAM, 0
521 or Carp::croak "unable to create new tcp socket: $!"; 406 or Carp::croak "unable to create new tcp socket: $!";
522 binmode $fh, ":raw"; 407 binmode $fh, ":raw";
523 fcntl $fh, F_SETFL, O_NONBLOCK; 408 fcntl $fh, F_SETFL, O_NONBLOCK;
524 connect $fh, (sockaddr_in $self->{fcp}{port}, inet_aton $self->{fcp}{host}) 409 connect $fh, (sockaddr_in $self->{fcp}{port}, inet_aton $self->{fcp}{host});
525 and !$!{EWOULDBLOCK}
526 and !$!{EINPROGRESS}
527 and Carp::croak "FCP::txn: unable to connect to $self->{fcp}{host}:$self->{fcp}{port}: $!\n"; 410# and Carp::croak "FCP::txn: unable to connect to $self->{fcp}{host}:$self->{fcp}{port}: $!\n";
528 411
529 $self->{sbuf} = 412 $self->{sbuf} =
530 "\x00\x00\x00\x02" 413 "\x00\x00\x00\x02"
531 . (Net::FCP::touc $self->{type}) 414 . (Net::FCP::touc $self->{type})
532 . "\012$attr$data"; 415 . "\012$attr$data";
533 416
534 #shutdown $fh, 1; # freenet buggy?, well, it's java... 417 #shutdown $fh, 1; # freenet buggy?, well, it's java...
535 418
536 $self->{fh} = $fh; 419 $self->{fh} = $fh;
537 420
538 $self->{w} = $EVENT->new_from_fh ($fh)->cb(sub { $self->fh_ready_w })->poll(0, 1, 1); 421 $self->{w} = AnyEvent->io (fh => $fh, poll => 'w', cb => sub { $self->fh_ready_w });
539 422
540 $self; 423 $self;
541} 424}
542 425
543=item $txn = $txn->cb ($coderef) 426=item $txn = $txn->cb ($coderef)
579 $self; 462 $self;
580} 463}
581 464
582=item $txn->cancel (%attr) 465=item $txn->cancel (%attr)
583 466
584Cancels the operation with a C<cancel> exception anf the given attributes 467Cancels the operation with a C<cancel> exception and the given attributes
585(consider at least giving the attribute C<reason>). 468(consider at least giving the attribute C<reason>).
586 469
587UNTESTED. 470UNTESTED.
588 471
589=cut 472=cut
602 485
603 if ($len > 0) { 486 if ($len > 0) {
604 substr $self->{sbuf}, 0, $len, ""; 487 substr $self->{sbuf}, 0, $len, "";
605 unless (length $self->{sbuf}) { 488 unless (length $self->{sbuf}) {
606 fcntl $self->{fh}, F_SETFL, 0; 489 fcntl $self->{fh}, F_SETFL, 0;
607 $self->{w}->cb(sub { $self->fh_ready_r })->poll (1, 0, 1); 490 $self->{w} = AnyEvent->io (fh => $self->{fh}, poll => 'r', cb => sub { $self->fh_ready_r });
608 } 491 }
609 } elsif (defined $len) { 492 } elsif (defined $len) {
610 $self->throw (Net::FCP::Exception->new (network_error => { reason => "unexpected end of file while writing" })); 493 $self->throw (Net::FCP::Exception->new (network_error => { reason => "unexpected end of file while writing" }));
611 } else { 494 } else {
612 $self->throw (Net::FCP::Exception->new (network_error => { reason => "$!" })); 495 $self->throw (Net::FCP::Exception->new (network_error => { reason => "$!" }));
614} 497}
615 498
616sub fh_ready_r { 499sub fh_ready_r {
617 my ($self) = @_; 500 my ($self) = @_;
618 501
619 if (sysread $self->{fh}, $self->{buf}, 65536, length $self->{buf}) { 502 if (sysread $self->{fh}, $self->{buf}, 16384 + 1024, length $self->{buf}) {
620 for (;;) { 503 for (;;) {
621 if ($self->{datalen}) { 504 if ($self->{datalen}) {
622 #warn "expecting new datachunk $self->{datalen}, got ".(length $self->{buf})."\n";#d# 505 #warn "expecting new datachunk $self->{datalen}, got ".(length $self->{buf})."\n";#d#
623 if (length $self->{buf} >= $self->{datalen}) { 506 if (length $self->{buf} >= $self->{datalen}) {
624 $self->rcv_data (substr $self->{buf}, 0, delete $self->{datalen}, ""); 507 $self->rcv_data (substr $self->{buf}, 0, delete $self->{datalen}, "");
627 } 510 }
628 } elsif ($self->{buf} =~ s/^DataChunk\015?\012Length=([0-9a-fA-F]+)\015?\012Data\015?\012//) { 511 } elsif ($self->{buf} =~ s/^DataChunk\015?\012Length=([0-9a-fA-F]+)\015?\012Data\015?\012//) {
629 $self->{datalen} = hex $1; 512 $self->{datalen} = hex $1;
630 #warn "expecting new datachunk $self->{datalen}\n";#d# 513 #warn "expecting new datachunk $self->{datalen}\n";#d#
631 } elsif ($self->{buf} =~ s/^([a-zA-Z]+)\015?\012(?:(.+?)\015?\012)?EndMessage\015?\012//s) { 514 } elsif ($self->{buf} =~ s/^([a-zA-Z]+)\015?\012(?:(.+?)\015?\012)?EndMessage\015?\012//s) {
632 print "RECV<$1>\n";
633 $self->rcv ($1, { 515 $self->rcv ($1, {
634 map { my ($a, $b) = split /=/, $_, 2; ((Net::FCP::tolc $a), $b) } 516 map { my ($a, $b) = split /=/, $_, 2; ((Net::FCP::tolc $a), $b) }
635 split /\015?\012/, $2 517 split /\015?\012/, $2
636 }); 518 });
637 } else { 519 } else {
678 my ($self, $result) = @_; 560 my ($self, $result) = @_;
679 561
680 unless (exists $self->{result}) { 562 unless (exists $self->{result}) {
681 $self->{result} = $result; 563 $self->{result} = $result;
682 $self->{cb}->($self) if exists $self->{cb}; 564 $self->{cb}->($self) if exists $self->{cb};
683 $self->{signal}->send; 565 $self->{signal}->broadcast;
684 } 566 }
685} 567}
686 568
687sub eof { 569sub eof {
688 my ($self) = @_; 570 my ($self) = @_;
761 643
762use base Net::FCP::Txn; 644use base Net::FCP::Txn;
763 645
764sub rcv_success { 646sub rcv_success {
765 my ($self, $attr) = @_; 647 my ($self, $attr) = @_;
766 $self->set_result ([$attr->{PublicKey}, $attr->{PrivateKey}]); 648 $self->set_result ([$attr->{public_key}, $attr->{private_key}, $attr->{crypto_key}]);
767} 649}
768 650
769package Net::FCP::Txn::InsertPrivateKey; 651package Net::FCP::Txn::InvertPrivateKey;
770 652
771use base Net::FCP::Txn; 653use base Net::FCP::Txn;
772 654
773sub rcv_success { 655sub rcv_success {
774 my ($self, $attr) = @_; 656 my ($self, $attr) = @_;
775 $self->set_result ($attr->{PublicKey}); 657 $self->set_result ($attr->{public_key});
776} 658}
777 659
778package Net::FCP::Txn::GetSize; 660package Net::FCP::Txn::GetSize;
779 661
780use base Net::FCP::Txn; 662use base Net::FCP::Txn;
781 663
782sub rcv_success { 664sub rcv_success {
783 my ($self, $attr) = @_; 665 my ($self, $attr) = @_;
784 $self->set_result (hex $attr->{Length}); 666 $self->set_result (hex $attr->{length});
785} 667}
786 668
787package Net::FCP::Txn::GetPut; 669package Net::FCP::Txn::GetPut;
788 670
789# base class for get and put 671# base class for get and put
816 698
817 $self->progress ("data", { chunk => length $chunk, received => length $self->{data}, total => $self->{datalength} }); 699 $self->progress ("data", { chunk => length $chunk, received => length $self->{data}, total => $self->{datalength} });
818 700
819 if ($self->{datalength} == length $self->{data}) { 701 if ($self->{datalength} == length $self->{data}) {
820 my $data = delete $self->{data}; 702 my $data = delete $self->{data};
821 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, ""; 703 my $meta = new Net::FCP::Metadata (substr $data, 0, $self->{metalength}, "");
822 704
823 $self->set_result ([$meta, $data]); 705 $self->set_result ([$meta, $data]);
824 $self->eof; 706 $self->eof;
825 } 707 }
826} 708}
837package Net::FCP::Txn::ClientPut; 719package Net::FCP::Txn::ClientPut;
838 720
839use base Net::FCP::Txn::GetPut; 721use base Net::FCP::Txn::GetPut;
840 722
841*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception; 723*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception;
842*rcv_key_collision = \&Net::FCP::Txn::rcv_throw_exception;
843 724
844sub rcv_pending { 725sub rcv_pending {
845 my ($self, $attr, $type) = @_; 726 my ($self, $attr, $type) = @_;
846 $self->progress ($type, $attr); 727 $self->progress ($type, $attr);
847} 728}
848 729
849sub rcv_success { 730sub rcv_success {
850 my ($self, $attr, $type) = @_; 731 my ($self, $attr, $type) = @_;
851 $self->set_result ($attr); 732 $self->set_result ($attr);
733}
734
735sub rcv_key_collision {
736 my ($self, $attr, $type) = @_;
737 $self->set_result ({ key_collision => 1, %$attr });
852} 738}
853 739
854=back 740=back
855 741
856=head2 The Net::FCP::Exception CLASS 742=head2 The Net::FCP::Exception CLASS
924 810
925=head1 BUGS 811=head1 BUGS
926 812
927=head1 AUTHOR 813=head1 AUTHOR
928 814
929 Marc Lehmann <pcg@goof.com> 815 Marc Lehmann <schmorp@schmorp.de>
930 http://www.goof.com/pcg/marc/ 816 http://home.schmorp.de/
931 817
932=cut 818=cut
933 819
934package Net::FCP::Event::Auto; 8201
935 821
936my @models = (
937 [Coro => Coro::Event::],
938 [Event => Event::],
939 [Glib => Glib::],
940 [Tk => Tk::],
941);
942
943sub AUTOLOAD {
944 $AUTOLOAD =~ s/.*://;
945
946 for (@models) {
947 my ($model, $package) = @$_;
948 if (defined ${"$package\::VERSION"}) {
949 $EVENT = "Net::FCP::Event::$model";
950 eval "require $EVENT"; die if $@;
951 goto &{"$EVENT\::$AUTOLOAD"};
952 }
953 }
954
955 for (@models) {
956 my ($model, $package) = @$_;
957 $EVENT = "Net::FCP::Event::$model";
958 if (eval "require $EVENT") {
959 goto &{"$EVENT\::$AUTOLOAD"};
960 }
961 }
962
963 die "No event module selected for Net::FCP and autodetect failed. Install any of these: Coro, Event, Glib or Tk.";
964}
965
9661;
967

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines