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.20 by root, Mon Sep 15 00:05:32 2003 UTC vs.
Revision 1.41 by root, Thu May 1 15:30:15 2008 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines