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.32 by root, Fri May 14 17:25:17 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# 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
677 } 607 }
678} 608}
679 609
680sub progress { 610sub progress {
681 my ($self, $type, $attr) = @_; 611 my ($self, $type, $attr) = @_;
612
682 $self->{fcp}->progress ($self, $type, $attr); 613 $self->{fcp}->progress ($self, $type, $attr);
683} 614}
684 615
685=item $result = $txn->result 616=item $result = $txn->result
686 617
738 669
739use base Net::FCP::Txn; 670use base Net::FCP::Txn;
740 671
741sub rcv_success { 672sub rcv_success {
742 my ($self, $attr) = @_; 673 my ($self, $attr) = @_;
743 $self->set_result ([$attr->{PublicKey}, $attr->{PrivateKey}]); 674 $self->set_result ([$attr->{public_key}, $attr->{private_key}, $attr->{crypto_key}]);
744} 675}
745 676
746package Net::FCP::Txn::InsertPrivateKey; 677package Net::FCP::Txn::InvertPrivateKey;
747 678
748use base Net::FCP::Txn; 679use base Net::FCP::Txn;
749 680
750sub rcv_success { 681sub rcv_success {
751 my ($self, $attr) = @_; 682 my ($self, $attr) = @_;
752 $self->set_result ($attr->{PublicKey}); 683 $self->set_result ($attr->{public_key});
753} 684}
754 685
755package Net::FCP::Txn::GetSize; 686package Net::FCP::Txn::GetSize;
756 687
757use base Net::FCP::Txn; 688use base Net::FCP::Txn;
758 689
759sub rcv_success { 690sub rcv_success {
760 my ($self, $attr) = @_; 691 my ($self, $attr) = @_;
761 $self->set_result (hex $attr->{Length}); 692 $self->set_result (hex $attr->{length});
762} 693}
763 694
764package Net::FCP::Txn::GetPut; 695package Net::FCP::Txn::GetPut;
765 696
766# base class for get and put 697# base class for get and put
767 698
768use base Net::FCP::Txn; 699use base Net::FCP::Txn;
769 700
770*rcv_uri_error = \&Net::FCP::Txn::rcv_throw_exception; 701*rcv_uri_error = \&Net::FCP::Txn::rcv_throw_exception;
771*rcv_route_not_found = \&Net::FCP::Txn::rcv_throw_exception; 702*rcv_route_not_found = \&Net::FCP::Txn::rcv_throw_exception;
772 703
773sub rcv_restarted { 704sub rcv_restarted {
774 my ($self, $attr, $type) = @_; 705 my ($self, $attr, $type) = @_;
775 706
776 delete $self->{datalength}; 707 delete $self->{datalength};
793 724
794 $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} });
795 726
796 if ($self->{datalength} == length $self->{data}) { 727 if ($self->{datalength} == length $self->{data}) {
797 my $data = delete $self->{data}; 728 my $data = delete $self->{data};
798 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, ""; 729 my $meta = new Net::FCP::Metadata (substr $data, 0, $self->{metalength}, "");
799 730
800 $self->set_result ([$meta, $data]); 731 $self->set_result ([$meta, $data]);
801 $self->eof; 732 $self->eof;
802 } 733 }
803} 734}
814package Net::FCP::Txn::ClientPut; 745package Net::FCP::Txn::ClientPut;
815 746
816use base Net::FCP::Txn::GetPut; 747use base Net::FCP::Txn::GetPut;
817 748
818*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception; 749*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception;
819*rcv_key_collision = \&Net::FCP::Txn::rcv_throw_exception;
820 750
821sub rcv_pending { 751sub rcv_pending {
822 my ($self, $attr, $type) = @_; 752 my ($self, $attr, $type) = @_;
823 $self->progress ($type, $attr); 753 $self->progress ($type, $attr);
824} 754}
825 755
826sub rcv_success { 756sub rcv_success {
827 my ($self, $attr, $type) = @_; 757 my ($self, $attr, $type) = @_;
828 $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 });
829} 764}
830 765
831=back 766=back
832 767
833=head2 The Net::FCP::Exception CLASS 768=head2 The Net::FCP::Exception CLASS
909=cut 844=cut
910 845
911package Net::FCP::Event::Auto; 846package Net::FCP::Event::Auto;
912 847
913my @models = ( 848my @models = (
914 [Coro => Coro::Event:: ], 849 [Coro => Coro::Event::],
915 [Event => Event::], 850 [Event => Event::],
916 [Glib => Glib:: ], 851 [Glib => Glib::],
917 [Tk => Tk::], 852 [Tk => Tk::],
918); 853);
919 854
920sub AUTOLOAD { 855sub AUTOLOAD {
921 $AUTOLOAD =~ s/.*://; 856 $AUTOLOAD =~ s/.*://;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines