[freenet-cvs] r12505 - in trunk/apps/perlFreenet: . Freenet

alexlehm at freenetproject.org alexlehm at freenetproject.org
Sun Apr 1 00:50:14 UTC 2007


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";




More information about the cvs mailing list