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.29 by root, Thu May 13 21:43:16 2004 UTC vs.
Revision 1.35 by root, Thu Mar 3 17:31:26 2005 UTC

72 72
73package Net::FCP; 73package Net::FCP;
74 74
75use Carp; 75use Carp;
76 76
77$VERSION = 0.6; 77$VERSION = 0.8;
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 1 while s/(SVK|CHK|URI)([^_])/$1\_$2/i;
105 1 while s/([^_])(SVK|CHK|URI)/$1\_$2/i;
106 s/(?<=[a-z])(?=[A-Z])/_/g;
107 lc $_;
108}
109
110# the opposite of hex
111sub xeh($) {
112 sprintf "%x", $_[0];
113}
114
115=item $meta = Net::FCP::parse_metadata $string
116
117Parse a metadata string and return it.
118
119The metadata will be a hashref with key C<version> (containing the
120mandatory version header entries) and key C<raw> containing the original
121metadata string.
122
123All other headers are represented by arrayrefs (they can be repeated).
124
125Since this description is confusing, here is a rather verbose example of a
126parsed manifest:
127
128 (
129 raw => "Version...",
130 version => { revision => 1 },
131 document => [
132 {
133 info => { format" => "image/jpeg" },
134 name => "background.jpg",
135 redirect => { target => "freenet:CHK\@ZcagI,ra726bSw" },
136 },
137 {
138 info => { format" => "text/html" },
139 name => ".next",
140 redirect => { target => "freenet:SSK\@ilUPAgM/TFEE/3" },
141 },
142 {
143 info => { format" => "text/html" },
144 redirect => { target => "freenet:CHK\@8M8Po8ucwI,8xA" },
145 }
146 ]
147 )
148
149=cut
150
151sub parse_metadata {
152 my $data = shift;
153 my $meta = { raw => $data };
154
155 if ($data =~ /^Version\015?\012/gc) {
156 my $hdr = $meta->{version} = {};
157
158 for (;;) {
159 while ($data =~ /\G([^=\015\012]+)=([^\015\012]*)\015?\012/gc) {
160 my ($k, $v) = ($1, $2);
161 my @p = split /\./, tolc $k, 3;
162
163 $hdr->{$p[0]} = $v if @p == 1; # lamest code I ever wrote
164 $hdr->{$p[0]}{$p[1]} = $v if @p == 2;
165 $hdr->{$p[0]}{$p[1]}{$p[2]} = $v if @p == 3;
166 die "FATAL: 4+ dot metadata" if @p >= 4;
167 }
168
169 if ($data =~ /\GEndPart\015?\012/gc) {
170 # nop
171 } elsif ($data =~ /\GEnd(\015?\012|$)/gc) {
172 last;
173 } elsif ($data =~ /\G([A-Za-z0-9.\-]+)\015?\012/gcs) {
174 push @{$meta->{tolc $1}}, $hdr = {};
175 } elsif ($data =~ /\G(.*)/gcs) {
176 print STDERR "metadata format error ($1), please report this string: <<$data>>";
177 die "metadata format error";
178 }
179 }
180 }
181
182 #$meta->{tail} = substr $data, pos $data;
183
184 $meta;
185}
186
187=item $string = Net::FCP::build_metadata $meta
188
189Takes a hash reference as returned by C<Net::FCP::parse_metadata> and
190returns the corresponding string form. If a string is given, it's returned
191as is.
192
193=cut
194
195sub build_metadata_subhash($$$) {
196 my ($prefix, $level, $hash) = @_;
197
198 join "",
199 map
200 ref $hash->{$_} ? build_metadata_subhash ($prefix . (Net::FCP::touc $_) . ".", $level + 1, $hash->{$_})
201 : $prefix . ($level > 1 ? $_ : Net::FCP::touc $_) . "=" . $hash->{$_} . "\n",
202 keys %$hash;
203}
204
205sub build_metadata_hash($$) {
206 my ($header, $hash) = @_;
207
208 if (ref $hash eq ARRAY::) {
209 join "", map build_metadata_hash ($header, $_), @$hash
210 } else {
211 (Net::FCP::touc $header) . "\n"
212 . (build_metadata_subhash "", 0, $hash)
213 . "EndPart\n";
214 }
215}
216
217sub build_metadata($) {
218 my ($meta) = @_;
219
220 return $meta unless ref $meta;
221
222 $meta = { %$meta };
223
224 delete $meta->{raw};
225
226 my $res =
227 (build_metadata_hash version => delete $meta->{version})
228 . (join "", map +(build_metadata_hash $_, $meta->{$_}), keys %$meta);
229
230 substr $res, 0, -5; # get rid of "Part". Broken Syntax....
231}
232
233
234=item $fcp = new Net::FCP [host => $host][, port => $port][, progress => \&cb] 98=item $fcp = new Net::FCP [host => $host][, port => $port][, progress => \&cb]
235 99
236Create 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
237127.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>).
238 102
247 my ($self, $txn, $type, $attr) = @_; 111 my ($self, $txn, $type, $attr) = @_;
248 112
249 warn "progress<$txn,$type," . (join ":", %$attr) . ">\n"; 113 warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
250 } 114 }
251 115
252=begin comment
253
254However, the existance of the node is checked by executing a
255C<ClientHello> transaction.
256
257=end
258
259=cut 116=cut
260 117
261sub new { 118sub new {
262 my $class = shift; 119 my $class = shift;
263 my $self = bless { @_ }, $class; 120 my $self = bless { @_ }, $class;
264 121
265 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1"; 122 $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1";
266 $self->{port} ||= $ENV{FREDPORT} || 8481; 123 $self->{port} ||= $ENV{FREDPORT} || 8481;
267 124
268 #$self->{nodehello} = $self->client_hello
269 # or croak "unable to get nodehello from node\n";
270
271 $self; 125 $self;
272} 126}
273 127
274sub progress { 128sub progress {
275 my ($self, $txn, $type, $attr) = @_; 129 my ($self, $txn, $type, $attr) = @_;
276 130
277 $self->{progress}->($self, $txn, $type, $attr) 131 $self->{progress}->($self, $txn, $type, $attr)
278 if $self->{progress}; 132 if $self->{progress};
279} 133}
280 134
281=item $txn = $fcp->txn(type => attr => val,...) 135=item $txn = $fcp->txn (type => attr => val,...)
282 136
283The low-level interface to transactions. Don't use it. 137The low-level interface to transactions. Don't use it unless you have
284 138"special needs". Instead, use predefiend transactions like this:
285Here are some examples of using transactions:
286 139
287The blocking case, no (visible) transactions involved: 140The blocking case, no (visible) transactions involved:
288 141
289 my $nodehello = $fcp->client_hello; 142 my $nodehello = $fcp->client_hello;
290 143
392=cut 245=cut
393 246
394$txn->(generate_chk => sub { 247$txn->(generate_chk => sub {
395 my ($self, $metadata, $data, $cipher) = @_; 248 my ($self, $metadata, $data, $cipher) = @_;
396 249
250 $metadata = Net::FCP::Metadata::build_metadata $metadata;
251
397 $self->txn (generate_chk => 252 $self->txn (generate_chk =>
398 data => "$metadata$data", 253 data => "$metadata$data",
399 metadata_length => xeh length $metadata, 254 metadata_length => xeh length $metadata,
400 cipher => $cipher || "Twofish"); 255 cipher => $cipher || "Twofish");
401}); 256});
402 257
403=item $txn = $fcp->txn_generate_svk_pair 258=item $txn = $fcp->txn_generate_svk_pair
404 259
405=item ($public, $private) = @{ $fcp->generate_svk_pair } 260=item ($public, $private, $crypto) = @{ $fcp->generate_svk_pair }
406 261
407Creates a new SVK pair. Returns an arrayref with the public key, the 262Creates a new SVK pair. Returns an arrayref with the public key, the
408private key and a crypto key, which is just additional entropy. 263private key and a crypto key, which is just additional entropy.
409 264
410 [ 265 [
466 321
467=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]]) 322=item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]])
468 323
469=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal) 324=item ($metadata, $data) = @{ $fcp->client_get ($uri, $htl, $removelocal)
470 325
471Fetches a (small, as it should fit into memory) file from 326Fetches a (small, as it should fit into memory) key content block from
472freenet. 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>).
473C<undef>).
474 328
475The C<$uri> should begin with C<freenet:>, but the scheme is currently 329The C<$uri> should begin with C<freenet:>, but the scheme is currently
476added, if missing. 330added, if missing.
477
478Due to the overhead, a better method to download big files should be used.
479 331
480 my ($meta, $data) = @{ 332 my ($meta, $data) = @{
481 $fcp->client_get ( 333 $fcp->client_get (
482 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w" 334 "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w"
483 ) 335 )
486=cut 338=cut
487 339
488$txn->(client_get => sub { 340$txn->(client_get => sub {
489 my ($self, $uri, $htl, $removelocal) = @_; 341 my ($self, $uri, $htl, $removelocal) = @_;
490 342
491 $uri =~ s/^freenet://; 343 $uri =~ s/^freenet://; $uri = "freenet:$uri";
492 $uri = "freenet:$uri";
493 344
494 $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),
495 remove_local_key => $removelocal ? "true" : "false"); 346 remove_local_key => $removelocal ? "true" : "false");
496}); 347});
497 348
510The result is an arrayref with the keys C<uri>, C<public_key> and C<private_key>. 361The result is an arrayref with the keys C<uri>, C<public_key> and C<private_key>.
511 362
512=cut 363=cut
513 364
514$txn->(client_put => sub { 365$txn->(client_put => sub {
515 my ($self, $uri, $meta, $data, $htl, $removelocal) = @_; 366 my ($self, $uri, $metadata, $data, $htl, $removelocal) = @_;
516 367
517 $meta = build_metadata $meta; 368 $metadata = Net::FCP::Metadata::build_metadata $metadata;
369 $uri =~ s/^freenet://; $uri = "freenet:$uri";
518 370
519 $self->txn (client_put => URI => $uri, 371 $self->txn (client_put => URI => $uri,
520 hops_to_live => xeh (defined $htl ? $htl : 15), 372 hops_to_live => xeh (defined $htl ? $htl : 15),
521 remove_local_key => $removelocal ? "true" : "false", 373 remove_local_key => $removelocal ? "true" : "false",
522 data => "$meta$data", metadata_length => xeh length $meta); 374 data => "$metadata$data", metadata_length => xeh length $metadata);
523}); 375});
524 376
525} # transactions 377} # transactions
526 378
527=back 379=back
590 442
591 #shutdown $fh, 1; # freenet buggy?, well, it's java... 443 #shutdown $fh, 1; # freenet buggy?, well, it's java...
592 444
593 $self->{fh} = $fh; 445 $self->{fh} = $fh;
594 446
595 $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);
596 450
597 $self; 451 $self;
598} 452}
599 453
600=item $txn = $txn->cb ($coderef) 454=item $txn = $txn->cb ($coderef)
636 $self; 490 $self;
637} 491}
638 492
639=item $txn->cancel (%attr) 493=item $txn->cancel (%attr)
640 494
641Cancels the operation with a C<cancel> exception anf the given attributes 495Cancels the operation with a C<cancel> exception and the given attributes
642(consider at least giving the attribute C<reason>). 496(consider at least giving the attribute C<reason>).
643 497
644UNTESTED. 498UNTESTED.
645 499
646=cut 500=cut
872 726
873 $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} });
874 728
875 if ($self->{datalength} == length $self->{data}) { 729 if ($self->{datalength} == length $self->{data}) {
876 my $data = delete $self->{data}; 730 my $data = delete $self->{data};
877 my $meta = Net::FCP::parse_metadata substr $data, 0, $self->{metalength}, ""; 731 my $meta = new Net::FCP::Metadata (substr $data, 0, $self->{metalength}, "");
878 732
879 $self->set_result ([$meta, $data]); 733 $self->set_result ([$meta, $data]);
880 $self->eof; 734 $self->eof;
881 } 735 }
882} 736}
893package Net::FCP::Txn::ClientPut; 747package Net::FCP::Txn::ClientPut;
894 748
895use base Net::FCP::Txn::GetPut; 749use base Net::FCP::Txn::GetPut;
896 750
897*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception; 751*rcv_size_error = \&Net::FCP::Txn::rcv_throw_exception;
898*rcv_key_collision = \&Net::FCP::Txn::rcv_throw_exception;
899 752
900sub rcv_pending { 753sub rcv_pending {
901 my ($self, $attr, $type) = @_; 754 my ($self, $attr, $type) = @_;
902 $self->progress ($type, $attr); 755 $self->progress ($type, $attr);
903} 756}
904 757
905sub rcv_success { 758sub rcv_success {
906 my ($self, $attr, $type) = @_; 759 my ($self, $attr, $type) = @_;
907 $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 });
908} 766}
909 767
910=back 768=back
911 769
912=head2 The Net::FCP::Exception CLASS 770=head2 The Net::FCP::Exception CLASS
980 838
981=head1 BUGS 839=head1 BUGS
982 840
983=head1 AUTHOR 841=head1 AUTHOR
984 842
985 Marc Lehmann <pcg@goof.com> 843 Marc Lehmann <schmorp@schmorp.de>
986 http://www.goof.com/pcg/marc/ 844 http://home.schmorp.de/
987 845
988=cut 846=cut
989 847
990package Net::FCP::Event::Auto; 848package Net::FCP::Event::Auto;
991 849

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines