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.26 by root, Wed Dec 10 02:36:37 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
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 73
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)/\L$1\_/;
105 s/(?<=[a-z])(?=[A-Z])/_/g;
106 lc $_;
107}
108
109# the opposite of hex
110sub xeh($) {
111 sprintf "%x", $_[0];
112}
113
114=item $meta = Net::FCP::parse_metadata $string
115
116Parse a metadata string and return it.
117
118The metadata will be a hashref with key C<version> (containing the
119mandatory version header entries) and key C<raw> containing the original
120metadata string.
121
122All other headers are represented by arrayrefs (they can be repeated).
123
124Since this description is confusing, here is a rather verbose example of a
125parsed manifest:
126
127 (
128 raw => "Version...",
129 version => { revision => 1 },
130 document => [
131 {
132 info => { format" => "image/jpeg" },
133 name => "background.jpg",
134 redirect => { target => "freenet:CHK\@ZcagI,ra726bSw" },
135 },
136 {
137 info => { format" => "text/html" },
138 name => ".next",
139 redirect => { target => "freenet:SSK\@ilUPAgM/TFEE/3" },
140 },
141 {
142 info => { format" => "text/html" },
143 redirect => { target => "freenet:CHK\@8M8Po8ucwI,8xA" },
144 }
145 ]
146 )
147
148=cut
149
150sub parse_metadata {
151 my $data = shift;
152 my $meta = { raw => $data };
153
154 if ($data =~ /^Version\015?\012/gc) {
155 my $hdr = $meta->{version} = {};
156
157 for (;;) {
158 while ($data =~ /\G([^=\015\012]+)=([^\015\012]*)\015?\012/gc) {
159 my ($k, $v) = ($1, $2);
160 my @p = split /\./, tolc $k, 3;
161
162 $hdr->{$p[0]} = $v if @p == 1; # lamest code I ever wrote
163 $hdr->{$p[0]}{$p[1]} = $v if @p == 2;
164 $hdr->{$p[0]}{$p[1]}{$p[2]} = $v if @p == 3;
165 die "FATAL: 4+ dot metadata" if @p >= 4;
166 }
167
168 if ($data =~ /\GEndPart\015?\012/gc) {
169 # nop
170 } elsif ($data =~ /\GEnd(\015?\012|$)/gc) {
171 last;
172 } elsif ($data =~ /\G([A-Za-z0-9.\-]+)\015?\012/gcs) {
173 push @{$meta->{tolc $1}}, $hdr = {};
174 } elsif ($data =~ /\G(.*)/gcs) {
175 print STDERR "metadata format error ($1), please report this string: <<$data>>";
176 die "metadata format error";
177 }
178 }
179 }
180
181 #$meta->{tail} = substr $data, pos $data;
182
183 $meta;
184}
185
186=item $fcp = new Net::FCP [host => $host][, port => $port] 74=item $fcp = new Net::FCP [host => $host][, port => $port][, progress => \&cb]
187 75
188Create 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
189127.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>).
190 78
191Connections are virtual because no persistent physical connection is 79Connections are virtual because no persistent physical connection is
192established. 80established.
193 81
194=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:
195 85
196However, the existance of the node is checked by executing a 86 sub progress_cb {
197C<ClientHello> transaction. 87 my ($self, $txn, $type, $attr) = @_;
198 88
199=end 89 warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
90 }
200 91
201=cut 92=cut
202 93
203sub new { 94sub new {
204 my $class = shift; 95 my $class = shift;
205 my $self = bless { @_ }, $class; 96 my $self = bless { @_ }, $class;
206 97
207 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1"; 98 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1";
208 $self->{port} ||= $ENV{FREDPORT} || 8481; 99 $self->{port} ||= $ENV{FREDPORT} || 8481;
209 100
210 #$self->{nodehello} = $self->client_hello
211 # or croak "unable to get nodehello from node\n";
212
213 $self; 101 $self;
214} 102}
215 103
216sub progress { 104sub progress {
217 my ($self, $txn, $type, $attr) = @_; 105 my ($self, $txn, $type, $attr) = @_;
218 #warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
219}
220 106
107 $self->{progress}->($self, $txn, $type, $attr)
108 if $self->{progress};
109}
110
221=item $txn = $fcp->txn(type => attr => val,...) 111=item $txn = $fcp->txn (type => attr => val,...)
222 112
223The low-level interface to transactions. Don't use it. 113The low-level interface to transactions. Don't use it unless you have
224 114"special needs". Instead, use predefiend transactions like this:
225Here are some examples of using transactions:
226 115
227The blocking case, no (visible) transactions involved: 116The blocking case, no (visible) transactions involved:
228 117
229 my $nodehello = $fcp->client_hello; 118 my $nodehello = $fcp->client_hello;
230 119
249sub txn { 138sub txn {
250 my ($self, $type, %attr) = @_; 139 my ($self, $type, %attr) = @_;
251 140
252 $type = touc $type; 141 $type = touc $type;
253 142
254 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);
255 144
256 $txn; 145 $txn;
257} 146}
258 147
259{ # transactions 148{ # transactions
324 213
325=item $txn = $fcp->txn_generate_chk ($metadata, $data[, $cipher]) 214=item $txn = $fcp->txn_generate_chk ($metadata, $data[, $cipher])
326 215
327=item $uri = $fcp->generate_chk ($metadata, $data[, $cipher]) 216=item $uri = $fcp->generate_chk ($metadata, $data[, $cipher])
328 217
329Calculcates a CHK, given the metadata and data. C<$cipher> is either 218Calculates a CHK, given the metadata and data. C<$cipher> is either
330C<Rijndael> or C<Twofish>, with the latter being the default. 219C<Rijndael> or C<Twofish>, with the latter being the default.
331 220
332=cut 221=cut
333 222
334$txn->(generate_chk => sub { 223$txn->(generate_chk => sub {
335 my ($self, $metadata, $data, $cipher) = @_; 224 my ($self, $metadata, $data, $cipher) = @_;
336 225
226 $metadata = Net::FCP::Metadata::build_metadata $metadata;
227
337 $self->txn (generate_chk => 228 $self->txn (generate_chk =>
338 data => "$metadata$data", 229 data => "$metadata$data",
339 metadata_length => xeh length $metadata, 230 metadata_length => xeh length $metadata,
340 cipher => $cipher || "Twofish"); 231 cipher => $cipher || "Twofish");
341}); 232});
342 233
343=item $txn = $fcp->txn_generate_svk_pair 234=item $txn = $fcp->txn_generate_svk_pair
344 235
345=item ($public, $private) = @{ $fcp->generate_svk_pair } 236=item ($public, $private, $crypto) = @{ $fcp->generate_svk_pair }
346 237
347Creates 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.
348 240
349 [ 241 [
350 "hKs0-WDQA4pVZyMPKNFsK1zapWY", 242 "acLx4dux9fvvABH15Gk6~d3I-yw",
351 "ZnmvMITaTXBMFGl4~jrjuyWxOWg" 243 "cPoDkDMXDGSMM32plaPZDhJDxSs",
244 "BH7LXCov0w51-y9i~BoB3g",
352 ] 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!
353 256
354=cut 257=cut
355 258
356$txn->(generate_svk_pair => sub { 259$txn->(generate_svk_pair => sub {
357 my ($self) = @_; 260 my ($self) = @_;
358 261
359 $self->txn ("generate_svk_pair"); 262 $self->txn ("generate_svk_pair");
360}); 263});
361 264
362=item $txn = $fcp->txn_insert_private_key ($private) 265=item $txn = $fcp->txn_invert_private_key ($private)
363 266
364=item $public = $fcp->insert_private_key ($private) 267=item $public = $fcp->invert_private_key ($private)
365 268
366Inserts 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
367with 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.
368back from C<generate_svk_pair>). 271the private value you get back from C<generate_svk_pair>).
369 272
370Returns the public key. 273Returns the public key.
371 274
372UNTESTED.
373
374=cut 275=cut
375 276
376$txn->(insert_private_key => sub { 277$txn->(invert_private_key => sub {
377 my ($self, $privkey) = @_; 278 my ($self, $privkey) = @_;
378 279
379 $self->txn (invert_private_key => private => $privkey); 280 $self->txn (invert_private_key => private => $privkey);
380}); 281});
381 282
384=item $length = $fcp->get_size ($uri) 285=item $length = $fcp->get_size ($uri)
385 286
386Finds 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
387given document. 288given document.
388 289
389UNTESTED.
390
391=cut 290=cut
392 291
393$txn->(get_size => sub { 292$txn->(get_size => sub {
394 my ($self, $uri) = @_; 293 my ($self, $uri) = @_;
395 294
398 297
399=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]]) 298=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]])
400 299
401=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal) 300=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal)
402 301
403Fetches a (small, as it should fit into memory) file from 302Fetches a (small, as it should fit into memory) key content block from
404freenet. 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>).
405C<undef>).
406 304
407Due 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.
408 307
409 my ($meta, $data) = @{ 308 my ($meta, $data) = @{
410 $fcp->client_get ( 309 $fcp->client_get (
411 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w" 310 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w"
412 ) 311 )
415=cut 314=cut
416 315
417$txn->(client_get => sub { 316$txn->(client_get => sub {
418 my ($self, $uri, $htl, $removelocal) = @_; 317 my ($self, $uri, $htl, $removelocal) = @_;
419 318
420 $uri =~ s/^freenet://; 319 $uri =~ s/^freenet://; $uri = "freenet:$uri";
421 $uri = "freenet:$uri";
422 320
423 $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),
424 remove_local_key => $removelocal ? "true" : "false"); 322 remove_local_key => $removelocal ? "true" : "false");
425}); 323});
426 324
428 326
429=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal); 327=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal);
430 328
431Insert 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
432abbreviated as just CHK@. In this case, the node will calculate the 330abbreviated as just CHK@. In this case, the node will calculate the
433CHK. 331CHK. If the key is a private SSK key, the node will calculcate the public
332key and the resulting public URI.
434 333
435C<$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.
436 336
437THIS INTERFACE IS UNTESTED AND SUBJECT TO CHANGE. 337The result is an arrayref with the keys C<uri>, C<public_key> and C<private_key>.
438 338
439=cut 339=cut
440 340
441$txn->(client_put => sub { 341$txn->(client_put => sub {
442 my ($self, $uri, $meta, $data, $htl, $removelocal) = @_; 342 my ($self, $uri, $metadata, $data, $htl, $removelocal) = @_;
443 343
444 $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),
445 remove_local_key => $removelocal ? "true" : "false", 349 remove_local_key => $removelocal ? "true" : "false",
446 data => "$meta$data", metadata_length => xeh length $meta); 350 data => "$metadata$data", metadata_length => xeh length $metadata);
447}); 351});
448 352
449} # transactions 353} # transactions
450
451=item MISSING: (ClientPut), InsertKey
452 354
453=back 355=back
454 356
455=head2 THE Net::FCP::Txn CLASS 357=head2 THE Net::FCP::Txn CLASS
456 358
480 382
481sub new { 383sub new {
482 my $class = shift; 384 my $class = shift;
483 my $self = bless { @_ }, $class; 385 my $self = bless { @_ }, $class;
484 386
485 $self->{signal} = $EVENT->new_signal; 387 $self->{signal} = AnyEvent->condvar;
486 388
487 $self->{fcp}{txn}{$self} = $self; 389 $self->{fcp}{txn}{$self} = $self;
488 390
489 my $attr = ""; 391 my $attr = "";
490 my $data = delete $self->{attr}{data}; 392 my $data = delete $self->{attr}{data};
502 404
503 socket my $fh, PF_INET, SOCK_STREAM, 0 405 socket my $fh, PF_INET, SOCK_STREAM, 0
504 or Carp::croak "unable to create new tcp socket: $!"; 406 or Carp::croak "unable to create new tcp socket: $!";
505 binmode $fh, ":raw"; 407 binmode $fh, ":raw";
506 fcntl $fh, F_SETFL, O_NONBLOCK; 408 fcntl $fh, F_SETFL, O_NONBLOCK;
507 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});
508 and !$!{EWOULDBLOCK}
509 and !$!{EINPROGRESS}
510 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";
511 411
512 $self->{sbuf} = 412 $self->{sbuf} =
513 "\x00\x00\x00\x02" 413 "\x00\x00\x00\x02"
514 . (Net::FCP::touc $self->{type}) 414 . (Net::FCP::touc $self->{type})
515 . "\012$attr$data"; 415 . "\012$attr$data";
516 416
517 #shutdown $fh, 1; # freenet buggy?, well, it's java... 417 #shutdown $fh, 1; # freenet buggy?, well, it's java...
518 418
519 $self->{fh} = $fh; 419 $self->{fh} = $fh;
520 420
521 $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 });
522 422
523 $self; 423 $self;
524} 424}
525 425
526=item $txn = $txn->cb ($coderef) 426=item $txn = $txn->cb ($coderef)
562 $self; 462 $self;
563} 463}
564 464
565=item $txn->cancel (%attr) 465=item $txn->cancel (%attr)
566 466
567Cancels the operation with a C<cancel> exception anf the given attributes 467Cancels the operation with a C<cancel> exception and the given attributes
568(consider at least giving the attribute C<reason>). 468(consider at least giving the attribute C<reason>).
569 469
570UNTESTED. 470UNTESTED.
571 471
572=cut 472=cut
585 485
586 if ($len > 0) { 486 if ($len > 0) {
587 substr $self->{sbuf}, 0, $len, ""; 487 substr $self->{sbuf}, 0, $len, "";
588 unless (length $self->{sbuf}) { 488 unless (length $self->{sbuf}) {
589 fcntl $self->{fh}, F_SETFL, 0; 489 fcntl $self->{fh}, F_SETFL, 0;
590 $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 });
591 } 491 }
592 } elsif (defined $len) { 492 } elsif (defined $len) {
593 $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" }));
594 } else { 494 } else {
595 $self->throw (Net::FCP::Exception->new (network_error => { reason => "$!" })); 495 $self->throw (Net::FCP::Exception->new (network_error => { reason => "$!" }));
597} 497}
598 498
599sub fh_ready_r { 499sub fh_ready_r {
600 my ($self) = @_; 500 my ($self) = @_;
601 501
602 if (sysread $self->{fh}, $self->{buf}, 65536, length $self->{buf}) { 502 if (sysread $self->{fh}, $self->{buf}, 16384 + 1024, length $self->{buf}) {
603 for (;;) { 503 for (;;) {
604 if ($self->{datalen}) { 504 if ($self->{datalen}) {
605 #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#
606 if (length $self->{buf} >= $self->{datalen}) { 506 if (length $self->{buf} >= $self->{datalen}) {
607 $self->rcv_data (substr $self->{buf}, 0, delete $self->{datalen}, ""); 507 $self->rcv_data (substr $self->{buf}, 0, delete $self->{datalen}, "");
660 my ($self, $result) = @_; 560 my ($self, $result) = @_;
661 561
662 unless (exists $self->{result}) { 562 unless (exists $self->{result}) {
663 $self->{result} = $result; 563 $self->{result} = $result;
664 $self->{cb}->($self) if exists $self->{cb}; 564 $self->{cb}->($self) if exists $self->{cb};
665 $self->{signal}->send; 565 $self->{signal}->broadcast;
666 } 566 }
667} 567}
668 568
669sub eof { 569sub eof {
670 my ($self) = @_; 570 my ($self) = @_;
681 } 581 }
682} 582}
683 583
684sub progress { 584sub progress {
685 my ($self, $type, $attr) = @_; 585 my ($self, $type, $attr) = @_;
586
686 $self->{fcp}->progress ($self, $type, $attr); 587 $self->{fcp}->progress ($self, $type, $attr);
687} 588}
688 589
689=item $result = $txn->result 590=item $result = $txn->result
690 591
742 643
743use base Net::FCP::Txn; 644use base Net::FCP::Txn;
744 645
745sub rcv_success { 646sub rcv_success {
746 my ($self, $attr) = @_; 647 my ($self, $attr) = @_;
747 $self->set_result ([$attr->{PublicKey}, $attr->{PrivateKey}]); 648 $self->set_result ([$attr->{public_key}, $attr->{private_key}, $attr->{crypto_key}]);
748} 649}
749 650
750package Net::FCP::Txn::InsertPrivateKey; 651package Net::FCP::Txn::InvertPrivateKey;
751 652
752use base Net::FCP::Txn; 653use base Net::FCP::Txn;
753 654
754sub rcv_success { 655sub rcv_success {
755 my ($self, $attr) = @_; 656 my ($self, $attr) = @_;
756 $self->set_result ($attr->{PublicKey}); 657 $self->set_result ($attr->{public_key});
757} 658}
758 659
759package Net::FCP::Txn::GetSize; 660package Net::FCP::Txn::GetSize;
760 661
761use base Net::FCP::Txn; 662use base Net::FCP::Txn;
762 663
763sub rcv_success { 664sub rcv_success {
764 my ($self, $attr) = @_; 665 my ($self, $attr) = @_;
765 $self->set_result (hex $attr->{Length}); 666 $self->set_result (hex $attr->{length});
766} 667}
767 668
768package Net::FCP::Txn::GetPut; 669package Net::FCP::Txn::GetPut;
769 670
770# base class for get and put 671# base class for get and put
771 672
772use base Net::FCP::Txn; 673use base Net::FCP::Txn;
773 674
774*rcv_uri_error = \&Net::FCP::Txn::rcv_throw_exception; 675*rcv_uri_error = \&Net::FCP::Txn::rcv_throw_exception;
775*rcv_route_not_found = \&Net::FCP::Txn::rcv_throw_exception; 676*rcv_route_not_found = \&Net::FCP::Txn::rcv_throw_exception;
776 677
777sub rcv_restarted { 678sub rcv_restarted {
778 my ($self, $attr, $type) = @_; 679 my ($self, $attr, $type) = @_;
779 680
780 delete $self->{datalength}; 681 delete $self->{datalength};
797 698
798 $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} });
799 700
800 if ($self->{datalength} == length $self->{data}) { 701 if ($self->{datalength} == length $self->{data}) {
801 my $data = delete $self->{data}; 702 my $data = delete $self->{data};
802 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, ""; 703 my $meta = new Net::FCP::Metadata (substr $data, 0, $self->{metalength}, "");
803 704
804 $self->set_result ([$meta, $data]); 705 $self->set_result ([$meta, $data]);
805 $self->eof; 706 $self->eof;
806 } 707 }
807} 708}
818package Net::FCP::Txn::ClientPut; 719package Net::FCP::Txn::ClientPut;
819 720
820use base Net::FCP::Txn::GetPut; 721use base Net::FCP::Txn::GetPut;
821 722
822*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception; 723*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception;
823*rcv_key_collision = \&Net::FCP::Txn::rcv_throw_exception;
824 724
825sub rcv_pending { 725sub rcv_pending {
826 my ($self, $attr, $type) = @_; 726 my ($self, $attr, $type) = @_;
827 $self->progress ($type, $attr); 727 $self->progress ($type, $attr);
828} 728}
829 729
830sub rcv_success { 730sub rcv_success {
831 my ($self, $attr, $type) = @_; 731 my ($self, $attr, $type) = @_;
832 $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 });
833} 738}
834 739
835=back 740=back
836 741
837=head2 The Net::FCP::Exception CLASS 742=head2 The Net::FCP::Exception CLASS
905 810
906=head1 BUGS 811=head1 BUGS
907 812
908=head1 AUTHOR 813=head1 AUTHOR
909 814
910 Marc Lehmann <pcg@goof.com> 815 Marc Lehmann <schmorp@schmorp.de>
911 http://www.goof.com/pcg/marc/ 816 http://home.schmorp.de/
912 817
913=cut 818=cut
914 819
915package Net::FCP::Event::Auto; 8201
916 821
917my @models = (
918 [Coro => Coro::Event:: ],
919 [Event => Event::],
920 [Glib => Glib:: ],
921 [Tk => Tk::],
922);
923
924sub AUTOLOAD {
925 $AUTOLOAD =~ s/.*://;
926
927 for (@models) {
928 my ($model, $package) = @$_;
929 if (defined ${"$package\::VERSION"}) {
930 $EVENT = "Net::FCP::Event::$model";
931 eval "require $EVENT"; die if $@;
932 goto &{"$EVENT\::$AUTOLOAD"};
933 }
934 }
935
936 for (@models) {
937 my ($model, $package) = @$_;
938 $EVENT = "Net::FCP::Event::$model";
939 if (eval "require $EVENT") {
940 goto &{"$EVENT\::$AUTOLOAD"};
941 }
942 }
943
944 die "No event module selected for Net::FCP and autodetect failed. Install any of these: Coro, Event, Glib or Tk.";
945}
946
9471;
948

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines