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.22 by root, Wed Sep 17 05:05:33 2003 UTC vs.
Revision 1.31 by root, Fri May 14 16:28:20 2004 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=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 the
113mandatory version header entries) and key C<raw> containing the original
114metadata string.
115
116All other headers are represented by arrayrefs (they can be repeated).
117
118Since this description is confusing, here is a rather verbose example of a
119parsed manifest:
120
121 (
122 raw => "Version...",
123 version => { revision => 1 },
124 document => [
125 {
126 info => { format" => "image/jpeg" },
127 name => "background.jpg",
128 redirect => { target => "freenet:CHK\@ZcagI,ra726bSw" },
129 },
130 {
131 info => { format" => "text/html" },
132 name => ".next",
133 redirect => { target => "freenet:SSK\@ilUPAgM/TFEE/3" },
134 },
135 {
136 info => { format" => "text/html" },
137 redirect => { target => "freenet:CHK\@8M8Po8ucwI,8xA" },
138 }
139 ]
140 )
141
142=cut
143
144sub parse_metadata {
145 my $data = shift;
146 my $meta = { raw => $data };
147
148 if ($data =~ /^Version\015?\012/gc) {
149 my $hdr = $meta->{version} = {};
150
151 for (;;) {
152 while ($data =~ /\G([^=\015\012]+)=([^\015\012]*)\015?\012/gc) {
153 my ($k, $v) = ($1, $2);
154 my @p = split /\./, tolc $k, 3;
155
156 $hdr->{$p[0]} = $v if @p == 1; # lamest code I ever wrote
157 $hdr->{$p[0]}{$p[1]} = $v if @p == 2;
158 $hdr->{$p[0]}{$p[1]}{$p[2]} = $v if @p == 3;
159 die "FATAL: 4+ dot metadata" if @p >= 4;
160 }
161
162 if ($data =~ /\GEndPart\015?\012/gc) {
163 # nop
164 } elsif ($data =~ /\GEnd(\015?\012|$)/gc) {
165 last;
166 } elsif ($data =~ /\G([A-Za-z0-9.\-]+)\015?\012/gcs) {
167 push @{$meta->{tolc $1}}, $hdr = {};
168 } elsif ($data =~ /\G(.*)/gcs) {
169 print STDERR "metadata format error ($1), please report this string: <<$data>>";
170 die "metadata format error";
171 }
172 }
173 }
174
175 #$meta->{tail} = substr $data, pos $data;
176
177 $meta;
178}
179
180=item $fcp = new Net::FCP [host => $host][, port => $port] 98=item $fcp = new Net::FCP [host => $host][, port => $port][, progress => \&cb]
181 99
182Create 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
183127.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>).
184 102
185Connections are virtual because no persistent physical connection is 103Connections are virtual because no persistent physical connection is
186established. 104established.
187 105
188=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:
189 109
190However, the existance of the node is checked by executing a 110 sub progress_cb {
191C<ClientHello> transaction. 111 my ($self, $txn, $type, $attr) = @_;
192 112
193=end 113 warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
114 }
194 115
195=cut 116=cut
196 117
197sub new { 118sub new {
198 my $class = shift; 119 my $class = shift;
199 my $self = bless { @_ }, $class; 120 my $self = bless { @_ }, $class;
200 121
201 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1"; 122 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1";
202 $self->{port} ||= $ENV{FREDPORT} || 8481; 123 $self->{port} ||= $ENV{FREDPORT} || 8481;
203 124
204 #$self->{nodehello} = $self->client_hello
205 # or croak "unable to get nodehello from node\n";
206
207 $self; 125 $self;
208} 126}
209 127
210sub progress { 128sub progress {
211 my ($self, $txn, $type, $attr) = @_; 129 my ($self, $txn, $type, $attr) = @_;
212 #warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
213}
214 130
131 $self->{progress}->($self, $txn, $type, $attr)
132 if $self->{progress};
133}
134
215=item $txn = $fcp->txn(type => attr => val,...) 135=item $txn = $fcp->txn (type => attr => val,...)
216 136
217The low-level interface to transactions. Don't use it. 137The low-level interface to transactions. Don't use it unless you have
218 138"special needs". Instead, use predefiend transactions like this:
219Here are some examples of using transactions:
220 139
221The blocking case, no (visible) transactions involved: 140The blocking case, no (visible) transactions involved:
222 141
223 my $nodehello = $fcp->client_hello; 142 my $nodehello = $fcp->client_hello;
224 143
243sub txn { 162sub txn {
244 my ($self, $type, %attr) = @_; 163 my ($self, $type, %attr) = @_;
245 164
246 $type = touc $type; 165 $type = touc $type;
247 166
248 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);
249 168
250 $txn; 169 $txn;
251} 170}
252 171
253{ # transactions 172{ # transactions
318 237
319=item $txn = $fcp->txn_generate_chk ($metadata, $data[, $cipher]) 238=item $txn = $fcp->txn_generate_chk ($metadata, $data[, $cipher])
320 239
321=item $uri = $fcp->generate_chk ($metadata, $data[, $cipher]) 240=item $uri = $fcp->generate_chk ($metadata, $data[, $cipher])
322 241
323Calculcates a CHK, given the metadata and data. C<$cipher> is either 242Calculates a CHK, given the metadata and data. C<$cipher> is either
324C<Rijndael> or C<Twofish>, with the latter being the default. 243C<Rijndael> or C<Twofish>, with the latter being the default.
325 244
326=cut 245=cut
327 246
328$txn->(generate_chk => sub { 247$txn->(generate_chk => sub {
329 my ($self, $metadata, $data, $cipher) = @_; 248 my ($self, $metadata, $data, $cipher) = @_;
330 249
250 $metadata = Net::FCP::Metadata::build_metadata $metadata;
251
331 $self->txn (generate_chk => 252 $self->txn (generate_chk =>
332 data => "$metadata$data", 253 data => "$metadata$data",
333 metadata_length => length $metadata, 254 metadata_length => xeh length $metadata,
334 cipher => $cipher || "Twofish"); 255 cipher => $cipher || "Twofish");
335}); 256});
336 257
337=item $txn = $fcp->txn_generate_svk_pair 258=item $txn = $fcp->txn_generate_svk_pair
338 259
339=item ($public, $private) = @{ $fcp->generate_svk_pair } 260=item ($public, $private) = @{ $fcp->generate_svk_pair }
340 261
341Creates 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.
342 264
343 [ 265 [
344 "hKs0-WDQA4pVZyMPKNFsK1zapWY", 266 "acLx4dux9fvvABH15Gk6~d3I-yw",
345 "ZnmvMITaTXBMFGl4~jrjuyWxOWg" 267 "cPoDkDMXDGSMM32plaPZDhJDxSs",
268 "BH7LXCov0w51-y9i~BoB3g",
346 ] 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!
347 280
348=cut 281=cut
349 282
350$txn->(generate_svk_pair => sub { 283$txn->(generate_svk_pair => sub {
351 my ($self) = @_; 284 my ($self) = @_;
352 285
353 $self->txn ("generate_svk_pair"); 286 $self->txn ("generate_svk_pair");
354}); 287});
355 288
356=item $txn = $fcp->txn_insert_private_key ($private) 289=item $txn = $fcp->txn_invert_private_key ($private)
357 290
358=item $public = $fcp->insert_private_key ($private) 291=item $public = $fcp->invert_private_key ($private)
359 292
360Inserts 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
361with 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.
362back from C<generate_svk_pair>). 295the private value you get back from C<generate_svk_pair>).
363 296
364Returns the public key. 297Returns the public key.
365 298
366UNTESTED.
367
368=cut 299=cut
369 300
370$txn->(insert_private_key => sub { 301$txn->(invert_private_key => sub {
371 my ($self, $privkey) = @_; 302 my ($self, $privkey) = @_;
372 303
373 $self->txn (invert_private_key => private => $privkey); 304 $self->txn (invert_private_key => private => $privkey);
374}); 305});
375 306
378=item $length = $fcp->get_size ($uri) 309=item $length = $fcp->get_size ($uri)
379 310
380Finds 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
381given document. 312given document.
382 313
383UNTESTED.
384
385=cut 314=cut
386 315
387$txn->(get_size => sub { 316$txn->(get_size => sub {
388 my ($self, $uri) = @_; 317 my ($self, $uri) = @_;
389 318
392 321
393=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]]) 322=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]])
394 323
395=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal) 324=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal)
396 325
397Fetches a (small, as it should fit into memory) file from 326Fetches a (small, as it should fit into memory) key content block from
398freenet. 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>).
399C<undef>).
400 328
401Due 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.
402 331
403 my ($meta, $data) = @{ 332 my ($meta, $data) = @{
404 $fcp->client_get ( 333 $fcp->client_get (
405 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w" 334 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w"
406 ) 335 )
409=cut 338=cut
410 339
411$txn->(client_get => sub { 340$txn->(client_get => sub {
412 my ($self, $uri, $htl, $removelocal) = @_; 341 my ($self, $uri, $htl, $removelocal) = @_;
413 342
343 $uri =~ s/^freenet://; $uri = "freenet:$uri";
344
414 $self->txn (client_get => URI => $uri, hops_to_live => (defined $htl ? $htl :15), 345 $self->txn (client_get => URI => $uri, hops_to_live => xeh (defined $htl ? $htl : 15),
415 remove_local_key => $removelocal ? "true" : "false"); 346 remove_local_key => $removelocal ? "true" : "false");
416}); 347});
417 348
418=item $txn = $fcp->txn_client_put ($uri, $metadata, $data, $htl, $removelocal) 349=item $txn = $fcp->txn_client_put ($uri, $metadata, $data, $htl, $removelocal)
419 350
420=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal); 351=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal);
421 352
422Insert 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
423abbreviated as just CHK@. In this case, the node will calculate the 354abbreviated as just CHK@. In this case, the node will calculate the
424CHK. 355CHK. If the key is a private SSK key, the node will calculcate the public
356key and the resulting public URI.
425 357
426C<$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.
427 360
428THIS INTERFACE IS UNTESTED AND SUBJECT TO CHANGE. 361The result is an arrayref with the keys C<uri>, C<public_key> and C<private_key>.
429 362
430=cut 363=cut
431 364
432$txn->(client_put => sub { 365$txn->(client_put => sub {
433 my ($self, $uri, $meta, $data, $htl, $removelocal) = @_; 366 my ($self, $uri, $metadata, $data, $htl, $removelocal) = @_;
434 367
435 $self->txn (client_put => URI => $uri, hops_to_live => (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),
436 remove_local_key => $removelocal ? "true" : "false", 373 remove_local_key => $removelocal ? "true" : "false",
437 data => "$meta$data", metadata_length => length $meta); 374 data => "$metadata$data", metadata_length => xeh length $metadata);
438}); 375});
439 376
440} # transactions 377} # transactions
441 378
442=item MISSING: (ClientPut), InsretKey
443
444=back 379=back
445 380
446=head2 THE Net::FCP::Txn CLASS 381=head2 THE Net::FCP::Txn CLASS
447 382
448All requests (or transactions) are executed in a asynchroneous way (LIE: 383All requests (or transactions) are executed in a asynchronous way. For
449uploads are blocking). For each request, a C<Net::FCP::Txn> object is 384each request, a C<Net::FCP::Txn> object is created (worse: a tcp
450created (worse: a tcp connection is created, too). 385connection is created, too).
451 386
452For each request there is actually a different subclass (and it's possible 387For each request there is actually a different subclass (and it's possible
453to subclass these, although of course not documented). 388to subclass these, although of course not documented).
454 389
455The most interesting method is C<result>. 390The most interesting method is C<result>.
672 } 607 }
673} 608}
674 609
675sub progress { 610sub progress {
676 my ($self, $type, $attr) = @_; 611 my ($self, $type, $attr) = @_;
612
677 $self->{fcp}->progress ($self, $type, $attr); 613 $self->{fcp}->progress ($self, $type, $attr);
678} 614}
679 615
680=item $result = $txn->result 616=item $result = $txn->result
681 617
682Waits until a result is available and then returns it. 618Waits until a result is available and then returns it.
683 619
684This waiting is (depending on your event model) not very efficient, as it 620This waiting is (depending on your event model) not very efficient, as it
685is done outside the "mainloop". 621is done outside the "mainloop". The biggest problem, however, is that it's
622blocking one thread of execution. Try to use the callback mechanism, if
623possible, and call result from within the callback (or after is has been
624run), as then no waiting is necessary.
686 625
687=cut 626=cut
688 627
689sub result { 628sub result {
690 my ($self) = @_; 629 my ($self) = @_;
730 669
731use base Net::FCP::Txn; 670use base Net::FCP::Txn;
732 671
733sub rcv_success { 672sub rcv_success {
734 my ($self, $attr) = @_; 673 my ($self, $attr) = @_;
735 $self->set_result ([$attr->{PublicKey}, $attr->{PrivateKey}]); 674 $self->set_result ([$attr->{public_key}, $attr->{private_key}, $attr->{crypto_key}]);
736} 675}
737 676
738package Net::FCP::Txn::InsertPrivateKey; 677package Net::FCP::Txn::InvertPrivateKey;
739 678
740use base Net::FCP::Txn; 679use base Net::FCP::Txn;
741 680
742sub rcv_success { 681sub rcv_success {
743 my ($self, $attr) = @_; 682 my ($self, $attr) = @_;
744 $self->set_result ($attr->{PublicKey}); 683 $self->set_result ($attr->{public_key});
745} 684}
746 685
747package Net::FCP::Txn::GetSize; 686package Net::FCP::Txn::GetSize;
748 687
749use base Net::FCP::Txn; 688use base Net::FCP::Txn;
750 689
751sub rcv_success { 690sub rcv_success {
752 my ($self, $attr) = @_; 691 my ($self, $attr) = @_;
753 $self->set_result ($attr->{Length}); 692 $self->set_result (hex $attr->{length});
754} 693}
755 694
756package Net::FCP::Txn::GetPut; 695package Net::FCP::Txn::GetPut;
757 696
758# base class for get and put 697# base class for get and put
759 698
760use base Net::FCP::Txn; 699use base Net::FCP::Txn;
761 700
762*rcv_uri_error = \&Net::FCP::Txn::rcv_throw_exception; 701*rcv_uri_error = \&Net::FCP::Txn::rcv_throw_exception;
763*rcv_route_not_found = \&Net::FCP::Txn::rcv_throw_exception; 702*rcv_route_not_found = \&Net::FCP::Txn::rcv_throw_exception;
764 703
765sub rcv_restarted { 704sub rcv_restarted {
766 my ($self, $attr, $type) = @_; 705 my ($self, $attr, $type) = @_;
767 706
768 delete $self->{datalength}; 707 delete $self->{datalength};
785 724
786 $self->progress ("data", { chunk => length $chunk, received => length $self->{data}, total => $self->{datalength} }); 725 $self->progress ("data", { chunk => length $chunk, received => length $self->{data}, total => $self->{datalength} });
787 726
788 if ($self->{datalength} == length $self->{data}) { 727 if ($self->{datalength} == length $self->{data}) {
789 my $data = delete $self->{data}; 728 my $data = delete $self->{data};
790 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, ""; 729 my $meta = new Net::FCP::Metadata (substr $data, 0, $self->{metalength}, "");
791 730
792 $self->set_result ([$meta, $data]); 731 $self->set_result ([$meta, $data]);
793 $self->eof; 732 $self->eof;
794 } 733 }
795} 734}
806package Net::FCP::Txn::ClientPut; 745package Net::FCP::Txn::ClientPut;
807 746
808use base Net::FCP::Txn::GetPut; 747use base Net::FCP::Txn::GetPut;
809 748
810*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception; 749*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception;
811*rcv_key_collision = \&Net::FCP::Txn::rcv_throw_exception;
812 750
813sub rcv_pending { 751sub rcv_pending {
814 my ($self, $attr, $type) = @_; 752 my ($self, $attr, $type) = @_;
815 $self->progress ($type, $attr); 753 $self->progress ($type, $attr);
816} 754}
817 755
818sub rcv_success { 756sub rcv_success {
819 my ($self, $attr, $type) = @_; 757 my ($self, $attr, $type) = @_;
820 $self->set_result ($attr); 758 $self->set_result ($attr);
759}
760
761sub rcv_key_collision {
762 my ($self, $attr, $type) = @_;
763 $self->set_result ({ key_collision => 1, %$attr });
821} 764}
822 765
823=back 766=back
824 767
825=head2 The Net::FCP::Exception CLASS 768=head2 The Net::FCP::Exception CLASS
901=cut 844=cut
902 845
903package Net::FCP::Event::Auto; 846package Net::FCP::Event::Auto;
904 847
905my @models = ( 848my @models = (
906 [Coro => Coro::Event:: ], 849 [Coro => Coro::Event::],
907 [Event => Event::], 850 [Event => Event::],
908 [Glib => Glib:: ], 851 [Glib => Glib::],
909 [Tk => Tk::], 852 [Tk => Tk::],
910); 853);
911 854
912sub AUTOLOAD { 855sub AUTOLOAD {
913 $AUTOLOAD =~ s/.*://; 856 $AUTOLOAD =~ s/.*://;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines