ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-FCP/FCP.pm
(Generate patch)

Comparing Net-FCP/FCP.pm (file contents):
Revision 1.23 by root, Wed Sep 17 08:57:32 2003 UTC vs.
Revision 1.34 by root, Wed Jan 12 20:37:33 2005 UTC

72 72
73package Net::FCP; 73package Net::FCP;
74 74
75use Carp; 75use Carp;
76 76
77$VERSION = 0.5; 77$VERSION = 0.7;
78 78
79no warnings; 79no warnings;
80
81use Net::FCP::Metadata;
82use Net::FCP::Util qw(tolc touc xeh);
80 83
81our $EVENT = Net::FCP::Event::Auto::; 84our $EVENT = Net::FCP::Event::Auto::;
82 85
83sub import { 86sub import {
84 shift; 87 shift;
90 } 93 }
91 } 94 }
92 die $@ if $@; 95 die $@ if $@;
93} 96}
94 97
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# the opposite of hex
109sub xeh($) {
110 sprintf "%x", $_[0];
111}
112
113=item $meta = Net::FCP::parse_metadata $string
114
115Parse a metadata string and return it.
116
117The metadata will be a hashref with key C<version> (containing the
118mandatory version header entries) and key C<raw> containing the original
119metadata string.
120
121All other headers are represented by arrayrefs (they can be repeated).
122
123Since this description is confusing, here is a rather verbose example of a
124parsed manifest:
125
126 (
127 raw => "Version...",
128 version => { revision => 1 },
129 document => [
130 {
131 info => { format" => "image/jpeg" },
132 name => "background.jpg",
133 redirect => { target => "freenet:CHK\@ZcagI,ra726bSw" },
134 },
135 {
136 info => { format" => "text/html" },
137 name => ".next",
138 redirect => { target => "freenet:SSK\@ilUPAgM/TFEE/3" },
139 },
140 {
141 info => { format" => "text/html" },
142 redirect => { target => "freenet:CHK\@8M8Po8ucwI,8xA" },
143 }
144 ]
145 )
146
147=cut
148
149sub parse_metadata {
150 my $data = shift;
151 my $meta = { raw => $data };
152
153 if ($data =~ /^Version\015?\012/gc) {
154 my $hdr = $meta->{version} = {};
155
156 for (;;) {
157 while ($data =~ /\G([^=\015\012]+)=([^\015\012]*)\015?\012/gc) {
158 my ($k, $v) = ($1, $2);
159 my @p = split /\./, tolc $k, 3;
160
161 $hdr->{$p[0]} = $v if @p == 1; # lamest code I ever wrote
162 $hdr->{$p[0]}{$p[1]} = $v if @p == 2;
163 $hdr->{$p[0]}{$p[1]}{$p[2]} = $v if @p == 3;
164 die "FATAL: 4+ dot metadata" if @p >= 4;
165 }
166
167 if ($data =~ /\GEndPart\015?\012/gc) {
168 # nop
169 } elsif ($data =~ /\GEnd(\015?\012|$)/gc) {
170 last;
171 } elsif ($data =~ /\G([A-Za-z0-9.\-]+)\015?\012/gcs) {
172 push @{$meta->{tolc $1}}, $hdr = {};
173 } elsif ($data =~ /\G(.*)/gcs) {
174 print STDERR "metadata format error ($1), please report this string: <<$data>>";
175 die "metadata format error";
176 }
177 }
178 }
179
180 #$meta->{tail} = substr $data, pos $data;
181
182 $meta;
183}
184
185=item $fcp = new Net::FCP [host => $host][, port => $port] 98=item $fcp = new Net::FCP [host => $host][, port => $port][, progress => \&cb]
186 99
187Create a new virtual FCP connection to the given host and port (default 100Create a new virtual FCP connection to the given host and port (default
188127.0.0.1:8481, or the environment variables C<FREDHOST> and C<FREDPORT>). 101127.0.0.1:8481, or the environment variables C<FREDHOST> and C<FREDPORT>).
189 102
190Connections are virtual because no persistent physical connection is 103Connections are virtual because no persistent physical connection is
191established. 104established.
192 105
193=begin comment 106You can install a progress callback that is being called with the Net::FCP
107object, a txn object, the type of the transaction and the attributes. Use
108it like this:
194 109
195However, the existance of the node is checked by executing a 110 sub progress_cb {
196C<ClientHello> transaction. 111 my ($self, $txn, $type, $attr) = @_;
197 112
198=end 113 warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
114 }
199 115
200=cut 116=cut
201 117
202sub new { 118sub new {
203 my $class = shift; 119 my $class = shift;
204 my $self = bless { @_ }, $class; 120 my $self = bless { @_ }, $class;
205 121
206 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1"; 122 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1";
207 $self->{port} ||= $ENV{FREDPORT} || 8481; 123 $self->{port} ||= $ENV{FREDPORT} || 8481;
208 124
209 #$self->{nodehello} = $self->client_hello
210 # or croak "unable to get nodehello from node\n";
211
212 $self; 125 $self;
213} 126}
214 127
215sub progress { 128sub progress {
216 my ($self, $txn, $type, $attr) = @_; 129 my ($self, $txn, $type, $attr) = @_;
217 #warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
218}
219 130
131 $self->{progress}->($self, $txn, $type, $attr)
132 if $self->{progress};
133}
134
220=item $txn = $fcp->txn(type => attr => val,...) 135=item $txn = $fcp->txn (type => attr => val,...)
221 136
222The low-level interface to transactions. Don't use it. 137The low-level interface to transactions. Don't use it unless you have
223 138"special needs". Instead, use predefiend transactions like this:
224Here are some examples of using transactions:
225 139
226The blocking case, no (visible) transactions involved: 140The blocking case, no (visible) transactions involved:
227 141
228 my $nodehello = $fcp->client_hello; 142 my $nodehello = $fcp->client_hello;
229 143
248sub txn { 162sub txn {
249 my ($self, $type, %attr) = @_; 163 my ($self, $type, %attr) = @_;
250 164
251 $type = touc $type; 165 $type = touc $type;
252 166
253 my $txn = "Net::FCP::Txn::$type"->new(fcp => $self, type => tolc $type, attr => \%attr); 167 my $txn = "Net::FCP::Txn::$type"->new (fcp => $self, type => tolc $type, attr => \%attr);
254 168
255 $txn; 169 $txn;
256} 170}
257 171
258{ # transactions 172{ # transactions
323 237
324=item $txn = $fcp->txn_generate_chk ($metadata, $data[, $cipher]) 238=item $txn = $fcp->txn_generate_chk ($metadata, $data[, $cipher])
325 239
326=item $uri = $fcp->generate_chk ($metadata, $data[, $cipher]) 240=item $uri = $fcp->generate_chk ($metadata, $data[, $cipher])
327 241
328Calculcates a CHK, given the metadata and data. C<$cipher> is either 242Calculates a CHK, given the metadata and data. C<$cipher> is either
329C<Rijndael> or C<Twofish>, with the latter being the default. 243C<Rijndael> or C<Twofish>, with the latter being the default.
330 244
331=cut 245=cut
332 246
333$txn->(generate_chk => sub { 247$txn->(generate_chk => sub {
334 my ($self, $metadata, $data, $cipher) = @_; 248 my ($self, $metadata, $data, $cipher) = @_;
335 249
250 $metadata = Net::FCP::Metadata::build_metadata $metadata;
251
336 $self->txn (generate_chk => 252 $self->txn (generate_chk =>
337 data => "$metadata$data", 253 data => "$metadata$data",
338 metadata_length => xeh length $metadata, 254 metadata_length => xeh length $metadata,
339 cipher => $cipher || "Twofish"); 255 cipher => $cipher || "Twofish");
340}); 256});
341 257
342=item $txn = $fcp->txn_generate_svk_pair 258=item $txn = $fcp->txn_generate_svk_pair
343 259
344=item ($public, $private) = @{ $fcp->generate_svk_pair } 260=item ($public, $private, $crypto) = @{ $fcp->generate_svk_pair }
345 261
346Creates a new SVK pair. Returns an arrayref. 262Creates a new SVK pair. Returns an arrayref with the public key, the
263private key and a crypto key, which is just additional entropy.
347 264
348 [ 265 [
349 "hKs0-WDQA4pVZyMPKNFsK1zapWY", 266 "acLx4dux9fvvABH15Gk6~d3I-yw",
350 "ZnmvMITaTXBMFGl4~jrjuyWxOWg" 267 "cPoDkDMXDGSMM32plaPZDhJDxSs",
268 "BH7LXCov0w51-y9i~BoB3g",
351 ] 269 ]
270
271A private key (for inserting) can be constructed like this:
272
273 SSK@<private_key>,<crypto_key>/<name>
274
275It can be used to insert data. The corresponding public key looks like this:
276
277 SSK@<public_key>PAgM,<crypto_key>/<name>
278
279Watch out for the C<PAgM>-part!
352 280
353=cut 281=cut
354 282
355$txn->(generate_svk_pair => sub { 283$txn->(generate_svk_pair => sub {
356 my ($self) = @_; 284 my ($self) = @_;
357 285
358 $self->txn ("generate_svk_pair"); 286 $self->txn ("generate_svk_pair");
359}); 287});
360 288
361=item $txn = $fcp->txn_insert_private_key ($private) 289=item $txn = $fcp->txn_invert_private_key ($private)
362 290
363=item $public = $fcp->insert_private_key ($private) 291=item $public = $fcp->invert_private_key ($private)
364 292
365Inserts a private key. $private can be either an insert URI (must start 293Inverts a private key (returns the public key). C<$private> can be either
366with C<freenet:SSK@>) or a raw private key (i.e. the private value you get 294an insert URI (must start with C<freenet:SSK@>) or a raw private key (i.e.
367back from C<generate_svk_pair>). 295the private value you get back from C<generate_svk_pair>).
368 296
369Returns the public key. 297Returns the public key.
370 298
371UNTESTED.
372
373=cut 299=cut
374 300
375$txn->(insert_private_key => sub { 301$txn->(invert_private_key => sub {
376 my ($self, $privkey) = @_; 302 my ($self, $privkey) = @_;
377 303
378 $self->txn (invert_private_key => private => $privkey); 304 $self->txn (invert_private_key => private => $privkey);
379}); 305});
380 306
383=item $length = $fcp->get_size ($uri) 309=item $length = $fcp->get_size ($uri)
384 310
385Finds and returns the size (rounded up to the nearest power of two) of the 311Finds and returns the size (rounded up to the nearest power of two) of the
386given document. 312given document.
387 313
388UNTESTED.
389
390=cut 314=cut
391 315
392$txn->(get_size => sub { 316$txn->(get_size => sub {
393 my ($self, $uri) = @_; 317 my ($self, $uri) = @_;
394 318
397 321
398=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]]) 322=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]])
399 323
400=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal) 324=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal)
401 325
402Fetches a (small, as it should fit into memory) file from 326Fetches a (small, as it should fit into memory) key content block from
403freenet. C<$meta> is the metadata (as returned by C<parse_metadata> or 327freenet. C<$meta> is a C<Net::FCP::Metadata> object or C<undef>).
404C<undef>).
405 328
406Due to the overhead, a better method to download big files should be used. 329The C<$uri> should begin with C<freenet:>, but the scheme is currently
330added, if missing.
407 331
408 my ($meta, $data) = @{ 332 my ($meta, $data) = @{
409 $fcp->client_get ( 333 $fcp->client_get (
410 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w" 334 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w"
411 ) 335 )
414=cut 338=cut
415 339
416$txn->(client_get => sub { 340$txn->(client_get => sub {
417 my ($self, $uri, $htl, $removelocal) = @_; 341 my ($self, $uri, $htl, $removelocal) = @_;
418 342
343 $uri =~ s/^freenet://; $uri = "freenet:$uri";
344
419 $self->txn (client_get => URI => $uri, hops_to_live => xeh (defined $htl ? $htl : 15), 345 $self->txn (client_get => URI => $uri, hops_to_live => xeh (defined $htl ? $htl : 15),
420 remove_local_key => $removelocal ? "true" : "false"); 346 remove_local_key => $removelocal ? "true" : "false");
421}); 347});
422 348
423=item $txn = $fcp->txn_client_put ($uri, $metadata, $data, $htl, $removelocal) 349=item $txn = $fcp->txn_client_put ($uri, $metadata, $data, $htl, $removelocal)
424 350
425=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal); 351=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal);
426 352
427Insert a new key. If the client is inserting a CHK, the URI may be 353Insert a new key. If the client is inserting a CHK, the URI may be
428abbreviated as just CHK@. In this case, the node will calculate the 354abbreviated as just CHK@. In this case, the node will calculate the
429CHK. 355CHK. If the key is a private SSK key, the node will calculcate the public
356key and the resulting public URI.
430 357
431C<$meta> can be a reference or a string (ONLY THE STRING CASE IS IMPLEMENTED!). 358C<$meta> can be a hash reference (same format as returned by
359C<Net::FCP::parse_metadata>) or a string.
432 360
433THIS INTERFACE IS UNTESTED AND SUBJECT TO CHANGE. 361The result is an arrayref with the keys C<uri>, C<public_key> and C<private_key>.
434 362
435=cut 363=cut
436 364
437$txn->(client_put => sub { 365$txn->(client_put => sub {
438 my ($self, $uri, $meta, $data, $htl, $removelocal) = @_; 366 my ($self, $uri, $metadata, $data, $htl, $removelocal) = @_;
439 367
440 $self->txn (client_put => URI => $uri, xeh (defined $htl ? $htl : 15), 368 $metadata = Net::FCP::Metadata::build_metadata $metadata;
369 $uri =~ s/^freenet://; $uri = "freenet:$uri";
370
371 $self->txn (client_put => URI => $uri,
372 hops_to_live => xeh (defined $htl ? $htl : 15),
441 remove_local_key => $removelocal ? "true" : "false", 373 remove_local_key => $removelocal ? "true" : "false",
442 data => "$meta$data", metadata_length => xeh length $meta); 374 data => "$metadata$data", metadata_length => xeh length $metadata);
443}); 375});
444 376
445} # transactions 377} # transactions
446
447=item MISSING: (ClientPut), InsertKey
448 378
449=back 379=back
450 380
451=head2 THE Net::FCP::Txn CLASS 381=head2 THE Net::FCP::Txn CLASS
452 382
512 442
513 #shutdown $fh, 1; # freenet buggy?, well, it's java... 443 #shutdown $fh, 1; # freenet buggy?, well, it's java...
514 444
515 $self->{fh} = $fh; 445 $self->{fh} = $fh;
516 446
517 $self->{w} = $EVENT->new_from_fh ($fh)->cb(sub { $self->fh_ready_w })->poll(0, 1, 1); 447 $self->{w} = $EVENT->new_from_fh ($fh)
448 ->cb (sub { $self->fh_ready_w })
449 ->poll (0, 1, 1);
518 450
519 $self; 451 $self;
520} 452}
521 453
522=item $txn = $txn->cb ($coderef) 454=item $txn = $txn->cb ($coderef)
558 $self; 490 $self;
559} 491}
560 492
561=item $txn->cancel (%attr) 493=item $txn->cancel (%attr)
562 494
563Cancels the operation with a C<cancel> exception anf the given attributes 495Cancels the operation with a C<cancel> exception and the given attributes
564(consider at least giving the attribute C<reason>). 496(consider at least giving the attribute C<reason>).
565 497
566UNTESTED. 498UNTESTED.
567 499
568=cut 500=cut
677 } 609 }
678} 610}
679 611
680sub progress { 612sub progress {
681 my ($self, $type, $attr) = @_; 613 my ($self, $type, $attr) = @_;
614
682 $self->{fcp}->progress ($self, $type, $attr); 615 $self->{fcp}->progress ($self, $type, $attr);
683} 616}
684 617
685=item $result = $txn->result 618=item $result = $txn->result
686 619
738 671
739use base Net::FCP::Txn; 672use base Net::FCP::Txn;
740 673
741sub rcv_success { 674sub rcv_success {
742 my ($self, $attr) = @_; 675 my ($self, $attr) = @_;
743 $self->set_result ([$attr->{PublicKey}, $attr->{PrivateKey}]); 676 $self->set_result ([$attr->{public_key}, $attr->{private_key}, $attr->{crypto_key}]);
744} 677}
745 678
746package Net::FCP::Txn::InsertPrivateKey; 679package Net::FCP::Txn::InvertPrivateKey;
747 680
748use base Net::FCP::Txn; 681use base Net::FCP::Txn;
749 682
750sub rcv_success { 683sub rcv_success {
751 my ($self, $attr) = @_; 684 my ($self, $attr) = @_;
752 $self->set_result ($attr->{PublicKey}); 685 $self->set_result ($attr->{public_key});
753} 686}
754 687
755package Net::FCP::Txn::GetSize; 688package Net::FCP::Txn::GetSize;
756 689
757use base Net::FCP::Txn; 690use base Net::FCP::Txn;
758 691
759sub rcv_success { 692sub rcv_success {
760 my ($self, $attr) = @_; 693 my ($self, $attr) = @_;
761 $self->set_result (hex $attr->{Length}); 694 $self->set_result (hex $attr->{length});
762} 695}
763 696
764package Net::FCP::Txn::GetPut; 697package Net::FCP::Txn::GetPut;
765 698
766# base class for get and put 699# base class for get and put
767 700
768use base Net::FCP::Txn; 701use base Net::FCP::Txn;
769 702
770*rcv_uri_error = \&Net::FCP::Txn::rcv_throw_exception; 703*rcv_uri_error = \&Net::FCP::Txn::rcv_throw_exception;
771*rcv_route_not_found = \&Net::FCP::Txn::rcv_throw_exception; 704*rcv_route_not_found = \&Net::FCP::Txn::rcv_throw_exception;
772 705
773sub rcv_restarted { 706sub rcv_restarted {
774 my ($self, $attr, $type) = @_; 707 my ($self, $attr, $type) = @_;
775 708
776 delete $self->{datalength}; 709 delete $self->{datalength};
793 726
794 $self->progress ("data", { chunk => length $chunk, received => length $self->{data}, total => $self->{datalength} }); 727 $self->progress ("data", { chunk => length $chunk, received => length $self->{data}, total => $self->{datalength} });
795 728
796 if ($self->{datalength} == length $self->{data}) { 729 if ($self->{datalength} == length $self->{data}) {
797 my $data = delete $self->{data}; 730 my $data = delete $self->{data};
798 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, ""; 731 my $meta = new Net::FCP::Metadata (substr $data, 0, $self->{metalength}, "");
799 732
800 $self->set_result ([$meta, $data]); 733 $self->set_result ([$meta, $data]);
801 $self->eof; 734 $self->eof;
802 } 735 }
803} 736}
814package Net::FCP::Txn::ClientPut; 747package Net::FCP::Txn::ClientPut;
815 748
816use base Net::FCP::Txn::GetPut; 749use base Net::FCP::Txn::GetPut;
817 750
818*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception; 751*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception;
819*rcv_key_collision = \&Net::FCP::Txn::rcv_throw_exception;
820 752
821sub rcv_pending { 753sub rcv_pending {
822 my ($self, $attr, $type) = @_; 754 my ($self, $attr, $type) = @_;
823 $self->progress ($type, $attr); 755 $self->progress ($type, $attr);
824} 756}
825 757
826sub rcv_success { 758sub rcv_success {
827 my ($self, $attr, $type) = @_; 759 my ($self, $attr, $type) = @_;
828 $self->set_result ($attr); 760 $self->set_result ($attr);
761}
762
763sub rcv_key_collision {
764 my ($self, $attr, $type) = @_;
765 $self->set_result ({ key_collision => 1, %$attr });
829} 766}
830 767
831=back 768=back
832 769
833=head2 The Net::FCP::Exception CLASS 770=head2 The Net::FCP::Exception CLASS
902=head1 BUGS 839=head1 BUGS
903 840
904=head1 AUTHOR 841=head1 AUTHOR
905 842
906 Marc Lehmann <pcg@goof.com> 843 Marc Lehmann <pcg@goof.com>
907 http://www.goof.com/pcg/marc/ 844 http://home.schmorp.de/
908 845
909=cut 846=cut
910 847
911package Net::FCP::Event::Auto; 848package Net::FCP::Event::Auto;
912 849
913my @models = ( 850my @models = (
914 [Coro => Coro::Event:: ], 851 [Coro => Coro::Event::],
915 [Event => Event::], 852 [Event => Event::],
916 [Glib => Glib:: ], 853 [Glib => Glib::],
917 [Tk => Tk::], 854 [Tk => Tk::],
918); 855);
919 856
920sub AUTOLOAD { 857sub AUTOLOAD {
921 $AUTOLOAD =~ s/.*://; 858 $AUTOLOAD =~ s/.*://;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines