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.17 by root, Fri Sep 12 03:28:45 2003 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 30
40=head2 FREENET BASICS 31=head2 FREENET BASICS
41 32
42Ok, 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
43problems I found that you might want to avoid: 34problems I found that you might want to avoid:
69 60
70package Net::FCP; 61package Net::FCP;
71 62
72use Carp; 63use Carp;
73 64
74$VERSION = 0.07; 65$VERSION = '1.0';
75 66
76no warnings; 67no warnings;
77 68
78our $EVENT = Net::FCP::Event::Auto::; 69use AnyEvent;
79$EVENT = Net::FCP::Event::Event;#d#
80 70
81sub import { 71use Net::FCP::Metadata;
82 shift; 72use Net::FCP::Util qw(tolc touc xeh);
83 73
84 for (@_) {
85 if (/^event=(\w+)$/) {
86 $EVENT = "Net::FCP::Event::$1";
87 }
88 }
89 eval "require $EVENT";
90 die $@ if $@;
91}
92
93sub touc($) {
94 local $_ = shift;
95 1 while s/((?:^|_)(?:svk|chk|uri)(?:_|$))/\U$1/;
96 s/(?:^|_)(.)/\U$1/g;
97 $_;
98}
99
100sub tolc($) {
101 local $_ = shift;
102 s/(?<=[a-z])(?=[A-Z])/_/g;
103 lc $_;
104}
105
106=item $meta = Net::FCP::parse_metadata $string
107
108Parse a metadata string and return it.
109
110The metadata will be a hashref with key C<version> (containing
111the mandatory version header entries).
112
113All other headers are represented by arrayrefs (they can be repeated).
114
115Since this is confusing, here is a rather verbose example of a parsed
116manifest:
117
118 (
119 version => { revision => 1 },
120 document => [
121 {
122 info => { format" => "image/jpeg" },
123 name => "background.jpg",
124 redirect => { target => "freenet:CHK\@ZcagI,ra726bSw" },
125 },
126 {
127 info => { format" => "text/html" },
128 name => ".next",
129 redirect => { target => "freenet:SSK\@ilUPAgM/TFEE/3" },
130 },
131 {
132 info => { format" => "text/html" },
133 redirect => { target => "freenet:CHK\@8M8Po8ucwI,8xA" },
134 }
135 ]
136 )
137
138=cut
139
140sub parse_metadata {
141 my $meta;
142
143 my $data = shift;
144 if ($data =~ /^Version\015?\012/gc) {
145 my $hdr = $meta->{version} = {};
146
147 for (;;) {
148 while ($data =~ /\G([^=\015\012]+)=([^\015\012]*)\015?\012/gc) {
149 my ($k, $v) = ($1, $2);
150 my @p = split /\./, tolc $k, 3;
151
152 $hdr->{$p[0]} = $v if @p == 1; # lamest code I ever wrote
153 $hdr->{$p[0]}{$p[1]} = $v if @p == 2;
154 $hdr->{$p[0]}{$p[1]}{$p[2]} = $v if @p == 3;
155 die "FATAL: 4+ dot metadata" if @p >= 4;
156 }
157
158 if ($data =~ /\GEndPart\015?\012/gc) {
159 # nop
160 } elsif ($data =~ /\GEnd(\015?\012|$)/gc) {
161 last;
162 } elsif ($data =~ /\G([A-Za-z0-9.\-]+)\015?\012/gcs) {
163 push @{$meta->{tolc $1}}, $hdr = {};
164 } elsif ($data =~ /\G(.*)/gcs) {
165 die "metadata format error ($1), please report this string: <<$data>>";
166 }
167 }
168 }
169
170 #$meta->{tail} = substr $data, pos $data;
171
172 $meta;
173}
174
175=item $fcp = new Net::FCP [host => $host][, port => $port] 74=item $fcp = new Net::FCP [host => $host][, port => $port][, progress => \&cb]
176 75
177Create 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
178127.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>).
179 78
180Connections are virtual because no persistent physical connection is 79Connections are virtual because no persistent physical connection is
181established. 80established.
182 81
183=begin comment 82You can install a progress callback that is being called with the Net::FCP
83object, a txn object, the type of the transaction and the attributes. Use
84it like this:
184 85
185However, the existance of the node is checked by executing a 86 sub progress_cb {
186C<ClientHello> transaction. 87 my ($self, $txn, $type, $attr) = @_;
187 88
188=end 89 warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
90 }
189 91
190=cut 92=cut
191 93
192sub new { 94sub new {
193 my $class = shift; 95 my $class = shift;
194 my $self = bless { @_ }, $class; 96 my $self = bless { @_ }, $class;
195 97
196 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1"; 98 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1";
197 $self->{port} ||= $ENV{FREDPORT} || 8481; 99 $self->{port} ||= $ENV{FREDPORT} || 8481;
198 100
199 #$self->{nodehello} = $self->client_hello
200 # or croak "unable to get nodehello from node\n";
201
202 $self; 101 $self;
203} 102}
204 103
205sub progress { 104sub progress {
206 my ($self, $txn, $type, $attr) = @_; 105 my ($self, $txn, $type, $attr) = @_;
207 warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
208}
209 106
107 $self->{progress}->($self, $txn, $type, $attr)
108 if $self->{progress};
109}
110
210=item $txn = $fcp->txn(type => attr => val,...) 111=item $txn = $fcp->txn (type => attr => val,...)
211 112
212The low-level interface to transactions. Don't use it. 113The low-level interface to transactions. Don't use it unless you have
213 114"special needs". Instead, use predefiend transactions like this:
214Here are some examples of using transactions:
215 115
216The blocking case, no (visible) transactions involved: 116The blocking case, no (visible) transactions involved:
217 117
218 my $nodehello = $fcp->client_hello; 118 my $nodehello = $fcp->client_hello;
219 119
238sub txn { 138sub txn {
239 my ($self, $type, %attr) = @_; 139 my ($self, $type, %attr) = @_;
240 140
241 $type = touc $type; 141 $type = touc $type;
242 142
243 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);
244 144
245 $txn; 145 $txn;
246} 146}
247 147
248{ # transactions 148{ # transactions
309 my ($self) = @_; 209 my ($self) = @_;
310 210
311 $self->txn ("client_info"); 211 $self->txn ("client_info");
312}); 212});
313 213
314=item $txn = $fcp->txn_generate_chk ($metadata, $data) 214=item $txn = $fcp->txn_generate_chk ($metadata, $data[, $cipher])
315 215
316=item $uri = $fcp->generate_chk ($metadata, $data) 216=item $uri = $fcp->generate_chk ($metadata, $data[, $cipher])
317 217
318Creates a new CHK, given the metadata and data. UNTESTED. 218Calculates a CHK, given the metadata and data. C<$cipher> is either
219C<Rijndael> or C<Twofish>, with the latter being the default.
319 220
320=cut 221=cut
321 222
322$txn->(generate_chk => sub { 223$txn->(generate_chk => sub {
323 my ($self, $metadata, $data) = @_; 224 my ($self, $metadata, $data, $cipher) = @_;
324 225
325 $self->txn (generate_chk => data => "$metadata$data", metadata_length => length $metadata); 226 $metadata = Net::FCP::Metadata::build_metadata $metadata;
227
228 $self->txn (generate_chk =>
229 data => "$metadata$data",
230 metadata_length => xeh length $metadata,
231 cipher => $cipher || "Twofish");
326}); 232});
327 233
328=item $txn = $fcp->txn_generate_svk_pair 234=item $txn = $fcp->txn_generate_svk_pair
329 235
330=item ($public, $private) = @{ $fcp->generate_svk_pair } 236=item ($public, $private, $crypto) = @{ $fcp->generate_svk_pair }
331 237
332Creates 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.
333 240
334 [ 241 [
335 "hKs0-WDQA4pVZyMPKNFsK1zapWY", 242 "acLx4dux9fvvABH15Gk6~d3I-yw",
336 "ZnmvMITaTXBMFGl4~jrjuyWxOWg" 243 "cPoDkDMXDGSMM32plaPZDhJDxSs",
244 "BH7LXCov0w51-y9i~BoB3g",
337 ] 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!
338 256
339=cut 257=cut
340 258
341$txn->(generate_svk_pair => sub { 259$txn->(generate_svk_pair => sub {
342 my ($self) = @_; 260 my ($self) = @_;
343 261
344 $self->txn ("generate_svk_pair"); 262 $self->txn ("generate_svk_pair");
345}); 263});
346 264
347=item $txn = $fcp->txn_insert_private_key ($private) 265=item $txn = $fcp->txn_invert_private_key ($private)
348 266
349=item $public = $fcp->insert_private_key ($private) 267=item $public = $fcp->invert_private_key ($private)
350 268
351Inserts 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
352with 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.
353back from C<generate_svk_pair>). 271the private value you get back from C<generate_svk_pair>).
354 272
355Returns the public key. 273Returns the public key.
356 274
357UNTESTED.
358
359=cut 275=cut
360 276
361$txn->(insert_private_key => sub { 277$txn->(invert_private_key => sub {
362 my ($self, $privkey) = @_; 278 my ($self, $privkey) = @_;
363 279
364 $self->txn (invert_private_key => private => $privkey); 280 $self->txn (invert_private_key => private => $privkey);
365}); 281});
366 282
369=item $length = $fcp->get_size ($uri) 285=item $length = $fcp->get_size ($uri)
370 286
371Finds 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
372given document. 288given document.
373 289
374UNTESTED.
375
376=cut 290=cut
377 291
378$txn->(get_size => sub { 292$txn->(get_size => sub {
379 my ($self, $uri) = @_; 293 my ($self, $uri) = @_;
380 294
383 297
384=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]]) 298=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]])
385 299
386=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal) 300=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal)
387 301
388Fetches a (small, as it should fit into memory) file from 302Fetches a (small, as it should fit into memory) key content block from
389freenet. 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>).
390C<undef>).
391 304
392Due to the overhead, a better method to download big files should be used. 305The C<$uri> should begin with C<freenet:>, but the scheme is currently
306added, if missing.
393 307
394 my ($meta, $data) = @{ 308 my ($meta, $data) = @{
395 $fcp->client_get ( 309 $fcp->client_get (
396 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w" 310 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w"
397 ) 311 )
400=cut 314=cut
401 315
402$txn->(client_get => sub { 316$txn->(client_get => sub {
403 my ($self, $uri, $htl, $removelocal) = @_; 317 my ($self, $uri, $htl, $removelocal) = @_;
404 318
319 $uri =~ s/^freenet://; $uri = "freenet:$uri";
320
405 $self->txn (client_get => URI => $uri, hops_to_live => (defined $htl ? $htl :15), 321 $self->txn (client_get => URI => $uri, hops_to_live => xeh (defined $htl ? $htl : 15),
406 remove_local_key => $removelocal ? "true" : "false"); 322 remove_local_key => $removelocal ? "true" : "false");
407}); 323});
408 324
409=item $txn = $fcp->txn_client_put ($uri, $metadata, $data, $htl, $removelocal) 325=item $txn = $fcp->txn_client_put ($uri, $metadata, $data, $htl, $removelocal)
410 326
411=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal); 327=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal);
412 328
413Insert 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
414abbreviated as just CHK@. In this case, the node will calculate the 330abbreviated as just CHK@. In this case, the node will calculate the
415CHK. 331CHK. If the key is a private SSK key, the node will calculcate the public
332key and the resulting public URI.
416 333
417C<$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.
418 336
419THIS INTERFACE IS UNTESTED AND SUBJECT TO CHANGE. 337The result is an arrayref with the keys C<uri>, C<public_key> and C<private_key>.
420 338
421=cut 339=cut
422 340
423$txn->(client_put => sub { 341$txn->(client_put => sub {
424 my ($self, $uri, $meta, $data, $htl, $removelocal) = @_; 342 my ($self, $uri, $metadata, $data, $htl, $removelocal) = @_;
425 343
426 $self->txn (client_put => URI => $uri, hops_to_live => (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),
427 remove_local_key => $removelocal ? "true" : "false", 349 remove_local_key => $removelocal ? "true" : "false",
428 data => "$meta$data", metadata_length => length $meta); 350 data => "$metadata$data", metadata_length => xeh length $metadata);
429}); 351});
430 352
431} # transactions 353} # transactions
432 354
433=item MISSING: (ClientPut), InsretKey
434
435=back 355=back
436 356
437=head2 THE Net::FCP::Txn CLASS 357=head2 THE Net::FCP::Txn CLASS
438 358
439All requests (or transactions) are executed in a asynchroneous way (LIE: 359All requests (or transactions) are executed in a asynchronous way. For
440uploads are blocking). For each request, a C<Net::FCP::Txn> object is 360each request, a C<Net::FCP::Txn> object is created (worse: a tcp
441created (worse: a tcp connection is created, too). 361connection is created, too).
442 362
443For each request there is actually a different subclass (and it's possible 363For each request there is actually a different subclass (and it's possible
444to subclass these, although of course not documented). 364to subclass these, although of course not documented).
445 365
446The most interesting method is C<result>. 366The most interesting method is C<result>.
462 382
463sub new { 383sub new {
464 my $class = shift; 384 my $class = shift;
465 my $self = bless { @_ }, $class; 385 my $self = bless { @_ }, $class;
466 386
467 $self->{signal} = $EVENT->new_signal; 387 $self->{signal} = AnyEvent->condvar;
468 388
469 $self->{fcp}{txn}{$self} = $self; 389 $self->{fcp}{txn}{$self} = $self;
470 390
471 my $attr = ""; 391 my $attr = "";
472 my $data = delete $self->{attr}{data}; 392 my $data = delete $self->{attr}{data};
474 while (my ($k, $v) = each %{$self->{attr}}) { 394 while (my ($k, $v) = each %{$self->{attr}}) {
475 $attr .= (Net::FCP::touc $k) . "=$v\012" 395 $attr .= (Net::FCP::touc $k) . "=$v\012"
476 } 396 }
477 397
478 if (defined $data) { 398 if (defined $data) {
479 $attr .= "DataLength=" . (length $data) . "\012"; 399 $attr .= sprintf "DataLength=%x\012", length $data;
480 $data = "Data\012$data"; 400 $data = "Data\012$data";
481 } else { 401 } else {
482 $data = "EndMessage\012"; 402 $data = "EndMessage\012";
483 } 403 }
484 404
485 socket my $fh, PF_INET, SOCK_STREAM, 0 405 socket my $fh, PF_INET, SOCK_STREAM, 0
486 or Carp::croak "unable to create new tcp socket: $!"; 406 or Carp::croak "unable to create new tcp socket: $!";
487 binmode $fh, ":raw"; 407 binmode $fh, ":raw";
488 fcntl $fh, F_SETFL, O_NONBLOCK; 408 fcntl $fh, F_SETFL, O_NONBLOCK;
489 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});
490 and !$!{EWOULDBLOCK}
491 and !$!{EINPROGRESS}
492 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";
493 411
494 $self->{sbuf} = 412 $self->{sbuf} =
495 "\x00\x00\x00\x02" 413 "\x00\x00\x00\x02"
496 . Net::FCP::touc $self->{type} 414 . (Net::FCP::touc $self->{type})
497 . "\012$attr$data"; 415 . "\012$attr$data";
498 416
499 #$fh->shutdown (1); # freenet buggy?, well, it's java... 417 #shutdown $fh, 1; # freenet buggy?, well, it's java...
500 418
501 $self->{fh} = $fh; 419 $self->{fh} = $fh;
502 420
503 $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 });
504 422
505 $self; 423 $self;
506} 424}
507 425
508=item $txn = $txn->cb ($coderef) 426=item $txn = $txn->cb ($coderef)
544 $self; 462 $self;
545} 463}
546 464
547=item $txn->cancel (%attr) 465=item $txn->cancel (%attr)
548 466
549Cancels the operation with a C<cancel> exception anf the given attributes 467Cancels the operation with a C<cancel> exception and the given attributes
550(consider at least giving the attribute C<reason>). 468(consider at least giving the attribute C<reason>).
551 469
552UNTESTED. 470UNTESTED.
553 471
554=cut 472=cut
567 485
568 if ($len > 0) { 486 if ($len > 0) {
569 substr $self->{sbuf}, 0, $len, ""; 487 substr $self->{sbuf}, 0, $len, "";
570 unless (length $self->{sbuf}) { 488 unless (length $self->{sbuf}) {
571 fcntl $self->{fh}, F_SETFL, 0; 489 fcntl $self->{fh}, F_SETFL, 0;
572 $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 });
573 } 491 }
574 } elsif (defined $len) { 492 } elsif (defined $len) {
575 $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" }));
576 } else { 494 } else {
577 $self->throw (Net::FCP::Exception->new (network_error => { reason => "$!" })); 495 $self->throw (Net::FCP::Exception->new (network_error => { reason => "$!" }));
579} 497}
580 498
581sub fh_ready_r { 499sub fh_ready_r {
582 my ($self) = @_; 500 my ($self) = @_;
583 501
584 if (sysread $self->{fh}, $self->{buf}, 65536, length $self->{buf}) { 502 if (sysread $self->{fh}, $self->{buf}, 16384 + 1024, length $self->{buf}) {
585 for (;;) { 503 for (;;) {
586 if ($self->{datalen}) { 504 if ($self->{datalen}) {
587 #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#
588 if (length $self->{buf} >= $self->{datalen}) { 506 if (length $self->{buf} >= $self->{datalen}) {
589 $self->rcv_data (substr $self->{buf}, 0, delete $self->{datalen}, ""); 507 $self->rcv_data (substr $self->{buf}, 0, delete $self->{datalen}, "");
642 my ($self, $result) = @_; 560 my ($self, $result) = @_;
643 561
644 unless (exists $self->{result}) { 562 unless (exists $self->{result}) {
645 $self->{result} = $result; 563 $self->{result} = $result;
646 $self->{cb}->($self) if exists $self->{cb}; 564 $self->{cb}->($self) if exists $self->{cb};
647 $self->{signal}->send; 565 $self->{signal}->broadcast;
648 } 566 }
649} 567}
650 568
651sub eof { 569sub eof {
652 my ($self) = @_; 570 my ($self) = @_;
663 } 581 }
664} 582}
665 583
666sub progress { 584sub progress {
667 my ($self, $type, $attr) = @_; 585 my ($self, $type, $attr) = @_;
586
668 $self->{fcp}->progress ($self, $type, $attr); 587 $self->{fcp}->progress ($self, $type, $attr);
669} 588}
670 589
671=item $result = $txn->result 590=item $result = $txn->result
672 591
673Waits until a result is available and then returns it. 592Waits until a result is available and then returns it.
674 593
675This waiting is (depending on your event model) not very efficient, as it 594This waiting is (depending on your event model) not very efficient, as it
676is done outside the "mainloop". 595is done outside the "mainloop". The biggest problem, however, is that it's
596blocking one thread of execution. Try to use the callback mechanism, if
597possible, and call result from within the callback (or after is has been
598run), as then no waiting is necessary.
677 599
678=cut 600=cut
679 601
680sub result { 602sub result {
681 my ($self) = @_; 603 my ($self) = @_;
712use base Net::FCP::Txn; 634use base Net::FCP::Txn;
713 635
714sub rcv_success { 636sub rcv_success {
715 my ($self, $attr) = @_; 637 my ($self, $attr) = @_;
716 638
717 $self->set_result ($attr); 639 $self->set_result ($attr->{uri});
718} 640}
719 641
720package Net::FCP::Txn::GenerateSVKPair; 642package Net::FCP::Txn::GenerateSVKPair;
721 643
722use base Net::FCP::Txn; 644use base Net::FCP::Txn;
723 645
724sub rcv_success { 646sub rcv_success {
725 my ($self, $attr) = @_; 647 my ($self, $attr) = @_;
726 $self->set_result ([$attr->{PublicKey}, $attr->{PrivateKey}]); 648 $self->set_result ([$attr->{public_key}, $attr->{private_key}, $attr->{crypto_key}]);
727} 649}
728 650
729package Net::FCP::Txn::InsertPrivateKey; 651package Net::FCP::Txn::InvertPrivateKey;
730 652
731use base Net::FCP::Txn; 653use base Net::FCP::Txn;
732 654
733sub rcv_success { 655sub rcv_success {
734 my ($self, $attr) = @_; 656 my ($self, $attr) = @_;
735 $self->set_result ($attr->{PublicKey}); 657 $self->set_result ($attr->{public_key});
736} 658}
737 659
738package Net::FCP::Txn::GetSize; 660package Net::FCP::Txn::GetSize;
739 661
740use base Net::FCP::Txn; 662use base Net::FCP::Txn;
741 663
742sub rcv_success { 664sub rcv_success {
743 my ($self, $attr) = @_; 665 my ($self, $attr) = @_;
744 $self->set_result ($attr->{Length}); 666 $self->set_result (hex $attr->{length});
745} 667}
746 668
747package Net::FCP::Txn::GetPut; 669package Net::FCP::Txn::GetPut;
748 670
749# base class for get and put 671# base class for get and put
750 672
751use base Net::FCP::Txn; 673use base Net::FCP::Txn;
752 674
753*rcv_uri_error = \&Net::FCP::Txn::rcv_throw_exception; 675*rcv_uri_error = \&Net::FCP::Txn::rcv_throw_exception;
754*rcv_route_not_found = \&Net::FCP::Txn::rcv_throw_exception; 676*rcv_route_not_found = \&Net::FCP::Txn::rcv_throw_exception;
755 677
756sub rcv_restarted { 678sub rcv_restarted {
757 my ($self, $attr, $type) = @_; 679 my ($self, $attr, $type) = @_;
758 680
759 delete $self->{datalength}; 681 delete $self->{datalength};
772sub rcv_data { 694sub rcv_data {
773 my ($self, $chunk) = @_; 695 my ($self, $chunk) = @_;
774 696
775 $self->{data} .= $chunk; 697 $self->{data} .= $chunk;
776 698
777 $self->progress ("data", { chunk => length $chunk, total => length $self->{data}, end => $self->{datalength} }); 699 $self->progress ("data", { chunk => length $chunk, received => length $self->{data}, total => $self->{datalength} });
778 700
779 if ($self->{datalength} == length $self->{data}) { 701 if ($self->{datalength} == length $self->{data}) {
780 my $data = delete $self->{data}; 702 my $data = delete $self->{data};
781 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, ""; 703 my $meta = new Net::FCP::Metadata (substr $data, 0, $self->{metalength}, "");
782 704
783 $self->set_result ([$meta, $data]); 705 $self->set_result ([$meta, $data]);
706 $self->eof;
784 } 707 }
785} 708}
786 709
787sub rcv_data_found { 710sub rcv_data_found {
788 my ($self, $attr, $type) = @_; 711 my ($self, $attr, $type) = @_;
796package Net::FCP::Txn::ClientPut; 719package Net::FCP::Txn::ClientPut;
797 720
798use base Net::FCP::Txn::GetPut; 721use base Net::FCP::Txn::GetPut;
799 722
800*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception; 723*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception;
801*rcv_key_collision = \&Net::FCP::Txn::rcv_throw_exception;
802 724
803sub rcv_pending { 725sub rcv_pending {
804 my ($self, $attr, $type) = @_; 726 my ($self, $attr, $type) = @_;
805 $self->progress ($type, $attr); 727 $self->progress ($type, $attr);
806} 728}
808sub rcv_success { 730sub rcv_success {
809 my ($self, $attr, $type) = @_; 731 my ($self, $attr, $type) = @_;
810 $self->set_result ($attr); 732 $self->set_result ($attr);
811} 733}
812 734
735sub rcv_key_collision {
736 my ($self, $attr, $type) = @_;
737 $self->set_result ({ key_collision => 1, %$attr });
738}
739
813=back 740=back
814 741
815=head2 The Net::FCP::Exception CLASS 742=head2 The Net::FCP::Exception CLASS
816 743
817Any unexpected (non-standard) responses that make it impossible to return 744Any unexpected (non-standard) responses that make it impossible to return
826 753
827package Net::FCP::Exception; 754package Net::FCP::Exception;
828 755
829use overload 756use overload
830 '""' => sub { 757 '""' => sub {
831 "Net::FCP::Exception<<$_[0][0]," . (join ":", %{$_[0][1]}) . ">>\n"; 758 "Net::FCP::Exception<<$_[0][0]," . (join ":", %{$_[0][1]}) . ">>";
832 }; 759 };
833 760
834=item $exc = new Net::FCP::Exception $type, \%attr 761=item $exc = new Net::FCP::Exception $type, \%attr
835 762
836Create a new exception object of the given type (a string like 763Create a new exception object of the given type (a string like
883 810
884=head1 BUGS 811=head1 BUGS
885 812
886=head1 AUTHOR 813=head1 AUTHOR
887 814
888 Marc Lehmann <pcg@goof.com> 815 Marc Lehmann <schmorp@schmorp.de>
889 http://www.goof.com/pcg/marc/ 816 http://home.schmorp.de/
890 817
891=cut 818=cut
892 819
8931; 8201
894 821

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines