Author: alexlehm
Date: 2007-04-01 00:50:14 +0000 (Sun, 01 Apr 2007)
New Revision: 12505

Added:
   trunk/apps/perlFreenet/Freenet/
   trunk/apps/perlFreenet/Freenet/Connection.pm
   trunk/apps/perlFreenet/Freenet/Message.pm
   trunk/apps/perlFreenet/README
   trunk/apps/perlFreenet/perlfn.pl
   trunk/apps/perlFreenet/putcomplexdir.pl
Log:
initial commit, added README

Added: trunk/apps/perlFreenet/Freenet/Connection.pm
===================================================================
--- trunk/apps/perlFreenet/Freenet/Connection.pm                                
(rev 0)
+++ trunk/apps/perlFreenet/Freenet/Connection.pm        2007-04-01 00:50:14 UTC 
(rev 12505)
@@ -0,0 +1,196 @@
+package Freenet::Connection;
+
+use Freenet::Message;
+use IO::socket::INET;
+
+sub new {
+  my $class = shift;
+  my $self = {};
+  bless $self, $class;
+  $self->initialize(@_);
+  return $self;
+}
+
+# we expect a hash with options, right now we only use Node
+# and Client
+#
+# you can use a string with the node hostname
+# or nothing at all
+# Node defaults to hostname:9481
+# or to localhost:9481 if nothing is given.
+# Client name defaults to perlfn, but please choose a sensible name
+# since you can only connect with each client name once
+
+sub initialize
+{
+  my $self = shift;
+  my $options = shift;
+
+       my $node;
+       my $socket;
+       my $clientname;
+       my $debug=0;
+
+       if(defined($options)) {
+               if(ref($options)) {
+                       $node=$options->{Node} || "localhost";
+                       $clientname=$options->{Client};
+                       $debug=$options->{Debug} || 0;
+               } else {
+                       # assume it's a string otherwise
+                       $node=$options;
+               }
+       }
+       
+       $node||="localhost";
+       $clientname||="perlfn";
+
+       # TODO: does this work with IPv6?
+       if($node !~ /:\d+$/) {
+         $node.=":9481";
+       }
+
+  $self->{node}=$node;
+  $self->{clientname}=$clientname;
+  $self->{debug}=$debug;
+  $self->{socket}=undef;
+}
+
+sub debug
+{
+  return shift->{debug};
+}
+
+sub connect
+{
+       my $self=shift;
+
+       # connect to the node
+       $socket=IO::Socket::INET->new(PeerAddr => $self->{node});
+
+       if(!$socket) {
+               # failed for some reason TODO: should wrap this is a proper 
error?
+               return undef;
+       }
+
+  $self->debug && print "connected to ".$self->{node}."\n";
+
+  $self->{socket}=$socket;
+
+  # now send a ClientHello
+       $msg=Freenet::Message->new("ClientHello", 
+               {
+                       ExpectedVersion => "2.0",
+                 Name => $self->{clientname},
+               }
+       );
+
+       if(!($self->sendmessage($msg))) {
+               return undef;
+       }
+       $response=$self->getmessage();
+
+  # TODO: keep node's features somewhere so we can use it later
+
+  return $response;
+}
+
+sub getmessage
+{
+  my $self=shift;
+
+  my $socket=$self->{socket};
+
+  my $message;
+  my $headers;
+  my $data;
+
+       $_=<$socket>;
+       chomp;
+  $self->debug && print "<$_\n";
+
+  $message=$_;
+
+  while(1) {
+    $_=<$socket>;
+    if($_ eq "") {
+      warn "read empty message from socket, probably the socket was closed by 
the node\n";
+      return undef;
+    }
+    chomp;
+    $self->debug && print "<$_\n";
+    last if /^EndMessage$/;
+    last if /^Data$/;
+    my($k,$v)=split(/=/,$_,2);
+    $headers->{$k}=$v;
+  }
+
+  if(/^Data$/) {
+    # handle data after message headers
+    my($dl)=$headers->{DataLength};
+    if(!defined($dl)) {
+      warn "warning: Message ends with Data line, but no DataLength. We will 
probably break afterwards\n";
+    } else {
+         $self->debug && print "<data follows\n";
+       read($socket,$data,$dl);
+         $self->debug && print "<read data\n";
+    }
+  }
+
+  my($res)=Freenet::Message->new($message, $headers);
+  if(defined($data)) {
+    $res->{data}=$data;
+  }
+
+  return $res;
+}
+
+sub sendmessage
+{
+       my($self)=shift;
+  my($msg)=shift;
+  if(!ref($msg)) {
+    # assume the parameters are the same as for Message->new
+    $msg=Freenet::Message->new($msg,shift);
+  }
+  my $sock=$self->{socket};
+
+  if(!ref($msg) eq "Freenet::Message") {
+    warn "wrong argument type\n";
+  }
+
+  print $sock $msg->message,"\n";
+  $self->debug && print ">".$msg->message."\n";
+
+  foreach my $k (keys(%{$msg->header})) {
+       my($h)=$msg->header($k);
+    print $sock "$k=$h\n";
+    $self->debug && print ">$k=$h\n";
+  }
+
+  print $sock "EndMessage\n";
+  $self->debug && print ">EndMessage\n";
+
+  if(defined($msg->data)) {
+       $self->debug && print ">data follows\n";
+    print $sock $msg->data;
+       $self->debug && print ">wrote data\n";
+  }
+
+  return 1;
+}
+
+sub disconnect
+{
+  my $self=shift;
+  my $ret;
+
+  $ret=close($self->{socket});
+  $self->{socket}=undef;
+
+  $self->debug && print "client disconnected\n";
+
+  return $ret;
+}
+
+1;

Added: trunk/apps/perlFreenet/Freenet/Message.pm
===================================================================
--- trunk/apps/perlFreenet/Freenet/Message.pm                           (rev 0)
+++ trunk/apps/perlFreenet/Freenet/Message.pm   2007-04-01 00:50:14 UTC (rev 
12505)
@@ -0,0 +1,67 @@
+package Freenet::Message;
+
+sub new {
+    my $class = shift;
+    my $self = {};
+    bless $self, $class;
+    $self->initialize(@_);
+    return $self;
+}
+
+sub initialize
+{
+    my $self = shift;
+
+    $self->{data}=undef;
+    $self->{message}=shift;
+    # if we don't have header field, you can just leave them out
+    # e.g. ->new("ShutDown");
+    $self->{header}=shift || {};
+}
+
+# TODO: how can these be assigned to?
+sub data
+{
+  return shift->{data};
+}
+
+# TODO: should this be called "name" or "messagename"?
+sub message
+{
+       return shift->{message};
+}
+
+# get header hash ref or one header
+
+sub header
+{
+       my($self)=shift;
+       if(int(@_)==0) {
+    return $self->{header};
+       } else {
+               my $k=shift;
+    return $self->{header}->{$k};
+       }
+}
+
+# as_string is useful for debugging, returns the complete message ending
+# with either EndMessage or Data
+
+sub as_string
+{
+       my($self)=shift;
+       
+       my($s)=$self->message."\n";
+       foreach my $k (keys(%{$self->header})) {
+         $s.=$k."=".$self->header($k)."\n";
+       }
+       if(defined($self->data)) {
+               # ignore the data field for now
+         $s.="Data\n";
+       } else {
+         $s.="EndMessage\n";
+  }
+       return $s;
+}
+
+1;

Added: trunk/apps/perlFreenet/README
===================================================================
--- trunk/apps/perlFreenet/README                               (rev 0)
+++ trunk/apps/perlFreenet/README       2007-04-01 00:50:14 UTC (rev 12505)
@@ -0,0 +1,24 @@
+Perl support for Freenet
+
+This is still very preliminary, you can connect to the server and 
send/received 
+messages including data. Some examples are in perlfn.pl and in 
putcomplexdir.pl.
+
+There is no support for waiting for or polling messages yet, so longer 
+operations will probably not work and you cannot start more than one operation 
+unless you take care of sorting the progress messages yourself.
+
+Right now there is no Makefile.PL nor PPM, you can either keep the Freenet 
+directory in your local dir or copy them to lib/perl/<version>/
+
+There are quite a few things missing, e.g. Perldoc.
+
+Until now, I have used the library under Windows only (Vista and XP) with 
+ActiveState Perl 5.8.8, it should work under Linux as well, but this is yet 
+untested.
+
+For feedback about the code, please use devel at P7LnnR2qMOTZdYbBa_teC92vTLQ 
in 
+[MAILBOX] or use the bug tracker at https://bugs.freenetproject.org/ 
+(perlFreenet)
+
+Thats all for now, I'll leave you to finding your own bugs ...
+

