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.21 by root, Tue Sep 16 07:00:59 2003 UTC vs.
Revision 1.30 by root, Fri May 14 16:12:26 2004 UTC

72 72
73package Net::FCP; 73package Net::FCP;
74 74
75use Carp; 75use Carp;
76 76
77$VERSION = 0.08; 77$VERSION = 0.7;
78 78
79no warnings; 79no warnings;
80
81use Net::FCP::Metadata;
80 82
81our $EVENT = Net::FCP::Event::Auto::; 83our $EVENT = Net::FCP::Event::Auto::;
82 84
83sub import { 85sub import {
84 shift; 86 shift;
99 $_; 101 $_;
100} 102}
101 103
102sub tolc($) { 104sub tolc($) {
103 local $_ = shift; 105 local $_ = shift;
106 1 while s/(SVK|CHK|URI)([^_])/$1\_$2/i;
107 1 while s/([^_])(SVK|CHK|URI)/$1\_$2/i;
104 s/(?<=[a-z])(?=[A-Z])/_/g; 108 s/(?<=[a-z])(?=[A-Z])/_/g;
105 lc $_; 109 lc $_;
106} 110}
107 111
108=item $meta = Net::FCP::parse_metadata $string 112# the opposite of hex
109 113sub xeh($) {
110Parse a metadata string and return it. 114 sprintf "%x", $_[0];
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} 115}
179 116
180=item $fcp = new Net::FCP [host => $host][, port => $port] 117=item $fcp = new Net::FCP [host => $host][, port => $port][, progress => \&cb]
181 118
182Create a new virtual FCP connection to the given host and port (default 119Create 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>). 120127.0.0.1:8481, or the environment variables C<FREDHOST> and C<FREDPORT>).
184 121
185Connections are virtual because no persistent physical connection is 122Connections are virtual because no persistent physical connection is
186established. 123established.
187 124
188=begin comment 125You can install a progress callback that is being called with the Net::FCP
126object, a txn object, the type of the transaction and the attributes. Use
127it like this:
189 128
190However, the existance of the node is checked by executing a 129 sub progress_cb {
191C<ClientHello> transaction. 130 my ($self, $txn, $type, $attr) = @_;
192 131
193=end 132 warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
133 }
194 134
195=cut 135=cut
196 136
197sub new { 137sub new {
198 my $class = shift; 138 my $class = shift;
199 my $self = bless { @_ }, $class; 139 my $self = bless { @_ }, $class;
200 140
201 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1"; 141 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1";
202 $self->{port} ||= $ENV{FREDPORT} || 8481; 142 $self->{port} ||= $ENV{FREDPORT} || 8481;
203 143
204 #$self->{nodehello} = $self->client_hello
205 # or croak "unable to get nodehello from node\n";
206
207 $self; 144 $self;
208} 145}
209 146
210sub progress { 147sub progress {
211 my ($self, $txn, $type, $attr) = @_; 148 my ($self, $txn, $type, $attr) = @_;
212 #warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
213}
214 149
150 $self->{progress}->($self, $txn, $type, $attr)
151 if $self->{progress};
152}
153
215=item $txn = $fcp->txn(type => attr => val,...) 154=item $txn = $fcp->txn (type => attr => val,...)
216 155
217The low-level interface to transactions. Don't use it. 156The low-level interface to transactions. Don't use it unless you have
218 157"special needs". Instead, use predefiend transactions like this:
219Here are some examples of using transactions:
220 158
221The blocking case, no (visible) transactions involved: 159The blocking case, no (visible) transactions involved:
222 160
223 my $nodehello = $fcp->client_hello; 161 my $nodehello = $fcp->client_hello;
224 162
243sub txn { 181sub txn {
244 my ($self, $type, %attr) = @_; 182 my ($self, $type, %attr) = @_;
245 183
246 $type = touc $type; 184 $type = touc $type;
247 185
248 my $txn = "Net::FCP::Txn::$type"->new(fcp => $self, type => tolc $type, attr => \%attr); 186 my $txn = "Net::FCP::Txn::$type"->new (fcp => $self, type => tolc $type, attr => \%attr);
249 187
250 $txn; 188 $txn;
251} 189}
252 190
253{ # transactions 191{ # transactions
318 256
319=item $txn = $fcp->txn_generate_chk ($metadata, $data[, $cipher]) 257=item $txn = $fcp->txn_generate_chk ($metadata, $data[, $cipher])
320 258
321=item $uri = $fcp->generate_chk ($metadata, $data[, $cipher]) 259=item $uri = $fcp->generate_chk ($metadata, $data[, $cipher])
322 260
323Calculcates a CHK, given the metadata and data. C<$cipher> is either 261Calculates a CHK, given the metadata and data. C<$cipher> is either
324C<Rijndael> or C<Twofish>, with the latter being the default. 262C<Rijndael> or C<Twofish>, with the latter being the default.
325 263
326=cut 264=cut
327 265
328$txn->(generate_chk => sub { 266$txn->(generate_chk => sub {
329 my ($self, $metadata, $data, $cipher) = @_; 267 my ($self, $metadata, $data, $cipher) = @_;
330 268
269 $metadata = Net::FCP::Metadata::build_metadata $metadata;
270
331 $self->txn (generate_chk => 271 $self->txn (generate_chk =>
332 data => "$metadata$data", 272 data => "$metadata$data",
333 metadata_length => length $metadata, 273 metadata_length => xeh length $metadata,
334 cipher => $cipher || "Twofish"); 274 cipher => $cipher || "Twofish");
335}); 275});
336 276
337=item $txn = $fcp->txn_generate_svk_pair 277=item $txn = $fcp->txn_generate_svk_pair
338 278
339=item ($public, $private) = @{ $fcp->generate_svk_pair } 279=item ($public, $private) = @{ $fcp->generate_svk_pair }
340 280
341Creates a new SVK pair. Returns an arrayref. 281Creates a new SVK pair. Returns an arrayref with the public key, the
282private key and a crypto key, which is just additional entropy.
342 283
343 [ 284 [
344 "hKs0-WDQA4pVZyMPKNFsK1zapWY", 285 "acLx4dux9fvvABH15Gk6~d3I-yw",
345 "ZnmvMITaTXBMFGl4~jrjuyWxOWg" 286 "cPoDkDMXDGSMM32plaPZDhJDxSs",
287 "BH7LXCov0w51-y9i~BoB3g",
346 ] 288 ]
289
290A private key (for inserting) can be constructed like this:
291
292 SSK@<private_key>,<crypto_key>/<name>
293
294It can be used to insert data. The corresponding public key looks like this:
295
296 SSK@<public_key>PAgM,<crypto_key>/<name>
297
298Watch out for the C<PAgM>-part!
347 299
348=cut 300=cut
349 301
350$txn->(generate_svk_pair => sub { 302$txn->(generate_svk_pair => sub {
351 my ($self) = @_; 303 my ($self) = @_;
352 304
353 $self->txn ("generate_svk_pair"); 305 $self->txn ("generate_svk_pair");
354}); 306});
355 307
356=item $txn = $fcp->txn_insert_private_key ($private) 308=item $txn = $fcp->txn_invert_private_key ($private)
357 309
358=item $public = $fcp->insert_private_key ($private) 310=item $public = $fcp->invert_private_key ($private)
359 311
360Inserts a private key. $private can be either an insert URI (must start 312Inverts 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 313an insert URI (must start with C<freenet:SSK@>) or a raw private key (i.e.
362back from C<generate_svk_pair>). 314the private value you get back from C<generate_svk_pair>).
363 315
364Returns the public key. 316Returns the public key.
365 317
366UNTESTED.
367
368=cut 318=cut
369 319
370$txn->(insert_private_key => sub { 320$txn->(invert_private_key => sub {
371 my ($self, $privkey) = @_; 321 my ($self, $privkey) = @_;
372 322
373 $self->txn (invert_private_key => private => $privkey); 323 $self->txn (invert_private_key => private => $privkey);
374}); 324});
375 325
378=item $length = $fcp->get_size ($uri) 328=item $length = $fcp->get_size ($uri)
379 329
380Finds and returns the size (rounded up to the nearest power of two) of the 330Finds and returns the size (rounded up to the nearest power of two) of the
381given document. 331given document.
382 332
383UNTESTED.
384
385=cut 333=cut
386 334
387$txn->(get_size => sub { 335$txn->(get_size => sub {
388 my ($self, $uri) = @_; 336 my ($self, $uri) = @_;
389 337
392 340
393=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]]) 341=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]])
394 342
395=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal) 343=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal)
396 344
397Fetches a (small, as it should fit into memory) file from 345Fetches 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 346freenet. C<$meta> is a C<Net::FCP::Metadata> object or C<undef>).
399C<undef>).
400 347
401Due to the overhead, a better method to download big files should be used. 348The C<$uri> should begin with C<freenet:>, but the scheme is currently
349added, if missing.
402 350
403 my ($meta, $data) = @{ 351 my ($meta, $data) = @{
404 $fcp->client_get ( 352 $fcp->client_get (
405 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w" 353 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w"
406 ) 354 )
409=cut 357=cut
410 358
411$txn->(client_get => sub { 359$txn->(client_get => sub {
412 my ($self, $uri, $htl, $removelocal) = @_; 360 my ($self, $uri, $htl, $removelocal) = @_;
413 361
362 $uri =~ s/^freenet://; $uri = "freenet:$uri";
363
414 $self->txn (client_get => URI => $uri, hops_to_live => (defined $htl ? $htl :15), 364 $self->txn (client_get => URI => $uri, hops_to_live => xeh (defined $htl ? $htl : 15),
415 remove_local_key => $removelocal ? "true" : "false"); 365 remove_local_key => $removelocal ? "true" : "false");
416}); 366});
417 367
418=item $txn = $fcp->txn_client_put ($uri, $metadata, $data, $htl, $removelocal) 368=item $txn = $fcp->txn_client_put ($uri, $metadata, $data, $htl, $removelocal)
419 369
420=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal); 370=item my $uri = $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal);
421 371
422Insert a new key. If the client is inserting a CHK, the URI may be 372Insert 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 373abbreviated as just CHK@. In this case, the node will calculate the
424CHK. 374CHK. If the key is a private SSK key, the node will calculcate the public
375key and the resulting public URI.
425 376
426C<$meta> can be a reference or a string (ONLY THE STRING CASE IS IMPLEMENTED!). 377C<$meta> can be a hash reference (same format as returned by
378C<Net::FCP::parse_metadata>) or a string.
427 379
428THIS INTERFACE IS UNTESTED AND SUBJECT TO CHANGE. 380The result is an arrayref with the keys C<uri>, C<public_key> and C<private_key>.
429 381
430=cut 382=cut
431 383
432$txn->(client_put => sub { 384$txn->(client_put => sub {
433 my ($self, $uri, $meta, $data, $htl, $removelocal) = @_; 385 my ($self, $uri, $metadata, $data, $htl, $removelocal) = @_;
434 386
435 $self->txn (client_put => URI => $uri, hops_to_live => (defined $htl ? $htl :15), 387 $metadata = Net::FCP::Metadata::build_metadata $metadata;
388 $uri =~ s/^freenet://; $uri = "freenet:$uri";
389
390 $self->txn (client_put => URI => $uri,
391 hops_to_live => xeh (defined $htl ? $htl : 15),
436 remove_local_key => $removelocal ? "true" : "false", 392 remove_local_key => $removelocal ? "true" : "false",
437 data => "$meta$data", metadata_length => length $meta); 393 data => "$metadata$data", metadata_length => xeh length $metadata);
438}); 394});
439 395
440} # transactions 396} # transactions
441 397
442=item MISSING: (ClientPut), InsretKey
443
444=back 398=back
445 399
446=head2 THE Net::FCP::Txn CLASS 400=head2 THE Net::FCP::Txn CLASS
447 401
448All requests (or transactions) are executed in a asynchroneous way (LIE: 402All requests (or transactions) are executed in a asynchronous way. For
449uploads are blocking). For each request, a C<Net::FCP::Txn> object is 403each request, a C<Net::FCP::Txn> object is created (worse: a tcp
450created (worse: a tcp connection is created, too). 404connection is created, too).
451 405
452For each request there is actually a different subclass (and it's possible 406For each request there is actually a different subclass (and it's possible
453to subclass these, although of course not documented). 407to subclass these, although of course not documented).
454 408
455The most interesting method is C<result>. 409The most interesting method is C<result>.
672 } 626 }
673} 627}
674 628
675sub progress { 629sub progress {
676 my ($self, $type, $attr) = @_; 630 my ($self, $type, $attr) = @_;
631
677 $self->{fcp}->progress ($self, $type, $attr); 632 $self->{fcp}->progress ($self, $type, $attr);
678} 633}
679 634
680=item $result = $txn->result 635=item $result = $txn->result
681 636
682Waits until a result is available and then returns it. 637Waits until a result is available and then returns it.
683 638
684This waiting is (depending on your event model) not very efficient, as it 639This waiting is (depending on your event model) not very efficient, as it
685is done outside the "mainloop". 640is done outside the "mainloop". The biggest problem, however, is that it's
641blocking one thread of execution. Try to use the callback mechanism, if
642possible, and call result from within the callback (or after is has been
643run), as then no waiting is necessary.
686 644
687=cut 645=cut
688 646
689sub result { 647sub result {
690 my ($self) = @_; 648 my ($self) = @_;
730 688
731use base Net::FCP::Txn; 689use base Net::FCP::Txn;
732 690
733sub rcv_success { 691sub rcv_success {
734 my ($self, $attr) = @_; 692 my ($self, $attr) = @_;
735 $self->set_result ([$attr->{PublicKey}, $attr->{PrivateKey}]); 693 $self->set_result ([$attr->{public_key}, $attr->{private_key}, $attr->{crypto_key}]);
736} 694}
737 695
738package Net::FCP::Txn::InsertPrivateKey; 696package Net::FCP::Txn::InvertPrivateKey;
739 697
740use base Net::FCP::Txn; 698use base Net::FCP::Txn;
741 699
742sub rcv_success { 700sub rcv_success {
743 my ($self, $attr) = @_; 701 my ($self, $attr) = @_;
744 $self->set_result ($attr->{PublicKey}); 702 $self->set_result ($attr->{public_key});
745} 703}
746 704
747package Net::FCP::Txn::GetSize; 705package Net::FCP::Txn::GetSize;
748 706
749use base Net::FCP::Txn; 707use base Net::FCP::Txn;
750 708
751sub rcv_success { 709sub rcv_success {
752 my ($self, $attr) = @_; 710 my ($self, $attr) = @_;
753 $self->set_result ($attr->{Length}); 711 $self->set_result (hex $attr->{length});
754} 712}
755 713
756package Net::FCP::Txn::GetPut; 714package Net::FCP::Txn::GetPut;
757 715
758# base class for get and put 716# base class for get and put
759 717
760use base Net::FCP::Txn; 718use base Net::FCP::Txn;
761 719
762*rcv_uri_error = \&Net::FCP::Txn::rcv_throw_exception; 720*rcv_uri_error = \&Net::FCP::Txn::rcv_throw_exception;
763*rcv_route_not_found = \&Net::FCP::Txn::rcv_throw_exception; 721*rcv_route_not_found = \&Net::FCP::Txn::rcv_throw_exception;
764 722
765sub rcv_restarted { 723sub rcv_restarted {
766 my ($self, $attr, $type) = @_; 724 my ($self, $attr, $type) = @_;
767 725
768 delete $self->{datalength}; 726 delete $self->{datalength};
785 743
786 $self->progress ("data", { chunk => length $chunk, received => length $self->{data}, total => $self->{datalength} }); 744 $self->progress ("data", { chunk => length $chunk, received => length $self->{data}, total => $self->{datalength} });
787 745
788 if ($self->{datalength} == length $self->{data}) { 746 if ($self->{datalength} == length $self->{data}) {
789 my $data = delete $self->{data}; 747 my $data = delete $self->{data};
790 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, ""; 748 my $meta = new Net::FCP::Metadata (substr $data, 0, $self->{metalength}, "");
791 749
792 $self->set_result ([$meta, $data]); 750 $self->set_result ([$meta, $data]);
751 $self->eof;
793 } 752 }
794} 753}
795 754
796sub rcv_data_found { 755sub rcv_data_found {
797 my ($self, $attr, $type) = @_; 756 my ($self, $attr, $type) = @_;
805package Net::FCP::Txn::ClientPut; 764package Net::FCP::Txn::ClientPut;
806 765
807use base Net::FCP::Txn::GetPut; 766use base Net::FCP::Txn::GetPut;
808 767
809*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception; 768*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception;
810*rcv_key_collision = \&Net::FCP::Txn::rcv_throw_exception;
811 769
812sub rcv_pending { 770sub rcv_pending {
813 my ($self, $attr, $type) = @_; 771 my ($self, $attr, $type) = @_;
814 $self->progress ($type, $attr); 772 $self->progress ($type, $attr);
815} 773}
817sub rcv_success { 775sub rcv_success {
818 my ($self, $attr, $type) = @_; 776 my ($self, $attr, $type) = @_;
819 $self->set_result ($attr); 777 $self->set_result ($attr);
820} 778}
821 779
780sub rcv_key_collision {
781 my ($self, $attr, $type) = @_;
782 $self->set_result ({ key_collision => 1, %$attr });
783}
784
822=back 785=back
823 786
824=head2 The Net::FCP::Exception CLASS 787=head2 The Net::FCP::Exception CLASS
825 788
826Any unexpected (non-standard) responses that make it impossible to return 789Any unexpected (non-standard) responses that make it impossible to return
835 798
836package Net::FCP::Exception; 799package Net::FCP::Exception;
837 800
838use overload 801use overload
839 '""' => sub { 802 '""' => sub {
840 "Net::FCP::Exception<<$_[0][0]," . (join ":", %{$_[0][1]}) . ">>\n"; 803 "Net::FCP::Exception<<$_[0][0]," . (join ":", %{$_[0][1]}) . ">>";
841 }; 804 };
842 805
843=item $exc = new Net::FCP::Exception $type, \%attr 806=item $exc = new Net::FCP::Exception $type, \%attr
844 807
845Create a new exception object of the given type (a string like 808Create a new exception object of the given type (a string like
900=cut 863=cut
901 864
902package Net::FCP::Event::Auto; 865package Net::FCP::Event::Auto;
903 866
904my @models = ( 867my @models = (
905 [Coro => Coro::Event:: ], 868 [Coro => Coro::Event::],
906 [Event => Event::], 869 [Event => Event::],
907 [Glib => Glib:: ], 870 [Glib => Glib::],
908 [Tk => Tk::], 871 [Tk => Tk::],
909); 872);
910 873
911sub AUTOLOAD { 874sub AUTOLOAD {
912 $AUTOLOAD =~ s/.*://; 875 $AUTOLOAD =~ s/.*://;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines