… | |
… | |
31 | package Net::FCP; |
31 | package Net::FCP; |
32 | |
32 | |
33 | use Carp; |
33 | use Carp; |
34 | use IO::Socket::INET; |
34 | use IO::Socket::INET; |
35 | |
35 | |
36 | $VERSION = 0.01; |
36 | $VERSION = 0.02; |
37 | |
37 | |
38 | sub event_reg_cb { |
38 | sub event_reg_cb { |
39 | my ($obj) = @_; |
39 | my ($obj) = @_; |
40 | require Event; |
40 | require Event; |
41 | |
41 | |
… | |
… | |
75 | } |
75 | } |
76 | |
76 | |
77 | =item $fcp = new Net::FCP [host => $host][, port => $port] |
77 | =item $fcp = new Net::FCP [host => $host][, port => $port] |
78 | |
78 | |
79 | Create a new virtual FCP connection to the given host and port (default |
79 | Create a new virtual FCP connection to the given host and port (default |
80 | 127.0.0.1:8481). |
80 | 127.0.0.1:8481, or the environment variables C<FREDHOST> and C<FREDPORT>). |
81 | |
81 | |
82 | Connections are virtual because no persistent physical connection is |
82 | Connections are virtual because no persistent physical connection is |
83 | established. However, the existance of the node is checked by executing a |
83 | established. However, the existance of the node is checked by executing a |
84 | C<ClientHello> transaction. |
84 | C<ClientHello> transaction. |
85 | |
85 | |
… | |
… | |
87 | |
87 | |
88 | sub new { |
88 | sub new { |
89 | my $class = shift; |
89 | my $class = shift; |
90 | my $self = bless { @_ }, $class; |
90 | my $self = bless { @_ }, $class; |
91 | |
91 | |
92 | $self->{host} ||= "127.0.0.1"; |
92 | $self->{host} ||= $ENV{FREDHOST} || "127.0.0.1"; |
93 | $self->{port} ||= 8481; |
93 | $self->{port} ||= $ENV{FREDPORt} || 8481; |
94 | |
94 | |
95 | $self->{nodehello} = $self->txn("ClientHello")->result |
95 | $self->{nodehello} = $self->client_hello |
96 | or croak "unable to get nodehello from node\n"; |
96 | or croak "unable to get nodehello from node\n"; |
97 | |
97 | |
98 | $self; |
98 | $self; |
99 | } |
99 | } |
100 | |
100 | |
… | |
… | |
126 | |
126 | |
127 | Executes a ClientHello request and returns it's results. |
127 | Executes a ClientHello request and returns it's results. |
128 | |
128 | |
129 | { |
129 | { |
130 | max_file_size => "5f5e100", |
130 | max_file_size => "5f5e100", |
|
|
131 | node => "Fred,0.6,1.46,7050" |
131 | protocol => "1.2", |
132 | protocol => "1.2", |
132 | node => "Fred,0.6,1.46,7050" |
|
|
133 | } |
133 | } |
134 | |
134 | |
135 | =cut |
135 | =cut |
136 | |
136 | |
137 | _txn client_hello => sub { |
137 | _txn client_hello => sub { |
… | |
… | |
145 | =item $nodeinfo = $fcp->client_info |
145 | =item $nodeinfo = $fcp->client_info |
146 | |
146 | |
147 | Executes a ClientInfo request and returns it's results. |
147 | Executes a ClientInfo request and returns it's results. |
148 | |
148 | |
149 | { |
149 | { |
150 | max_file_size => "5f5e100", |
|
|
151 | datastore_max => "2540be400", |
|
|
152 | node_port => 369, |
|
|
153 | java_name => "Java HotSpot(_T_M) Server VM", |
|
|
154 | operating_system_version => "2.4.20", |
|
|
155 | estimated_load => 52, |
|
|
156 | free_memory => "5cc0148", |
|
|
157 | datastore_free => "5ce03400", |
|
|
158 | node_address => "1.2.3.4", |
|
|
159 | active_jobs => "1f", |
150 | active_jobs => "1f", |
160 | allocated_memory => "bde0000", |
151 | allocated_memory => "bde0000", |
161 | architecture => "i386", |
152 | architecture => "i386", |
|
|
153 | available_threads => 17, |
|
|
154 | datastore_free => "5ce03400", |
|
|
155 | datastore_max => "2540be400", |
|
|
156 | datastore_used => "1f72bb000", |
|
|
157 | estimated_load => 52, |
|
|
158 | free_memory => "5cc0148", |
|
|
159 | is_transient => "false", |
|
|
160 | java_name => "Java HotSpot(_T_M) Server VM", |
|
|
161 | java_vendor => "http://www.blackdown.org/", |
|
|
162 | java_version => "Blackdown-1.4.1-01", |
|
|
163 | least_recent_timestamp => "f41538b878", |
|
|
164 | max_file_size => "5f5e100", |
|
|
165 | most_recent_timestamp => "f77e2cc520" |
|
|
166 | node_address => "1.2.3.4", |
|
|
167 | node_port => 369, |
|
|
168 | operating_system => "Linux", |
|
|
169 | operating_system_version => "2.4.20", |
162 | routing_time => "a5", |
170 | routing_time => "a5", |
163 | least_recent_timestamp => "f41538b878", |
|
|
164 | available_threads => 17, |
|
|
165 | datastore_used => "1f72bb000", |
|
|
166 | java_version => "Blackdown-1.4.1-01", |
|
|
167 | is_transient => "false", |
|
|
168 | operating_system => "Linux", |
|
|
169 | java_vendor => "http://www.blackdown.org/", |
|
|
170 | most_recent_timestamp => "f77e2cc520" |
|
|
171 | } |
171 | } |
172 | |
172 | |
173 | =cut |
173 | =cut |
174 | |
174 | |
175 | _txn client_info => sub { |
175 | _txn client_info => sub { |
… | |
… | |
246 | my ($self, $uri) = @_; |
246 | my ($self, $uri) = @_; |
247 | |
247 | |
248 | $self->txn (get_size => URI => $uri); |
248 | $self->txn (get_size => URI => $uri); |
249 | }; |
249 | }; |
250 | |
250 | |
|
|
251 | =item $txn = $fcp->txn_client_get ($uri [, $htl = 15 [, $removelocal = 0]]) |
|
|
252 | |
|
|
253 | =item ($data, $metadata) = @{ $fcp->client_get ($uri, $htl, $removelocal) |
|
|
254 | |
|
|
255 | Fetches a (small, as it should fit into memory) file from freenet. |
|
|
256 | |
|
|
257 | Due to the overhead, a better method to download big fiels should be used. |
|
|
258 | |
|
|
259 | my ($data, $meta) = @{ |
|
|
260 | $fcp->client_get ( |
|
|
261 | "freenet:CHK@hdXaxkwZ9rA8-SidT0AN-bniQlgPAwI,XdCDmBuGsd-ulqbLnZ8v~w" |
|
|
262 | ) |
|
|
263 | }; |
|
|
264 | |
|
|
265 | =cut |
|
|
266 | |
|
|
267 | _txn client_get => sub { |
|
|
268 | my ($self, $uri, $htl, $removelocal) = @_; |
|
|
269 | |
|
|
270 | $self->txn (client_get => URI => $uri, hops_to_live => ($htl || 15), remove_local => $removelocal*1); |
|
|
271 | }; |
|
|
272 | |
251 | =item MISSING: ClientGet, ClientPut |
273 | =item MISSING: ClientPut |
252 | |
274 | |
253 | =back |
275 | =back |
254 | |
276 | |
255 | =head2 THE Net::FCP::Txn CLASS |
277 | =head2 THE Net::FCP::Txn CLASS |
256 | |
278 | |
… | |
… | |
327 | |
349 | |
328 | if (sysread $self->{fh}, $self->{buf}, 65536, length $self->{buf}) { |
350 | if (sysread $self->{fh}, $self->{buf}, 65536, length $self->{buf}) { |
329 | for (;;) { |
351 | for (;;) { |
330 | if ($self->{datalen}) { |
352 | if ($self->{datalen}) { |
331 | if (length $self->{buf} >= $self->{datalen}) { |
353 | if (length $self->{buf} >= $self->{datalen}) { |
332 | $self->recv_data (substr $self->{buf}, 0, $self->{datalen}, ""); |
354 | $self->rcv_data (substr $self->{buf}, 0, $self->{datalen}, ""); |
333 | } else { |
355 | } else { |
334 | last; |
356 | last; |
335 | } |
357 | } |
336 | } elsif ($self->{buf} =~ s/^DataChunk\015?\012Length=(\d+)\015?\012Data\015?\012//) { |
358 | } elsif ($self->{buf} =~ s/^DataChunk\015?\012Length=([0-9a-fA-F]+)\015?\012Data\015?\012//) { |
337 | $self->{datalen} = $1; |
359 | $self->{datalen} = hex $1; |
338 | } elsif ($self->{buf} =~ s/^([a-zA-Z]+)\015?\012(.*?)\015?\012EndMessage\015?\012//s) { |
360 | } elsif ($self->{buf} =~ s/^([a-zA-Z]+)\015?\012(.*?)\015?\012EndMessage\015?\012//s) { |
339 | $self->rcv ($1, { |
361 | $self->rcv ($1, { |
340 | map { my ($a, $b) = split /=/, $_, 2; ((Net::FCP::tolc $a), $b) } |
362 | map { my ($a, $b) = split /=/, $_, 2; ((Net::FCP::tolc $a), $b) } |
341 | split /\015?\012/, $2 |
363 | split /\015?\012/, $2 |
342 | }); |
364 | }); |
… | |
… | |
351 | } |
373 | } |
352 | } |
374 | } |
353 | |
375 | |
354 | sub rcv_data { |
376 | sub rcv_data { |
355 | my ($self, $chunk) = @_; |
377 | my ($self, $chunk) = @_; |
|
|
378 | |
|
|
379 | $self->{data} .= $chunk; |
356 | } |
380 | } |
357 | |
381 | |
358 | sub rcv { |
382 | sub rcv { |
359 | my ($self, $type, $attr) = @_; |
383 | my ($self, $type, $attr) = @_; |
360 | |
384 | |
361 | $type = Net::FCP::tolc $type; |
385 | $type = Net::FCP::tolc $type; |
|
|
386 | |
|
|
387 | #use PApp::Util; warn PApp::Util::dumpval [$type, $attr]; |
362 | |
388 | |
363 | if (my $method = $self->can("rcv_$type")) { |
389 | if (my $method = $self->can("rcv_$type")) { |
364 | $method->($self, $attr, $type); |
390 | $method->($self, $attr, $type); |
365 | } else { |
391 | } else { |
366 | warn "received unexpected reply type '$type' for '$self->{type}', ignoring\n"; |
392 | warn "received unexpected reply type '$type' for '$self->{type}', ignoring\n"; |
367 | $self->eof; |
|
|
368 | } |
393 | } |
|
|
394 | } |
|
|
395 | |
|
|
396 | sub set_result { |
|
|
397 | my ($self, $result) = @_; |
|
|
398 | |
|
|
399 | $self->{result} = $result unless exists $self->{result}; |
369 | } |
400 | } |
370 | |
401 | |
371 | sub eof { |
402 | sub eof { |
372 | my ($self, $result) = @_; |
403 | my ($self) = @_; |
373 | |
404 | $self->set_result; |
374 | $self->{result} = $result unless exists $self->{result}; |
|
|
375 | } |
405 | } |
376 | |
406 | |
377 | =item $result = $txn->result |
407 | =item $result = $txn->result |
378 | |
408 | |
379 | Waits until a result is available and then returns it. |
409 | Waits until a result is available and then returns it. |
380 | |
410 | |
381 | This waiting is (depending on your event modul) not very efficient, as it |
411 | This waiting is (depending on your event model) not very efficient, as it |
382 | is done outside the "mainloop". |
412 | is done outside the "mainloop". |
383 | |
413 | |
384 | =cut |
414 | =cut |
385 | |
415 | |
386 | sub result { |
416 | sub result { |
… | |
… | |
400 | use base Net::FCP::Txn; |
430 | use base Net::FCP::Txn; |
401 | |
431 | |
402 | sub rcv_node_hello { |
432 | sub rcv_node_hello { |
403 | my ($self, $attr) = @_; |
433 | my ($self, $attr) = @_; |
404 | |
434 | |
405 | $self->eof ($attr); |
435 | $self->set_result ($attr); |
406 | } |
436 | } |
407 | |
437 | |
408 | package Net::FCP::Txn::ClientInfo; |
438 | package Net::FCP::Txn::ClientInfo; |
409 | |
439 | |
410 | use base Net::FCP::Txn; |
440 | use base Net::FCP::Txn; |
411 | |
441 | |
412 | sub rcv_node_info { |
442 | sub rcv_node_info { |
413 | my ($self, $attr) = @_; |
443 | my ($self, $attr) = @_; |
414 | |
444 | |
415 | $self->eof ($attr); |
445 | $self->set_result ($attr); |
416 | } |
446 | } |
417 | |
447 | |
418 | package Net::FCP::Txn::GenerateCHK; |
448 | package Net::FCP::Txn::GenerateCHK; |
419 | |
449 | |
420 | use base Net::FCP::Txn; |
450 | use base Net::FCP::Txn; |
421 | |
451 | |
422 | sub rcv_success { |
452 | sub rcv_success { |
423 | my ($self, $attr) = @_; |
453 | my ($self, $attr) = @_; |
424 | |
454 | |
425 | $self->eof ($attr); |
455 | $self->set_result ($attr); |
426 | } |
456 | } |
427 | |
457 | |
428 | package Net::FCP::Txn::GenerateSVKPair; |
458 | package Net::FCP::Txn::GenerateSVKPair; |
429 | |
459 | |
430 | use base Net::FCP::Txn; |
460 | use base Net::FCP::Txn; |
431 | |
461 | |
432 | sub rcv_success { |
462 | sub rcv_success { |
433 | my ($self, $attr) = @_; |
463 | my ($self, $attr) = @_; |
434 | |
464 | |
435 | $self->eof ([$attr->{PublicKey}, $attr->{PrivateKey}]); |
465 | $self->set_result ([$attr->{PublicKey}, $attr->{PrivateKey}]); |
436 | } |
466 | } |
437 | |
467 | |
438 | package Net::FCP::Txn::InvertPrivateKey; |
468 | package Net::FCP::Txn::InvertPrivateKey; |
439 | |
469 | |
440 | use base Net::FCP::Txn; |
470 | use base Net::FCP::Txn; |
441 | |
471 | |
442 | sub rcv_success { |
472 | sub rcv_success { |
443 | my ($self, $attr) = @_; |
473 | my ($self, $attr) = @_; |
444 | |
474 | |
445 | $self->eof ($attr->{PublicKey}); |
475 | $self->set_result ($attr->{PublicKey}); |
446 | } |
476 | } |
447 | |
477 | |
448 | package Net::FCP::Txn::GetSize; |
478 | package Net::FCP::Txn::GetSize; |
449 | |
479 | |
450 | use base Net::FCP::Txn; |
480 | use base Net::FCP::Txn; |
451 | |
481 | |
452 | sub rcv_success { |
482 | sub rcv_success { |
453 | my ($self, $attr) = @_; |
483 | my ($self, $attr) = @_; |
454 | |
484 | |
455 | $self->eof ($attr->{Length}); |
485 | $self->set_result ($attr->{Length}); |
|
|
486 | } |
|
|
487 | |
|
|
488 | package Net::FCP::Txn::ClientGet; |
|
|
489 | |
|
|
490 | use base Net::FCP::Txn; |
|
|
491 | |
|
|
492 | sub rcv_data_found { |
|
|
493 | my ($self, $attr) = @_; |
|
|
494 | |
|
|
495 | $self->{datalength} = hex $attr->{data_length}; |
|
|
496 | $self->{metalength} = hex $attr->{meta_data_length}; |
|
|
497 | } |
|
|
498 | |
|
|
499 | sub eof { |
|
|
500 | my ($self) = @_; |
|
|
501 | #use PApp::Util; warn PApp::Util::dumpval $self; |
|
|
502 | my $data = delete $self->{data}; |
|
|
503 | $self->set_result ([ |
|
|
504 | (substr $data, 0, $self->{datalength}-$self->{metalength}), |
|
|
505 | (substr $data, $self->{datalength}-$self->{metalength}), |
|
|
506 | ]); |
456 | } |
507 | } |
457 | |
508 | |
458 | =back |
509 | =back |
459 | |
510 | |
460 | =head1 SEE ALSO |
511 | =head1 SEE ALSO |