Added: trunk/apps/perlFreenet/perlfn.pl
===================================================================
--- trunk/apps/perlFreenet/perlfn.pl                            (rev 0)
+++ trunk/apps/perlFreenet/perlfn.pl    2007-04-01 00:50:14 UTC (rev 12505)
@@ -0,0 +1,125 @@
+#! perl
+
+use Data::Dumper;
+use File::Slurp;
+
+use Freenet::Message;
+use Freenet::Connection;
+
+$node=Freenet::Connection->new({Node => 'localhost', Client=>'perl 
testclient', Debug=>1});
+($nodehello=$node->connect) || warn "connect failed\n";
+
+if($nodehello->message ne "NodeHello") {
+  warn "something went wrong, got ".$nodehello->message." instead of 
NodeHello\n";
+}
+
+# get uptime
+$node->sendmessage("GetNode", {WithVolatile => 'true'});
+$nodedata=$node->getmessage;
+$uptime=$nodedata->header("volatile.uptimeSeconds")/3600.0;
+print "uptime $uptime hours\n";
+
+# get a list of peer node names
+
+$node->sendmessage("ListPeers",
+       {
+               WithVolatile => 'true',
+               WithMetadata => 'true',
+       }
+);
+
+while(1) {
+       my($msg)=$node->getmessage;
+  if($msg->message eq "Peer") {
+       $myName=$msg->header(myName);
+       $status=$msg->header("volatile.status");
+       print "$myName $status\n";
+  }
+       last if $msg->message eq "EndListPeers";
+};
+
+$node->sendmessage("ClientGet",
+       {
+         IgnoreDS=>"false",
+         DSOnly=>"false",
+         URI=>'USK at 
Aegl9hc-9O2-VMpXBYuxwuj9JAoMDdXHlNjGst1hLD8,xJTwS8hLh5Uv-20UbH9Mp64nnfqjbGkTDaUlo4EPr9M,AQACAAE/fn_rrd/2/activelink.png',
+         Identifier=>"Request Number One",
+         Verbosity=>0,
+         ReturnType=>"direct",
+         MaxSize=>1000000,
+         MaxTempSize=>1000000,
+         MaxRetries=>100,
+         PriorityClass=>1,
+         Persistence=>"connection",
+         ClientToken=>"hello",
+         Global=>"false",
+       }
+);
+
+my($msg)=$node->getmessage;
+print $msg->as_string;
+
+if($msg->message ne "DataFound") {
+       die "didn't get the expected message (got ".$msg->message.")\n";
+}
+
+# from the wiki documentation I thought you have to do GetRequestStatus after
+# DataFound, but apparently the file is returned directly afterwards
+
+#$node->sendmessage(Freenet::Message->new("GetRequestStatus",
+#{
+#  Identifier=>"Request Number One",
+#  Global=>"true",
+#  OnlyData=>"false",
+#}
+#));
+
+$msg=$node->getmessage;
+print $msg->as_string;
+
+print "retrieved file size ".length($msg->data),"\n";
+
+write_file("test.png", {binmode => ':raw' }, $msg->data);
+
+$node->sendmessage("GenerateSSK", {Identifier=>"My Identifier Blah Blah"});
+print $node->getmessage->as_string;
+
+# shut down node (you probably dont want to do this is a test script)
+
+#$node->sendmessage("Shutdown");
+#print $node->getmessage->as_string;
+
+# get CHK of a known file
+
+# have to create the message beforehand since we have to add data element
+
+$msg=Freenet::Message->new("ClientPut",
+       {
+
+               URI=>"CHK@",
+               "Metadata.ContentType"=>"text/pdf",
+               Identifier=>"My Test File",
+               Verbosity=>"0",
+               MaxRetries=>"10",
+               PriorityClass=>"1",
+               GetCHKOnly=>"true",
+               Global=>"false",
+               DontCompress=>"true",
+               ClientToken=>"Hello!!!",
+               UploadFrom=>"direct",
+               TargetFilename=>"document.pdf",
+       }
+);
+
+$data=read_file("c:/document.pdf",{binmode => ':raw'});
+
+$msg->{data}=$data;
+$msg->{header}->{DataLength}=length($data);
+
+$node->sendmessage($msg);
+
+my($msg)=$node->getmessage;
+print $msg->as_string;
+
+$node->disconnect || warn "disconnect failed\n";
+

Added: trunk/apps/perlFreenet/putcomplexdir.pl
===================================================================
--- trunk/apps/perlFreenet/putcomplexdir.pl                             (rev 0)
+++ trunk/apps/perlFreenet/putcomplexdir.pl     2007-04-01 00:50:14 UTC (rev 
12505)
@@ -0,0 +1,55 @@
+#! perl
+
+use Data::Dumper;
+use File::Slurp;
+
+use Freenet::Message;
+use Freenet::Connection;
+
+$node=Freenet::Connection->new({Node => '192.168.178.20', Client=>'perl 
putcomplexdir', Debug=>1});
+($nodehello=$node->connect) || warn "connect failed\n";
+
+if($nodehello->message ne "NodeHello") {
+  warn "something went wrong, got ".$nodehello->message." instread of 
NodeHello\n";
+}
+
+$file0=read_file("index.html");
+$file1=read_file("foo.zip",{binmode=>':raw'});
+$file2=read_file("doc.pdf",{binmode=>':raw'});
+
+$msg=Freenet::Message->new("ClientPutComplexDir",
+       {
+               Identifier=>"My Test Dir Insert",
+               Verbosity=>1023,
+               MaxRetries=>999,
+               PriorityClass=>2,
+               URI=>'CHK@',
+               GetCHKOnly=>"false",
+               DontCompress=>"false",
+               ClientToken=>"My Client Token",
+               Persistence=>"connection",
+               Global=>"false",
+               DefaultName=>"index.html",
+               "Files.0.Name"=>"index.html",
+               "Files.0.UploadFrom"=>"direct",
+               "Files.0.Metadata.ContentType"=>"text/html",
+               "Files.0.DataLength"=>length($file0),
+               "Files.1.Name"=>"foo.zip",
+               "Files.1.UploadFrom"=>"direct",
+               "Files.1.Metadata.ContentType"=>"application/zip",
+               "Files.1.DataLength"=>length($file1),
+               "Files.2.Name"=>"doc.pdf",
+               "Files.2.UploadFrom"=>"direct",
+               "Files.2.Metadata.ContentType"=>"application/pdf",
+               "Files.2.DataLength"=>length($file2),
+       }
+);
+
+$msg->{data}=$file0.$file1.$file2;
+
+$node->sendmessage($msg);
+
+while(1) {
+  my($msg)=$node->getmessage;
+}
+$node->disconnect || warn "disconnect failed\n";


Reply via email to