fclient-commit Mailing List for fclient (Page 29)
Status: Pre-Alpha
Brought to you by:
jurner
You can subscribe to this list here.
| 2007 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(23) |
Nov
(54) |
Dec
|
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2008 |
Jan
(17) |
Feb
(209) |
Mar
(63) |
Apr
(31) |
May
(7) |
Jun
(39) |
Jul
(390) |
Aug
(122) |
Sep
(6) |
Oct
|
Nov
|
Dec
|
|
From: <ju...@us...> - 2008-02-26 10:17:57
|
Revision: 262
http://fclient.svn.sourceforge.net/fclient/?rev=262&view=rev
Author: jurner
Date: 2008-02-26 02:18:02 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
...
Removed Paths:
-------------
trunk/web/download-fcp.html
trunk/web/more-fcp.html
trunk/web/screenshots-fcp.html
Deleted: trunk/web/download-fcp.html
===================================================================
--- trunk/web/download-fcp.html 2008-02-26 10:17:25 UTC (rev 261)
+++ trunk/web/download-fcp.html 2008-02-26 10:18:02 UTC (rev 262)
@@ -1,21 +0,0 @@
-<html>
- <head>
- <link rel="StyleSheet" href="default.css" type="text/css" media="screen">
- </head>
- <body>
-
- <div class="navHeader">
- <a class="navRef" href="intro.html" target="mainFrame">fclient</a><span class="navRef">::download-fcp</span>
- </div>
-
-
- <div class="topic">
- <br>
- <br>
- Nothing to see here, move along
- </div>
-
- <div class="bottom_padding"></div>
- </body>
-</html>
-
Deleted: trunk/web/more-fcp.html
===================================================================
--- trunk/web/more-fcp.html 2008-02-26 10:17:25 UTC (rev 261)
+++ trunk/web/more-fcp.html 2008-02-26 10:18:02 UTC (rev 262)
@@ -1,84 +0,0 @@
-<html>
- <head>
- <link rel="StyleSheet" href="default.css" type="text/css" media="screen">
- </head>
- <body>
-
- <div class="navHeader">
- <a class="navRef" href="intro.html" target="mainFrame">fclient</a><span class="navRef">::more-fcp</span>
- </div>
-
-
- <div class="topic">
- <b>fcp:</b> high level wrapper for the freenet client protocol written in python. Automatic
- conversions from Fcp to python types, access to node and peer configurations.
-
- <br>
- Blah more here
- </div>
-
- <h5>Sample code:</h5>
-
-
-Connect to the freenet node
-<pre class="py_code">client <span class="py_operator">=</span> FcpClient()
-nodeHello <span class="py_operator">=</span> client.connect()
-<span class="py_keyword">if</span> nodeHello <span class="py_keyword">is</span> <span class="py_bool">None</span>:
- <span class="py_keyword">pass</span>
- <span class="py_comment"># something went wrong ..could not connect to the freenet node</span>
-<span class="py_keyword">else</span>:
- <span class="py_keyword">pass</span>
- <span class="py_comment"># everything went well ..we are connected now</span>
-</pre>
-
-Request data associated to a freenet key
-<pre class="py_code">myRequestIdentifier <span class="py_operator">=</span> client.getData(<span class="py_string2">'CHK@ABCDE.......'</span>)
-myRequest <span class="py_operator">=</span> client.getRequest(myIdentifier)
-client.run()
-<span class="py_keyword">print</span> myRequest.data
-</pre>
-
-
-Usually you would connect handlers to client events to do processing or handle errors
-<pre class="py_code"><span class="py_keyword">def</span> handleSuccess(event, request):
- <span class="py_keyword">print</span> <span class="py_string2">'Here is the data:'</span>, request.data
-
-<span class="py_keyword">def</span> handleFailure(event, request):
- <span class="py_keyword">print</span> <span class="py_string2">'Too bad, something went wrong'</span>
-
-client.events.RequestCompleted <span class="py_operator">+</span><span class="py_operator">=</span> handleSuccess
-client.events.RequestFailed <span class="py_operator">+</span><span class="py_operator">=</span> handleFailure
-
-client.getData(<span class="py_string2">'CHK@ABCDE.......'</span>)
-client.run()
-</pre>
-
-Instead of calling run() you may run the client step by step
-<pre class="py_code">client.getData(<span class="py_string2">'CHK@ABCDE.......'</span>)
-<span class="py_keyword">for</span> i <span class="py_keyword">in</span> xrange(50):
- client.next()
-</pre>
-
-You may disconnect event handlers aswel
-<pre class="py_code">client.events.RequestCompleted <span class="py_operator">-</span><span class="py_operator">=</span> handleSuccess
-client.events.RequestFailed <span class="py_operator">-</span><span class="py_operator">=</span> handleFailure
-</pre>
-
-Multiple event handlers may be connected / disconnected at once
-<pre class="py_code">client.events <span class="py_operator">+</span><span class="py_operator">=</span> (
- (client.events.RequestCompleted, handleSuccess),
- (client.events.RequestFailed, handleFailure)
- )
-</pre>
-
-
-
-To generate extensive documentation run the package through [<a href="http://epydoc.sourceforge.net/">epydoc</a>].
-To make things a bit simpler script <span class="hilight">gen_docs.py</span> located in the
-<span class="hilight">scripts</span> subdirectory of the package wich will dump docs automatically to the
-packages <span class="hilight">doc</span> folder.
-
-
- <div class="bottom_padding"></div>
- </body>
-</html>
\ No newline at end of file
Deleted: trunk/web/screenshots-fcp.html
===================================================================
--- trunk/web/screenshots-fcp.html 2008-02-26 10:17:25 UTC (rev 261)
+++ trunk/web/screenshots-fcp.html 2008-02-26 10:18:02 UTC (rev 262)
@@ -1,21 +0,0 @@
-<html>
- <head>
- <link rel="StyleSheet" href="default.css" type="text/css" media="screen">
- </head>
- <body>
-
- <div class="navHeader">
- <a class="navRef" href="intro.html" target="mainFrame">fclient</a><span class="navRef">::screenshots-fcp</span>
- </div>
-
-
- <div class="topic">
- <br>
- <br>
- Nothing to see here, move along
- </div>
-
-
- <div class="bottom_padding"></div>
- </body>
-</html>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-26 10:17:20
|
Revision: 261
http://fclient.svn.sourceforge.net/fclient/?rev=261&view=rev
Author: jurner
Date: 2008-02-26 02:17:25 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
...
Modified Paths:
--------------
trunk/web/default.css
trunk/web/index.html
trunk/web/intro.html
Modified: trunk/web/default.css
===================================================================
--- trunk/web/default.css 2008-02-26 10:08:38 UTC (rev 260)
+++ trunk/web/default.css 2008-02-26 10:17:25 UTC (rev 261)
@@ -11,10 +11,9 @@
div.body{
border: solid;
border-width: 0.1em;
- border-color: #C7E9D3;
+ border-color: black;
height: auto;
}
-
td.frame{
border: solid;
border-width: 0.1em;
Modified: trunk/web/index.html
===================================================================
--- trunk/web/index.html 2008-02-26 10:08:38 UTC (rev 260)
+++ trunk/web/index.html 2008-02-26 10:17:25 UTC (rev 261)
@@ -24,9 +24,12 @@
Your browser does not seem to support iframes. Some links for quick navigation
<br>
<a href="intro.html">Intro</a><br>
- <a href="fclient-more.html">fclient</a><br>
- <a href="fcp-more.html">fcp</a><br>
-
+ <a href="download-fclient.html">fclient</a><br>
+ <a href="download-fcp2.html">fcp</a><br>
+ <a href="more-fclient.html">fclient</a><br>
+ <a href="more-fcp2.html">fcp</a><br>
+ <a href="screenshots-fclient.html">fclient</a><br>
+ <a href="screenshots-fcp2.html">fcp</a><br>
</iframe>
</td>
</tr>
Modified: trunk/web/intro.html
===================================================================
--- trunk/web/intro.html 2008-02-26 10:08:38 UTC (rev 260)
+++ trunk/web/intro.html 2008-02-26 10:17:25 UTC (rev 261)
@@ -18,10 +18,10 @@
<div class="topic">
- <b>fcp:</b> high level wrapper for the freenet client protocol written in python. Automatic
+ <b>fcp2:</b> high level wrapper for the freenet client protocol version-2 written in python. Automatic
conversions from Fcp to python types, access to node and peer configurations and more
<br>
- [<a href="more-fcp.html" target="mainFrame">..More</a>] [<a href="download-fcp.html" target="mainFrame">Download</a>] [<a href="screenshots-fcp.html" target="mainFrame">Screenshots</a>]
+ [<a href="more-fcp2.html" target="mainFrame">..More</a>] [<a href="download-fcp2.html" target="mainFrame">Download</a>] [<a href="screenshots-fcp2.html" target="mainFrame">Screenshots</a>]
</div>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-26 10:08:41
|
Revision: 260
http://fclient.svn.sourceforge.net/fclient/?rev=260&view=rev
Author: jurner
Date: 2008-02-26 02:08:38 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
adapt to renames
Modified Paths:
--------------
trunk/sandbox/fcp2/boards/frost.py
Modified: trunk/sandbox/fcp2/boards/frost.py
===================================================================
--- trunk/sandbox/fcp2/boards/frost.py 2008-02-26 10:07:03 UTC (rev 259)
+++ trunk/sandbox/fcp2/boards/frost.py 2008-02-26 10:08:38 UTC (rev 260)
@@ -2,15 +2,15 @@
import os, sys, time
#--> rel import hack
-class SysPathHack(object):
+class _RelImportHack(object):
def __init__(self, n):
fpath = os.path.abspath(__file__)
for i in xrange(n): fpath = os.path.dirname(fpath)
sys.path.insert(0, fpath)
def __del__(self): sys.path.pop(0)
-hack = SysPathHack(2)
+hack = _RelImportHack(3)
-from fcp2_0_client import FcpClient
+from fcp2.client import Client
del hack
@@ -18,7 +18,7 @@
#**********************************************************************
#
#**********************************************************************
-#c = FcpClient()
+#c = Client()
#c.connect()
@@ -48,7 +48,7 @@
def __init__(self):
- self.fcpClient = FcpClient(debugVerbosity=FcpClient.consts.DebugVerbosity.Debug)
+ self.fcpClient = Client(debugVerbosity=Client.consts.DebugVerbosity.Debug)
nodeHello = self.fcpClient.connect()
if nodeHello is None:
return False
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-26 10:07:00
|
Revision: 259
http://fclient.svn.sourceforge.net/fclient/?rev=259&view=rev
Author: jurner
Date: 2008-02-26 02:07:03 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
renamed FcpClient to Client
Modified Paths:
--------------
trunk/sandbox/fcp2/test_fcp/test_client.py
trunk/sandbox/fcp2/test_fcp/test_config.py
trunk/sandbox/fcp2/test_fcp/test_message.py
Modified: trunk/sandbox/fcp2/test_fcp/test_client.py
===================================================================
--- trunk/sandbox/fcp2/test_fcp/test_client.py 2008-02-26 10:06:56 UTC (rev 258)
+++ trunk/sandbox/fcp2/test_fcp/test_client.py 2008-02-26 10:07:03 UTC (rev 259)
@@ -18,7 +18,7 @@
hack = _RelImportHack(3)
from fcp2 import client
-from fcp2.client import FcpClient
+from fcp2.client import Client
from fcp2 import consts
@@ -35,15 +35,15 @@
#***********************************************************************************
#
#***********************************************************************************
-class MyFcpClient(FcpClient):
+class MyFcpClient(Client):
"""Customized client recording all messages it sends
"""
def __init__(self, *args, **kwargs):
- FcpClient.__init__(self, *args, **kwargs)
+ Client.__init__(self, *args, **kwargs)
self.test_messagesSend = []
def sendMessageEx(self, msg):
- FcpClient.sendMessageEx(self, msg)
+ Client.sendMessageEx(self, msg)
# deepcopy here, we need exact state
msg = copy.deepcopy(msg)
self.test_messagesSend.append(msg)
Modified: trunk/sandbox/fcp2/test_fcp/test_config.py
===================================================================
--- trunk/sandbox/fcp2/test_fcp/test_config.py 2008-02-26 10:06:56 UTC (rev 258)
+++ trunk/sandbox/fcp2/test_fcp/test_config.py 2008-02-26 10:07:03 UTC (rev 259)
@@ -13,8 +13,8 @@
def __del__(self): sys.path.pop(0)
hack = _RelImportHack(3)
-from fcp2.client import FcpClient
-Message = FcpClient.Message
+from fcp2.client import Client
+Message = Client.Message
from fcp2 import types
del hack
@@ -35,7 +35,7 @@
'default.console.enabled': 'false',
}
- cfg = FcpClient.Config(Msg)
+ cfg = Client.Config(Msg)
# check if all items and values have been set as expected
consoleItem = cfg.children.get('console', None)
Modified: trunk/sandbox/fcp2/test_fcp/test_message.py
===================================================================
--- trunk/sandbox/fcp2/test_fcp/test_message.py 2008-02-26 10:06:56 UTC (rev 258)
+++ trunk/sandbox/fcp2/test_fcp/test_message.py 2008-02-26 10:07:03 UTC (rev 259)
@@ -13,8 +13,8 @@
def __del__(self): sys.path.pop(0)
hack = _RelImportHack(3)
-from fcp2.client import FcpClient
-Message = FcpClient.Message
+from fcp2.client import Client
+Message =Client.Message
from fcp2 import consts
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-26 10:06:52
|
Revision: 258
http://fclient.svn.sourceforge.net/fclient/?rev=258&view=rev
Author: jurner
Date: 2008-02-26 02:06:56 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
renamed FcpClient to Client
Modified Paths:
--------------
trunk/sandbox/fcp2/client.py
Modified: trunk/sandbox/fcp2/client.py
===================================================================
--- trunk/sandbox/fcp2/client.py 2008-02-26 10:01:29 UTC (rev 257)
+++ trunk/sandbox/fcp2/client.py 2008-02-26 10:06:56 UTC (rev 258)
@@ -215,7 +215,7 @@
#*************************************************************************************************
#
#*************************************************************************************************
-class FcpClient(object):
+class Client(object):
"""
@ivar events: events the client supports
"""
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-26 10:01:24
|
Revision: 257
http://fclient.svn.sourceforge.net/fclient/?rev=257&view=rev
Author: jurner
Date: 2008-02-26 02:01:29 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
adjusted package imports
Modified Paths:
--------------
trunk/sandbox/fcp2/client.py
trunk/sandbox/fcp2/config.py
trunk/sandbox/fcp2/events.py
trunk/sandbox/fcp2/message.py
trunk/sandbox/fcp2/params.py
trunk/sandbox/fcp2/scripts/gen_docs.py
trunk/sandbox/fcp2/scripts/gen_messagecheatsheet.py
trunk/sandbox/fcp2/test_fcp/test_client.py
trunk/sandbox/fcp2/test_fcp/test_config.py
trunk/sandbox/fcp2/test_fcp/test_message.py
trunk/sandbox/fcp2/types.py
trunk/sandbox/fcp2/uri.py
Modified: trunk/sandbox/fcp2/client.py
===================================================================
--- trunk/sandbox/fcp2/client.py 2008-02-26 09:52:41 UTC (rev 256)
+++ trunk/sandbox/fcp2/client.py 2008-02-26 10:01:29 UTC (rev 257)
@@ -197,15 +197,15 @@
hack = _RelImportHack(2)
-import fcp.fcp2_0_consts as consts
-from fcp.fcp2_0_events import Events
-from fcp.fcp2_0_config import Config
-from fcp.fcp2_0_message import Message
-import fcp.fcp2_0_params as FcParams
-from fcp.fcp2_0_uri import Uri
+from fcp2 import consts
+from fcp2.config import Config
+from fcp2.events import Events
+from fcp2.message import Message
+import fcp2.params as FcParams
+from fcp2.uri import Uri
-from fcp.fcp_lib import namespace
-from fcp.fcp_lib import tools
+from fcp2.fcp_lib import namespace
+from fcp2.fcp_lib import tools
del hack
Modified: trunk/sandbox/fcp2/config.py
===================================================================
--- trunk/sandbox/fcp2/config.py 2008-02-26 09:52:41 UTC (rev 256)
+++ trunk/sandbox/fcp2/config.py 2008-02-26 10:01:29 UTC (rev 257)
@@ -12,9 +12,9 @@
def __del__(self): sys.path.pop(0)
hack = _RelImportHack(2)
-from fcp import fcp2_0_consts as consts
-from fcp import fcp2_0_types as types
-from fcp.fcp_lib import uuid
+from fcp2 import consts
+from fcp2 import types
+from fcp2.fcp_lib import uuid
del hack
Modified: trunk/sandbox/fcp2/events.py
===================================================================
--- trunk/sandbox/fcp2/events.py 2008-02-26 09:52:41 UTC (rev 256)
+++ trunk/sandbox/fcp2/events.py 2008-02-26 10:01:29 UTC (rev 257)
@@ -13,8 +13,8 @@
def __del__(self): sys.path.pop(0)
hack = _RelImportHack(2)
-from fcp import fcp2_0_types as types
-from fcp.fcp_lib import events
+from fcp2 import types
+from fcp2.fcp_lib import events
del hack
Modified: trunk/sandbox/fcp2/message.py
===================================================================
--- trunk/sandbox/fcp2/message.py 2008-02-26 09:52:41 UTC (rev 256)
+++ trunk/sandbox/fcp2/message.py 2008-02-26 10:01:29 UTC (rev 257)
@@ -13,9 +13,9 @@
def __del__(self): sys.path.pop(0)
hack = _RelImportHack(2)
-from fcp import fcp2_0_consts as consts
-from fcp import fcp2_0_types as types
-from fcp.fcp_lib import uuid
+from fcp2 import consts
+from fcp2 import types
+from fcp2.fcp_lib import uuid
del hack
Modified: trunk/sandbox/fcp2/params.py
===================================================================
--- trunk/sandbox/fcp2/params.py 2008-02-26 09:52:41 UTC (rev 256)
+++ trunk/sandbox/fcp2/params.py 2008-02-26 10:01:29 UTC (rev 257)
@@ -13,7 +13,7 @@
def __del__(self): sys.path.pop(0)
hack = _RelImportHack(2)
-from fcp.fcp_lib import uuid
+from fcp2.fcp_lib import uuid
del hack
Modified: trunk/sandbox/fcp2/scripts/gen_docs.py
===================================================================
--- trunk/sandbox/fcp2/scripts/gen_docs.py 2008-02-26 09:52:41 UTC (rev 256)
+++ trunk/sandbox/fcp2/scripts/gen_docs.py 2008-02-26 10:01:29 UTC (rev 257)
@@ -21,7 +21,7 @@
def __del__(self): sys.path.pop(0)
hack = _RelImportHack(3)
-from fcp.scripts import fcpscripts_consts as consts
+from fcp2.scripts import fcpscripts_consts as consts
del hack
Modified: trunk/sandbox/fcp2/scripts/gen_messagecheatsheet.py
===================================================================
--- trunk/sandbox/fcp2/scripts/gen_messagecheatsheet.py 2008-02-26 09:52:41 UTC (rev 256)
+++ trunk/sandbox/fcp2/scripts/gen_messagecheatsheet.py 2008-02-26 10:01:29 UTC (rev 257)
@@ -32,7 +32,7 @@
def __del__(self): sys.path.pop(0)
hack = _RelImportHack(3)
-from fcp.scripts import fcpscripts_consts as consts
+from fcp2.scripts import fcpscripts_consts as consts
del hack
Modified: trunk/sandbox/fcp2/test_fcp/test_client.py
===================================================================
--- trunk/sandbox/fcp2/test_fcp/test_client.py 2008-02-26 09:52:41 UTC (rev 256)
+++ trunk/sandbox/fcp2/test_fcp/test_client.py 2008-02-26 10:01:29 UTC (rev 257)
@@ -17,9 +17,9 @@
def __del__(self): sys.path.pop(0)
hack = _RelImportHack(3)
-from fcp import fcp2_0_client
-from fcp.fcp2_0_client import FcpClient
-from fcp import fcp2_0_consts as consts
+from fcp2 import client
+from fcp2.client import FcpClient
+from fcp2 import consts
del hack
@@ -123,7 +123,7 @@
# inject our customized socket module
socketModule = DummySocketModule()
- fcp2_0_client.socket = socketModule
+ client.socket = socketModule
def __init__(self, *args, **kwargs):
Modified: trunk/sandbox/fcp2/test_fcp/test_config.py
===================================================================
--- trunk/sandbox/fcp2/test_fcp/test_config.py 2008-02-26 09:52:41 UTC (rev 256)
+++ trunk/sandbox/fcp2/test_fcp/test_config.py 2008-02-26 10:01:29 UTC (rev 257)
@@ -13,9 +13,9 @@
def __del__(self): sys.path.pop(0)
hack = _RelImportHack(3)
-from fcp.fcp2_0_client import FcpClient
+from fcp2.client import FcpClient
Message = FcpClient.Message
-from fcp import fcp2_0_types as types
+from fcp2 import types
del hack
#<-- rel import hack
Modified: trunk/sandbox/fcp2/test_fcp/test_message.py
===================================================================
--- trunk/sandbox/fcp2/test_fcp/test_message.py 2008-02-26 09:52:41 UTC (rev 256)
+++ trunk/sandbox/fcp2/test_fcp/test_message.py 2008-02-26 10:01:29 UTC (rev 257)
@@ -13,9 +13,9 @@
def __del__(self): sys.path.pop(0)
hack = _RelImportHack(3)
-from fcp.fcp2_0_client import FcpClient
+from fcp2.client import FcpClient
Message = FcpClient.Message
-from fcp import fcp2_0_consts as consts
+from fcp2 import consts
del hack
Modified: trunk/sandbox/fcp2/types.py
===================================================================
--- trunk/sandbox/fcp2/types.py 2008-02-26 09:52:41 UTC (rev 256)
+++ trunk/sandbox/fcp2/types.py 2008-02-26 10:01:29 UTC (rev 257)
@@ -15,8 +15,8 @@
def __del__(self): sys.path.pop(0)
hack =_RelImportHack(2)
-from fcp import fcp2_0_consts as consts
-from fcp.fcp_lib import numbers
+from fcp2 import consts
+from fcp2.fcp_lib import numbers
del hack
Modified: trunk/sandbox/fcp2/uri.py
===================================================================
--- trunk/sandbox/fcp2/uri.py 2008-02-26 09:52:41 UTC (rev 256)
+++ trunk/sandbox/fcp2/uri.py 2008-02-26 10:01:29 UTC (rev 257)
@@ -14,10 +14,9 @@
def __del__(self): sys.path.pop(0)
hack = _RelImportHack(2)
+from fcp2 import consts
-from fcp import fcp2_0_consts as consts
-
del hack
#<-- rel import hack
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-26 09:52:38
|
Revision: 256
http://fclient.svn.sourceforge.net/fclient/?rev=256&view=rev
Author: jurner
Date: 2008-02-26 01:52:41 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
renames
Removed Paths:
-------------
trunk/sandbox/fcp/
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-26 09:51:02
|
Revision: 255
http://fclient.svn.sourceforge.net/fclient/?rev=255&view=rev
Author: jurner
Date: 2008-02-26 01:50:39 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
renames
Added Paths:
-----------
trunk/sandbox/fcp2/
trunk/sandbox/fcp2/__init__.py
trunk/sandbox/fcp2/boards/frost.py
trunk/sandbox/fcp2/client.py
trunk/sandbox/fcp2/config.py
trunk/sandbox/fcp2/consts.py
trunk/sandbox/fcp2/events.py
trunk/sandbox/fcp2/fcp_lib/events.py
trunk/sandbox/fcp2/fcp_lib/namespace.py
trunk/sandbox/fcp2/fcp_lib/numbers.py
trunk/sandbox/fcp2/fcp_lib/tools.py
trunk/sandbox/fcp2/message.py
trunk/sandbox/fcp2/params.py
trunk/sandbox/fcp2/scripts/
trunk/sandbox/fcp2/scripts/gen_docs.py
trunk/sandbox/fcp2/scripts/gen_messagecheatsheet.py
trunk/sandbox/fcp2/test_fcp/client.py
trunk/sandbox/fcp2/test_fcp/dummy_socket.py
trunk/sandbox/fcp2/test_fcp/test_all.py
trunk/sandbox/fcp2/test_fcp/test_client.py
trunk/sandbox/fcp2/test_fcp/test_config.py
trunk/sandbox/fcp2/test_fcp/test_message.py
trunk/sandbox/fcp2/types.py
trunk/sandbox/fcp2/uri.py
Removed Paths:
-------------
trunk/sandbox/fcp2/001.py
trunk/sandbox/fcp2/__init__.py
trunk/sandbox/fcp2/boards/frost.py
trunk/sandbox/fcp2/fcp2_0_client.py
trunk/sandbox/fcp2/fcp2_0_config.py
trunk/sandbox/fcp2/fcp2_0_consts.py
trunk/sandbox/fcp2/fcp2_0_message.py
trunk/sandbox/fcp2/fcp2_0_params.py
trunk/sandbox/fcp2/fcp2_0_uri.py
trunk/sandbox/fcp2/fcp_lib/events.py
trunk/sandbox/fcp2/fcp_lib/namespace.py
trunk/sandbox/fcp2/fcp_lib/numbers.py
trunk/sandbox/fcp2/oo1.py
trunk/sandbox/fcp2/scripts/gen_docs.py
trunk/sandbox/fcp2/scripts/gen_messagecheatsheet.py
trunk/sandbox/fcp2/test_fcp/dummy_socket.py
trunk/sandbox/fcp2/test_fcp/dummy_socket.pyc
trunk/sandbox/fcp2/test_fcp/test_fcp2_0_client.py
trunk/sandbox/fcp2/test_fcp/test_fcp2_0_config.py
trunk/sandbox/fcp2/test_fcp/test_fcp2_0_message.py
Copied: trunk/sandbox/fcp2 (from rev 79, trunk/sandbox/fcp)
Deleted: trunk/sandbox/fcp2/001.py
===================================================================
--- trunk/sandbox/fcp/001.py 2008-01-27 02:16:50 UTC (rev 79)
+++ trunk/sandbox/fcp2/001.py 2008-02-26 09:50:39 UTC (rev 255)
@@ -1,107 +0,0 @@
-
-import random
-import uuid
-#*********************************************************************************************
-#
-#*********************************************************************************************
-def validateFcpBool(value):
- if value in ('true', 'false'):
- return value
- return None
-
-def validateFloat(value):
- try:
- return float(value)
- except ValueError:
- return None
-
-def validateInt(value):
- try:
- return int(value)
- except ValueError:
- return None
-
-def validateUuid(value):
- result = uuid.UUID_EXACT_MATCH_PAT.match(value)
- if result:
- return result.group(0)
- return None
-
-#*********************************************************************************************
-#
-#*********************************************************************************************
-FcParamsSep = '\x01'
-
-FcParams = (
- ('FcSubType', validateInt),
- ('FcInitTime', validateFloat), # can not take it from uuid cos requests may be resend multiple times
- ('FcHandleCollisions', validateFcpBool),
- ('FcCollisionHandled', validateFcpBool),
- ('FcRequestIdentifier', validateUuid),
- ('FcRandomBytes', validateInt),
- )
-
-
-ISubType = 0
-IRequestIdentifier = 1
-IInitTime = 2
-IHandleCollisions = 3
-ICollisionHandled = 4
-IRandomBytes = 5
-
-def paramsFromRequest(msg):
- """
-
- >>> params = [1, 123.456, 'false', 'false', uuid.uuid_time(), 123456789]
- >>> identifier = FcParamsSep.join( [str(i) for i in params] )
- >>> result = paramsFromRequest({'Identifier': identifier})
- >>> result == params
- True
-
- """
- identifier = msg.get('Identifier', None)
- if identifier is None:
- return None
-
- params = identifier.split(FcParamsSep)
- if len(params) != len(FcParams):
- return None
-
- for i, (paramName, paramValidator) in enumerate(FcParams):
- result = paramValidator(params[i])
- if result is None:
- return None
- params[i] = result
-
- return params
-
-def identifierFromRequest(msg):
- """
-
- >>> msg = {'FcSubType':1, 'FcInitTime':1.234, 'FcHandleCollisions':'false', 'FcCollisionHandled':'flase', 'FcRequestIdentifier':uuid.uuid_time(), 'FcRandomBytes':1234567879}
- >>> identifierFromRequest(msg)
-
- """
-
-
- params = []
- for paramName, paramValidator in FcParams:
- params.append(msg[paramName])
-
- params[-1] = random.getrandbits(32) # add some random bits to be able to
- # handle IdentifierCollisions(FcRequestIdentifier
- # remains the same, identifier kown to node changes)
-
- return FcParamsSep.join( [str(i) for i in params] )
-
-
-s = '1\x011.234\x01false\x01flase\x01{fc0125cc-c76f-11dc-9099-fce464f183f6}\x011234567879'
-print len(s)
-#*********************************************************************************
-#
-#*********************************************************************************
-if __name__ == '__main__2':
- import doctest
- doctest.testmod()
-
-
Deleted: trunk/sandbox/fcp2/__init__.py
===================================================================
--- trunk/sandbox/fcp/__init__.py 2008-01-27 02:16:50 UTC (rev 79)
+++ trunk/sandbox/fcp2/__init__.py 2008-02-26 09:50:39 UTC (rev 255)
@@ -1,11 +0,0 @@
-"""Python wrapper for the freenet client protocol
-
-See: [http://www.freenetproject.org]
-"""
-
-
-__author__ = 'Juergen Urner'
-__copyright__ = '(c) 2008 - Juergen Urner'
-__emeil__ = 'jue...@go...'
-__licence__ = 'Mit'
-__version__ = '0.1'
\ No newline at end of file
Copied: trunk/sandbox/fcp2/__init__.py (from rev 241, trunk/sandbox/fcp/__init__.py)
===================================================================
--- trunk/sandbox/fcp2/__init__.py (rev 0)
+++ trunk/sandbox/fcp2/__init__.py 2008-02-26 09:50:39 UTC (rev 255)
@@ -0,0 +1,17 @@
+"""Python wrapper for the freenet client protocol
+
+See: [http://www.freenetproject.org] and [http://wiki.freenetproject.org/FreenetFCPSpec2Point0]
+"""
+
+
+__author__ = 'Juergen Urner'
+__copyright__ = '(c) 2008 - Juergen Urner'
+__email__ = 'jue...@ar...'
+__licence__ = 'Mit'
+__version__ = '0.1'
+
+#****************************************************************************************
+#
+#****************************************************************************************
+def getFcpClient():
+ pass
Deleted: trunk/sandbox/fcp2/boards/frost.py
===================================================================
--- trunk/sandbox/fcp/boards/frost.py 2008-01-27 02:16:50 UTC (rev 79)
+++ trunk/sandbox/fcp2/boards/frost.py 2008-02-26 09:50:39 UTC (rev 255)
@@ -1,99 +0,0 @@
-
-import os, sys, time
-
-#--> rel import hack
-class SysPathHack(object):
- def __init__(self, n):
- fpath = os.path.abspath(__file__)
- for i in xrange(n): fpath = os.path.dirname(fpath)
- sys.path.insert(0, fpath)
- def __del__(self): sys.path.pop(0)
-hack = SysPathHack(2)
-
-from fcp2_0_client import FcpClient
-
-
-del hack
-#<-- rel import hack
-#**********************************************************************
-#
-#**********************************************************************
-#c = FcpClient()
-#c.connect()
-
-
-
-#KSK@frost|message|news|*currentDate*-*boardName*-*slot*.xml
-
-class FrostDate(object):
-
- def __init__(self, year, month, day):
- self.year = year
- self.month = month
- self.day = day
-
- @classmethod
- def now(clss):
- t = time.gmtime(time.time())
- instance = clss(t.tm_year, t.tm_mon, t.tm_mday)
- return instance
-
- def toString(self):
- return '%s.%s.%s' % (self.year, self.month, self.day)
-
-
-
-
-class FrostBoard(object):
-
- def __init__(self):
-
- self.fcpClient = FcpClient(debugVerbosity=FcpClient.DebugVerbosity.Debug)
- for nodeHello in self.fcpClient.connect():
- pass
- self.fcpClient.events.RequestCompleted += self.handleRequestCompleted
-
-
- def handleRequestCompleted(self, event, request):
-
- self.fcpClient.removeRequest(request['Identifier'])
- print request['FcData']
-
-
-
- def readBoard(self, boardName, section, startDate=None):
-
- slot = -1
- while True:
- slot += 1
- if slot > 30: break
-
- ksk = 'KSK@frost|message|%s|%s-%s-%s.xml' % (section, startDate.toString(), boardName, slot)
- print ksk
-
- self.fcpClient.getData(
- uri=ksk,
- maxSize='33000'
- )
-
- for i in xrange(300):
- self.fcpClient.next()
-
-
-
-
-board = FrostBoard()
-
-
-t = FrostDate.now()
-print t.toString()
-
-board.readBoard('de.freenet', 'news', FrostDate.now())
-
-
-
-
-
-
-
-
Copied: trunk/sandbox/fcp2/boards/frost.py (from rev 200, trunk/sandbox/fcp/boards/frost.py)
===================================================================
--- trunk/sandbox/fcp2/boards/frost.py (rev 0)
+++ trunk/sandbox/fcp2/boards/frost.py 2008-02-26 09:50:39 UTC (rev 255)
@@ -0,0 +1,101 @@
+
+import os, sys, time
+
+#--> rel import hack
+class SysPathHack(object):
+ def __init__(self, n):
+ fpath = os.path.abspath(__file__)
+ for i in xrange(n): fpath = os.path.dirname(fpath)
+ sys.path.insert(0, fpath)
+ def __del__(self): sys.path.pop(0)
+hack = SysPathHack(2)
+
+from fcp2_0_client import FcpClient
+
+
+del hack
+#<-- rel import hack
+#**********************************************************************
+#
+#**********************************************************************
+#c = FcpClient()
+#c.connect()
+
+
+
+#KSK@frost|message|news|*currentDate*-*boardName*-*slot*.xml
+
+class FrostDate(object):
+
+ def __init__(self, year, month, day):
+ self.year = year
+ self.month = month
+ self.day = day
+
+ @classmethod
+ def now(clss):
+ t = time.gmtime(time.time())
+ instance = clss(t.tm_year, t.tm_mon, t.tm_mday)
+ return instance
+
+ def toString(self):
+ return '%s.%s.%s' % (self.year, self.month, self.day)
+
+
+
+
+class FrostBoard(object):
+
+ def __init__(self):
+
+ self.fcpClient = FcpClient(debugVerbosity=FcpClient.consts.DebugVerbosity.Debug)
+ nodeHello = self.fcpClient.connect()
+ if nodeHello is None:
+ return False
+
+ self.fcpClient.events.RequestCompleted += self.handleRequestCompleted
+
+
+ def handleRequestCompleted(self, event, request):
+
+ #self.fcpClient.removeRequest(request['Identifier'])
+ print request.data
+
+
+
+ def readBoard(self, boardName, section, startDate=None):
+
+ slot = -1
+ while True:
+ slot += 1
+ if slot > 10: break
+
+ ksk = 'KSK@frost|message|%s|%s-%s-%s.xml' % (section, startDate.toString(), boardName, slot)
+ print ksk
+
+ self.fcpClient.getData(
+ uri=ksk,
+ maxSize='33000'
+ )
+
+ for i in xrange(50):
+ self.fcpClient.next()
+
+
+
+if __name__ == '__main__':
+ board = FrostBoard()
+
+
+ t = FrostDate.now()
+ print t.toString()
+
+ board.readBoard('de.freenet', 'news', FrostDate.now())
+
+
+
+
+
+
+
+
Copied: trunk/sandbox/fcp2/client.py (from rev 254, trunk/sandbox/fcp/client.py)
===================================================================
--- trunk/sandbox/fcp2/client.py (rev 0)
+++ trunk/sandbox/fcp2/client.py 2008-02-26 09:50:39 UTC (rev 255)
@@ -0,0 +1,2307 @@
+"""Freenet client protocol 2.0 implementation
+
+Compatibility: >= Freenet 0.7 Build #1107
+
+
+@newfield event: Event, Events
+@newfield requestparam: RequestParam, RequestParams
+
+@note: The client implementation never uses or watches the global queue. No implementation
+should ever do so. Global is evil.
+@note: the client is not thread save.
+
+
+Sample code. Connect to the freenet node::
+ client = FcpClient()
+ nodeHello = client.connect()
+ if nodeHello is None:
+ pass
+ # something went wrong ..could not connect to the freenet node
+ else:
+ pass
+ # everything went well ..we are connected now
+
+Request data associated to a freenet key::
+ myRequestIdentifier = client.getData('CHK@ABCDE.......')
+ myRequest = c.getRequest(myIdentifier)
+ client.run()
+ print myRequest.data
+
+Usually you would connect handlers to client events to do processing or handle errors::
+ def handleSuccess(event, request):
+ print 'Here is the data:', request.data
+
+ def handleFailure(event, request):
+ print 'Too bad, something went wrong'
+
+ client.events.RequestCompleted += handleSuccess
+ client.events.RequestFailed += handleFailure
+
+ client.getData('CHK@ABCDE.......')
+ c.run()
+
+
+Instead of calling run() you may run the client step by step::
+ client.getData('CHK@ABCDE.......')
+ for i in xrange(50):
+ client.next()
+
+
+You may disconnect event handlers aswell::
+
+ client.events.RequestCompleted -= handleSuccess
+ client.events.RequestFailed -= handleFailure
+
+
+Multiple event handlers may be connected / disconnected at once::
+
+ client.events += (
+ (client.events.RequestCompleted, handleSuccess),
+ (client.events.RequestFailed, handleFailure)
+ )
+
+
+"""
+
+#Bug reports filed and open:
+#--------------------------------------------------------------------------------------------------------------------------------------------
+# [0001931: Send EndListPersistentRequests following client connect]
+#
+# PendingRequests currently get lost if a.) the node goes down b.) if the client goes down unexpectedly.
+# This affects IdentifierCollision + FilenameCollision + ClientPut when a SSK needs to be created first
+#
+# we can handle this case none short of maintaining a file keeping messages. But still there is the
+# problem of knowing when the node has actually registered a request. The node does not send
+# an EndListPersistentRequests on connect so it is impossible to tell when or if to restore one of
+# the pending requests we stored.
+#
+#FIX: None
+#---------------------------------------------------------------------------------------------------------------------------------------------
+# [0001893: CloseConnectionDuplicateClientName bug or feature?]
+#
+# CloseConnectionDuplicateClientName
+# currently fcp takes down a our connection if another client (...) uses the same connection name.
+#
+#FIX: None
+#----------------------------------------------------------------------------------------------------------------------------------------------
+# [0001888: explicite connection locale]
+#
+# Many strings are already translated by freenet, but there is no way to tell the node wich language
+# to use to talk to a client. Maybe a good idea, maybe not.
+#
+#FIX: None
+#-----------------------------------------------------------------------------------------------------------------------------------------------
+# [0001781: unregister directories registered via TestDDARequest]
+#
+# With current state of the art DDA handling it is not possiblr to unregister directories (may pile
+# up in memory over time).
+#
+#FIX: None
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# [0002019: Socket dies if first message is not ClientHello]
+#
+# minor one
+#
+#FIX: None
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# [0001965: Persistence vs PersistenceType]
+#
+# PersistentGet passes persistence field as "PersistenceType", PersistentPut as "Persistence"
+# already fixed this here in the client
+#
+# FIX: implemented in client
+#-------------------------------------------------------------------------------------------------------------------------------------------------
+# [0002015: Drop the global queue]
+#
+# this one is somewhat related to [0001931: Send EndListPersistentRequests following client connect]
+#
+# We never use or watch the global queue. It is to dangerous. But problems remain when it comes
+# to restoring persistent requests. Shure these are our requests? Worst case is a client with a colliding
+# connection name flooding our client with an unknown number of left overs.
+#
+#FIX: None (that is, this case is handled as savely as possible - except from possible slowdowns - but no
+# guarantee that no unknown request may slip through)
+#-------------------------------------------------------------------------------------------------------------------------------------------------
+# [0001894: HandleCollision field in ClientGet]
+#
+# minor one. When downloading a file, filename collisions may occur. Fcp does not handle these very well
+# It checks if the tempfile (filename ?) can be created newly when the request is started. IIRC In the final
+# rename of the tempfile to filename no check is done and filename will get overwritten.
+#
+#FIX: we handle collisions in the client as savely as possible. But no guarantee either when a colliding file
+# (...) finds his way into the download directory while downloading another.
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# [0002083: RemovePersistentRequest ignores unknown requests]
+#
+# minor one, but related to it a major one: you can not change the Priority of requests with
+# Persistence=conncetion
+#
+#FIX: workaround for the "related" part
+#------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+# Todos
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# clean up
+#
+# x. move saveWriteFile and friends to a separate module
+#
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# Fcp types vs. Python types
+#
+# x. Fcp seems to use kibibytes. Autoconvert to kilobytes?
+# x. time intervals
+#
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# logging
+#
+# x. should uris (...) always be visible in log output? Certainly in memory. Maybe a specialized
+# "save" logger could be useful (like for user feedback).
+#
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# runtime
+#
+# x. if the socket dies the client disconnects automatically, clearing all requests.
+# No idea how to handle this. Would require at least an EndListPersistentRequest
+# from the node to check wich requests arrived at the node ..and an auto resend
+# requests the node does not know about.
+#
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# request status
+#
+# x. have to set a dedicated flag when a request is about to be modified or removed
+# Fcp gets confused if we disconnect emidiately after sending a modify or remove request
+# Curretnly the RequestStatus.Completed flag is removed and later set again to get some
+# control over the process.
+#
+# TODO: check if this is a bug in Fcp
+# NOTE: seems to be fixed in [build 1112], fixes removed
+#-------------------------------------------------------------------------------------------------------------------------------------------------
+import atexit
+import copy
+import logging
+import os
+import socket
+import subprocess
+import sys
+import time
+
+
+#--> rel import hack
+class _RelImportHack(object):
+ def __init__(self, n):
+ fpath = os.path.abspath(__file__)
+ for i in xrange(n): fpath = os.path.dirname(fpath)
+ sys.path.insert(0, fpath)
+ def __del__(self): sys.path.pop(0)
+hack = _RelImportHack(2)
+
+
+import fcp.fcp2_0_consts as consts
+from fcp.fcp2_0_events import Events
+from fcp.fcp2_0_config import Config
+from fcp.fcp2_0_message import Message
+import fcp.fcp2_0_params as FcParams
+from fcp.fcp2_0_uri import Uri
+
+from fcp.fcp_lib import namespace
+from fcp.fcp_lib import tools
+
+
+del hack
+#<-- rel import hack
+
+logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
+#*************************************************************************************************
+#
+#*************************************************************************************************
+class FcpClient(object):
+ """
+ @ivar events: events the client supports
+ """
+
+ DefaultFcpHost = os.environ.get('FCP_HOST', '127.0.0.1').strip()
+ try:
+ DefaultFcpPort = int(os.environ.get('FCP_PORT', '').strip())
+ except ValueError:
+ DefaultFcpPort = 9481
+
+
+
+ #TODO: check if required
+ # suggested by Mathew Toseland to use about 32k for mimeType requests
+ # basic sizes of keys are: 1k for SSks and 32k for CHKs
+ # without MaxSize DataFound will have DataLength set to 0 (?!)
+ MaxSizeKeyInfo = 32768
+ MinimumRunTime = 1 # minimum time (seconds) the client will run when run() is called (FIX: 0001931)
+ SocketTimeout = 0.1
+ ExpectedFcpVersion = 2.0
+ ExpectedNodeBuild = 1107
+
+ consts = consts
+ Config = Config
+ Message = Message
+ FcParams = FcParams
+ Uri = Uri
+
+
+ def __init__(self,
+ connectionName=None,
+ debugVerbosity=None,
+ ):
+ """
+ @param connectionName: name of the connection or None to use an arbitrary connection name
+ @param debugVerbosity: verbosity level for debugging. Default is L{consts.DebugVerbosity.Warning}
+
+ """
+ self._connectionName = self.setConnectionName(connectionName)
+ self._ddaTests = [] # currently running DDA tests (request0, ... requestN)
+ self._requests = {} # currently running requests (requestIdentifier --> request)
+
+ self._logEvent = logging.getLogger(consts.LoggerNames.ClientEvents)
+ self._logMessage = logging.getLogger(consts.LoggerNames.ClientMessages)
+ self._logRuntime = logging.getLogger(consts.LoggerNames.ClientRuntime)
+
+ self._nodeHelloMessage = None
+ self._socket = None
+
+ self.events = Events()
+ for event in self.events:
+ event += self._captureEvent
+
+ self.setDebugVerbosity(consts.DebugVerbosity.Warning if debugVerbosity is None else debugVerbosity)
+ atexit.register(self.close)
+
+
+ ###############################################################
+ ##
+ ## private methods
+ ##
+ ###############################################################
+ def _close(self, msg):
+ """Closes the client
+ @param msg: message to pass to the ClientDisconnected event or None to not inform listeners
+ """
+ self._logRuntime.info(consts.LogMessages.ClientClose)
+
+ # clean left over DDA test tmp files
+ for initialRequest in self._ddaTests:
+ if initialRequest['FcTestDDA'].get('TmpFile', None) is not None:
+ tools.saveRemoveFile(initialRequest['FcTestDDA']['TmpFile'])
+
+ self._ddaTests = []
+ self._requests = {}
+
+ if self._socket is None:
+ #TODO: complain or not?
+ pass
+ else:
+ self._socket.close()
+ self._socket = None
+ if msg is not None:
+ self.events.ClientDisconnected(msg)
+
+
+ def _finalizeRequest(self, msg, request, event):
+ """Finalzes a request
+ @param msg: message that is the reason for finalizing
+ @param request: request to finalize
+ @param event: event to trigger or None
+
+ @note: this method sets the requests L{consts.RequestStatus.RemovedFromQueue} and
+ L{consts.RequestStatus.Completed} flags accordingly
+ @note: Fcp removes Get / Put requests with Persistence == connection emidiately
+ from its queue. Same goes all requests on ProtocolError. We inform the caller
+ that the request has been completed and remove it fom our queue if necessary.
+ Non Get / Put requests will be removed in any case.
+ """
+ removeRequest = msg.name in (consts.Message.ProtocolError, consts.Message.PersistentRequestRemoved)
+ if not removeRequest:
+ #NOTE: non Get / Put related requests do not have a Persistence param
+ removeRequest = request.params.get('Persistence', consts.Persistence.Connection) == consts.Persistence.Connection
+ if removeRequest:
+ request['FcRequestStatus'] |= consts.RequestStatus.RemovedFromQueue
+
+ request['FcRequestStatus'] |= consts.RequestStatus.Completed
+ if event is not None:
+ event(request)
+
+ if removeRequest:
+ del self._requests[request['Identifier']]
+
+
+ def _registerRequest(self,
+ msg,
+ requestType,
+ userData=None,
+ identifier=None,
+ initTime=None,
+ persistentUserData='',
+ filenameCollision=consts.FilenameCollision.HandleNever,
+ ):
+ """Registers a request
+ @param msg: message to register
+ @param requestType: (L{consts.RequestType}) type of request to register
+ @param filenameCollision: (L{consts.FilenameCollision}) how to handle filename collisions.
+ Default is L{consts.FilenameCollision.HandleNever}
+ @param identifier: (str) identifier of the request or None to create a new one
+ @param initTime: (int) init time of the request or None to set it to now
+ @param persistentUserData: (str) anyuser defined persistent data
+ @param userData: (any) any user defined non persistent data
+
+ @return: (str) identifer of therequest
+ @note: the identifier returned is unique to the client but may not be unique to the node
+ """
+ identifier = self.FcParams.newUuid(uuids=self._requests) if identifier is None else identifier
+
+ if requestType & (consts.RequestType.MaskGet | consts.RequestType.MaskPut):
+
+ msg.params.update({
+
+ # persistent params that will go into identifier
+ 'FcRequestType': requestType, # identifies sub message types
+ 'FcInitTime': time.time() if initTime is None else initTime, # when was the request started?
+ 'FcFilenameCollision': filenameCollision, # handle fielanem collisions?
+ 'FcPersistentUserData': persistentUserData, # any user defined persistent data
+
+ # non persistent params
+ 'FcRequestStatus': consts.RequestStatus.Null,
+ 'FcErrorMessage': None, # error message in case an error occured
+ 'FcUserData': userData, # any user defined runtime data here
+
+ # params for SSKKeypair
+ 'FcPrivateKey': None,
+ 'FcPublicKey': None,
+
+ # params from DataFound
+ 'FcMetadataContentType': '', # contecnt type
+ 'FcDataLength': '', # content size
+
+ # params from PersistentRequestModified
+ 'FcModified': {},
+
+ # params for DDA test
+ 'FcTestDDA': {},
+
+ # params for SimpleProgress
+ 'FcProgressTotal': '0',
+ 'FcProgressRequired': '0',
+ 'FcProgressFailed': '0',
+ 'FcProgressFatalyFailed': '0',
+ 'FcProgressSucceeeded': '0',
+
+ })
+ # equip msg with some persistent pparams
+ if msg.get('ClientToken', None) is None:
+ msg['ClientToken'] = self.FcParams.messageToParams(msg)
+
+ elif requestType & consts.RequestType.MaskGenerateKeypair:
+ msg.params.update({
+ 'FcRequestType': requestType, # identifies sub message types
+ 'FcRequestStatus': consts.RequestStatus.Null,
+ 'FcInitTime': initTime, # when was the request started?
+ 'FcModified': {},
+
+ 'FcPrivateKey': None,
+ 'FcPublicKey': None,
+ })
+
+ elif requestType & consts.RequestType.PluginMessage:
+ msg.params.update({
+ 'FcRequestType': requestType, # identifies sub message types
+ 'FcRequestStatus': consts.RequestStatus.Null,
+ 'FcInitTime': initTime, # when was the request started?
+ 'FcModified': {},
+
+ 'FcPluginReply': None,
+ })
+
+
+
+ else:
+ msg.params.update({
+ 'FcRequestType': requestType, # identifies sub message types
+ 'FcRequestStatus': consts.RequestStatus.Null,
+ 'FcInitTime': initTime, # when was the request started?
+ 'FcModified': {},
+ })
+
+ msg['FcRequestStatus'] |= consts.RequestStatus.Null
+ msg['Identifier'] = identifier
+ self._requests[identifier] = msg
+
+
+ def _captureEvent(self, event, request):
+ if event != self.events.Idle:
+ self._logEvent.debug(consts.LogMessages.EventTriggered + event.name)
+
+ ###############################################################
+ ##
+ ## connection related methods
+ ##
+ ###############################################################
+ def close(self):
+ """Closes the client
+ @note: make shure to call close() when done with the client
+ """
+ msg = self.Message(
+ consts.Message.ClientDisconnected,
+ DisconnectReason=consts.DisconnectReason.Close,
+ Param=None,
+ )
+ self._close(msg)
+
+
+ def closeFreenet(self):
+ """Shuts down the freenet node"""
+ self.sendMessage(consts.Message.Shutdown)
+
+
+ def connect(self, host=DefaultFcpHost, port=DefaultFcpPort, duration=20, timeout=0.5):
+ """Connects to the freenet node
+ @param host: (str) host of th node
+ @param port: (int) port of the node
+ @param duration: (int) how many seconds try to connect before giving up
+ @param timeout: (int) how much time to wait before another attempt to connect
+
+ @return: (L{fcp2_0_message.Message}) NodeHello or None if no connection could be established
+ """
+ nodeHello = None
+ for nodeHello in self.iterConnect(host=host, port=port, duration=duration, timeout=timeout):
+ pass
+ return nodeHello
+
+
+ def iterConnect(self, host=DefaultFcpHost, port=DefaultFcpPort, duration=20, timeout=0.5):
+ """Iterator to stablish a connection to a freenet node
+ @param host: (str) host of th node
+ @param port: (int) port of the node
+ @param duration: (int) how many seconds try to connect before giving up
+ @param timeout: (int) how much time to wait before another attempt to connect
+
+ @return: (L{fcp2_0_message.Message}) NodeHello if successful, None otherwise for the next iteration
+
+ @event: ClientConnected(event, message) is triggered as soon as the client is connected
+ """
+ self._logRuntime.info(consts.LogMessages.Connecting)
+
+ # try to Connect socket
+ if self._socket is not None:
+ self._close(None)
+
+ # poll untill freenet responds
+ timeElapsed = 0
+ while timeElapsed < duration:
+
+ # try to Connect socket
+ if self._socket is not None:
+ self._close(None)
+ self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self._socket.settimeout(self.SocketTimeout)
+ try:
+ self._socket.connect((host, port))
+ except socket.error, d:
+ yield None
+ else:
+ self._logRuntime.info(consts.LogMessages.Connected)
+
+ # send ClientHello and wait for NodeHello
+ #NOTE: thought I could leave ClientHelloing up to the caller
+ # but instad of responding with ClientHelloMustBeFirst
+ # as expected when not doing so, the node disconnects.
+ # So take it over here.
+ self.sendMessage(
+ consts.Message.ClientHello,
+ Name=self._connectionName,
+ ExpectedVersion=self.ExpectedFcpVersion,
+ )
+ while timeElapsed <= duration:
+ msg = self.next(dispatch=False)
+
+ if msg.name == consts.Message.ClientSocketTimeout:
+ timeElapsed += self.SocketTimeout
+ yield None
+
+ elif msg.name == consts.Message.NodeHello:
+ self._nodeHelloMessage = msg
+ # check if version is ok
+ if self.versionCheckNodeHello(msg):
+ self.events.ClientConnected(msg)
+ else:
+ disconnectMsg = self.Message(
+ consts.Message.ClientDisconnected,
+ DisconnectReason=consts.DisconnectReason.VersionMissmatch,
+ Param=msg,
+ )
+ self._close(disconnectMsg)
+ yield self._nodeHelloMessage
+ raise StopIteration
+
+ else:
+ self._logMessage.debug(consts.LogMessages.MessageReceived + msg.pprint())
+ break
+ break
+
+ # continue polling
+ self._logRuntime.info(consts.LogMessages.ConnectionRetry)
+ timeElapsed += timeout
+ time.sleep(timeout)
+
+ self._logRuntime.info(consts.LogMessages.ConnectingFailed)
+ disconnectMsg = self.Message(
+ consts.Message.ClientDisconnected,
+ DisconnectReason=consts.DisconnectReason.ConnectingFailed,
+ Param=None,
+ )
+ self._close(disconnectMsg)
+ raise StopIteration
+
+
+ def getConnectionName(self):
+ """Returns the connection name used by the client
+ @return: (str) connection name
+ """
+ return self._connectionName
+
+
+ def setConnectionName(self, connectionName=None):
+ """Sets the connection name to be used by the client
+ @param connectionName: (str) connection name or None to use an arbitrary connection name
+ @return: (str) connection name
+ """
+ self._connectionName = self.FcParams.newUuid() if connectionName is None else connectionName
+ return self._connectionName
+
+
+ def setDebugVerbosity(self, debugVerbosity):
+ """Sets the verbosity level of the client
+ @note: see L{consts.DebugVerbosity}
+ """
+ self._logEvent.setLevel(debugVerbosity)
+ self._logMessage.setLevel(debugVerbosity)
+ self._logRuntime.setLevel(debugVerbosity)
+
+
+ def startFreenet(self, cmdline):
+ """Starts freenet
+ @param cmdline: commandline to start freenet (like '/freenet/run.sh start' or 'c:\freenet\start.bat')
+ @return: (str) whatever freenet returns
+ """
+ #TODO: on windows it may be necessary to hide the command window
+ p = subprocess.Popen(
+ args=cmdline,
+ shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ stdout, stderr = p.communicate()
+ return stdout
+
+
+ def versionCheckNodeHello(self, nodeHelloMessage):
+ """Performa a version check of the client against the specified NodeHello message
+ @return: (bool) True if version is ok, False otherwise
+ @note: if this check returns False the client will emidiately disconnect in L{connect()}
+ and triggers a ClientDisconnected event. Overwrite to adjust
+ """
+ if nodeHelloMessage['FCPVersion'] >= self.ExpectedFcpVersion:
+ if nodeHelloMessage['Build'] >= self.ExpectedNodeBuild:
+ return True
+ return False
+
+ #########################################################
+ ##
+ ## runtime related methods
+ ##
+ #########################################################
+ def handleMessage(self, msg):
+ """Handles a message from the freenet node
+ @param msg: (Message) to handle
+ @return: True if the message was handled, False otherwise
+ """
+
+ CancelPersistentRequests = 0 # for testing... if True, cancels all PersistentRequests
+
+ # check if we have an initial request corrosponding to msg
+ requestIdentifier = msg.get('Identifier', None)
+ initialRequest = None if requestIdentifier is None else self._requests.get(requestIdentifier, None)
+ ####################################################
+ ##
+ ## errors
+ ##
+ ####################################################
+ if msg.name == consts.Message.IdentifierCollision:
+ if initialRequest is None:
+ return False
+
+ # resend request with new identifier
+ newIdentifier = self.FcParams.newUuid(uuids=self._requests)
+ self._requests[newIdentifier] = initialRequest
+ del self._requests[requestIdentifier]
+ initialRequest['Identifier'] = newIdentifier
+ initialRequest['FcModified'] = {consts.RequestModified.Identifier: requestIdentifier}
+ self.events.RequestModified(initialRequest)
+ self.sendMessageEx(initialRequest)
+ return True
+
+
+ elif msg.name == consts.Message.ProtocolError:
+ code = msg['Code']
+ if code == consts.ProtocolError.ShuttingDown:
+ disconnectMsg = self.Message(
+ consts.Message.ClientDisconnected,
+ DisconnectReason=consts.DisconnectReason.Shutdown,
+ Param=None,
+ )
+ self._close(disconnectMsg)
+ return True
+
+
+ if requestIdentifier is None:
+ self.events.ProtocolError(msg)
+ return True
+
+ if initialRequest is None:
+ return False
+
+
+ # handle DDA errors
+ elif code == consts.ProtocolError.DDADenied:
+ ddaRequestMsg = self.Message(consts.Message.TestDDARequest)
+ if initialRequest.name == consts.Message.ClientGet:
+ ddaRequestMsg['WantWriteDirectory'] = True
+ directory = os.path.dirname(initialRequest['Filename'])
+ else:
+ ddaRequestMsg['WantReadDirectory'] = True
+ directory = os.path.dirname(initialRequest['Filename'])
+ ddaRequestMsg['Directory'] = directory
+
+ # add params required for testing
+ initialRequest['FcTestDDA'] = {
+ 'Directory': directory,
+ 'Replied': False,
+ 'TmpFile': None,
+ 'WantWrite': ddaRequestMsg.get('WantWriteDirectory', False),
+ 'ErrorMsg': msg,
+ }
+ self._ddaTests.append(initialRequest)
+ self.sendMessageEx(ddaRequestMsg)
+ return True
+
+
+ # handle filename collisions
+ elif code == consts.ProtocolError.DiskTargetExists:
+ handleCollision = initialRequest.get('FcFilenameCollision', consts.FilenameCollision.HandleNever)
+ collisionHandled = bool(handleCollision & consts.FilenameCollision.CollisionHandled)
+
+ # rename filename
+ if handleCollision & consts.FilenameCollision.HandleRename:
+ filename = initialRequest['Filename']
+ initialRequest['FcFilenameCollision'] |= consts.FilenameCollision.CollisionHandled
+ newFilename = namespace.unique_filename(filename, extensions=1, ispostfixed=collisionHandled)
+ initialRequest['Filename'] = newFilename
+ initialRequest['FcModified'] = {consts.RequestModified.Filename: filename}
+ self.sendMessageEx(initialRequest)
+ self.events.RequestModified(initialRequest)
+ return True
+
+ # don't handle
+ else:
+ initialRequest['FcFilenameCollision'] &= ~consts.FilenameCollision.CollisionHandled
+
+
+ # handle plugin related request failures
+ elif code == consts.ProtocolError.NoSuchPlugin or code == consts.ProtocolError.AccessDenied:
+ if initialRequest.name == consts.Message.GetPluginInfo:
+ initialRequest['FcErrorMessage'] = msg
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
+ self._finalizeRequest(msg, initialRequest, self.events.PluginInfoFailed)
+ return True
+
+ # TODO: just a guess that FCPPluginMessage can trigger an AccessDenied error
+ elif initialRequest.name == consts.Message.FCPPluginMessage:
+ initialRequest['FcErrorMessage'] = msg
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
+ self._finalizeRequest(msg, initialRequest, self.events.PluginMessageFailed)
+ return True
+
+ # only requests should get through to here
+
+ # NOTE: Fcp already removed the request
+ initialRequest['FcErrorMessage'] = msg
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
+ self._finalizeRequest(msg, initialRequest, self.events.RequestFailed)
+ return True
+
+
+ ####################################################
+ ##
+ ## TestDDA
+ ##
+ ## We assume that a DDATest messages do not get mixed up. 1st TestDDARequest is first to
+ ## enter TestDDAReply and TestDDAComplete. Hopefuly the freenet devels will rework the
+ ## TestDDA drill.
+ ##
+ ####################################################
+ elif msg.name == consts.Message.TestDDAReply:
+ directory = msg['Directory']
+
+ # find message that triggered the call
+ for initialRequest in self._ddaTests:
+ if initialRequest['FcTestDDA']['Directory'] == directory:
+ if not initialRequest['FcTestDDA']['Replied']:
+ initialRequest['FcTestDDA']['Replied'] = True
+ break
+ else:
+ # fell through
+ raise ValueError('No inital message found in TestDDAReply')
+
+ # perform read test if necessary
+ fpathRead = msg.params.get('ReadFilename', None)
+ readContent = ''
+ if fpathRead is not None:
+ readContent = tools.saveReadFile(fpathRead)
+ if readContent is None:
+ readContent = ''
+
+ # perform write test if necessary
+ fpathWrite = msg.params.get('WriteFilename', None)
+ if fpathWrite is not None:
+ written = tools.saveWriteFile(fpathWrite, msg['ContentToWrite'])
+ if not written:
+ tools.saveRemoveFile(fpathWrite)
+ else:
+ initialRequest['FcTestDDA']['TmpFile'] = fpathWrite
+
+ self.sendMessage(
+ consts.Message.TestDDAResponse,
+ Directory=msg['Directory'],
+ ReadContent=readContent,
+ )
+ return True
+
+
+ elif msg.name == consts.Message.TestDDAComplete:
+ # clean up tmp file
+ directory = msg['Directory']
+
+ # find message that triggered the call
+ for initialRequest in self._ddaTests:
+ if initialRequest['FcTestDDA']['Directory'] == directory:
+ if initialRequest['FcTestDDA']['Replied']:
+ break
+ else:
+ # fell through
+ raise ValueError('No initial message found in TestDDAComplete')
+
+ # remove test and clean tmp data
+ self._ddaTests.remove(initialRequest)
+ if initialRequest['FcTestDDA']['TmpFile'] is not None:
+ tools.saveRemoveFile(initialRequest['FcTestDDA']['TmpFile'])
+ wantWrite = initialRequest.params['FcTestDDA']['WantWrite']
+
+ # check if test was sucessful
+ testFailed = False
+ if wantWrite:
+ testFailed = not msg.params.get('WriteDirectoryAllowed', False)
+ else:
+ testFailed = not msg.params.get('ReadDirectoryAllowed', False)
+
+ if testFailed:
+ #TODO: check if errorMsg gives reasonable feedback
+ initialRequest['FcRequestStatus'] = consts.RequestStatus.Error
+ initialRequest['FcErrorMessage'] = initialRequest['FcTestDDA']['ErrorMsg']
+ self._finalizeRequest(msg, initialRequest, self.events.RequestFailed)
+ return True
+
+ # else: resend message
+ self.sendMessageEx(initialRequest)
+ return True
+
+ ####################################################
+ ##
+ ## config related
+ ##
+ ####################################################
+ elif msg.name == consts.Message.ConfigData:
+ self.events.ConfigData(msg)
+ return True
+
+ elif msg.name == consts.Message.NodeData:
+ self.events.NodeData(msg)
+ return True
+
+ ####################################################
+ ##
+ ## get / put related
+ ##
+ ####################################################
+ elif msg.name == consts.Message.AllData:
+ if initialRequest is None:
+ return False
+
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
+ initialRequest.data = msg.data
+ self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted)
+ return True
+
+ elif msg.name == consts.Message.DataFound:
+ if initialRequest is None:
+ return False
+
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
+ initialRequest['FcMetadataContentType'] = msg.get('Metadata.ContentType', '')
+ initialRequest['FcDataLength'] = msg.get('DataLength', '')
+
+ # except from GetData all requests are complete here. Next GetData will run through AllData...
+
+ # For GetData with persistence != connection the node sends no All Data message
+ # whatever that is good for ..fix this here to get all GetData request to complete on
+ # All Data.
+ if initialRequest['FcRequestType'] == consts.RequestType.GetData:
+ if initialRequest['Persistence'] != consts.Persistence.Connection:
+ self.sendMessage(
+ consts.Message.GetRequestStatus,
+ Identifier=initialRequest['Identifier'],
+ Global=False,
+ OnlyData=True
+ )
+ else:
+ self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted)
+
+ return True
+
+
+ elif msg.name == consts.Message.GetFailed:
+ if initialRequest is None:
+ return False
+
+ code = msg['Code']
+ if code == consts.FetchError.Canceled:
+ return False
+
+ # check if it is one of our requests for key information
+ if code == consts.FetchError.TooBig and initialRequest['FcRequestType'] == consts.RequestType.GetKeyInfo:
+ initialRequest['FcMetadataContentType'] = msg.get('ExpectedMetadata.ContentType', '')
+ initialRequest['FcDataLength'] = msg.get('ExpectedDataLength', -1)
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
+ self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted)
+ else:
+ initialRequest['FcErrorMessage'] = msg
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
+ self._finalizeRequest(msg, initialRequest, self.events.RequestFailed)
+ return True
+
+
+ elif msg.name == consts.Message.PersistentGet:
+
+ # unknown request... try to restore it
+ if initialRequest is None:
+ fcParams = self.FcParams.paramsFromRequest(msg)
+
+ # not one of our requests... so cancel it
+ if fcParams is None or CancelPersistentRequests:
+ self.sendMessage(
+ consts.Message.RemovePersistentRequest,
+ Identifier=requestIdentifier,
+ Global=msg['Global'],
+ )
+ return True
+
+ initialRequest = copy.deepcopy(msg)
+ self._registerRequest(
+ initialRequest,
+ fcParams[self.FcParams.IRequestType],
+ identifier=requestIdentifier,
+ initTime=fcParams[self.FcParams.IInitTime],
+ userData=None,
+ persistentUserData=fcParams[self.FcParams.IPersistentUserData],
+ filenameCollision=fcParams[self.FcParams.IFilenameCollision],
+ )
+
+ initialRequest.name = consts.Message.ClientGet
+ #FIX: remove Started param from PersistentGet / Put
+ del initialRequest.params['Started']
+ #FIX: [0001965: Persistence vs PersistenceType]
+ if 'PersistenceType' in initialRequest.params:
+ initialRequest['Persistence'] = initialRequest.params.pop('PersistenceType')
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Restored
+ self.events.RequestRestored(initialRequest)
+ return True
+
+ # known request ..we don't handle that
+ return False
+
+
+ elif msg.name == consts.Message.PersistentRequestModified:
+ if initialRequest is None:
+ return False
+
+ modified = {}
+
+ # check if PersistentUserData has changed
+ params = self.FcParams.paramsFromRequest(initialRequest)
+ if params is not None:
+ clientToken = msg.get('ClientToken', None)
+ if clientToken is not None:
+
+ #TODO: its more or less a guess that PersistentUserData has changed
+ # ...as long as no other param is changed at runtime we are ok
+ # otherwise we would have to set flags to indicate wich member
+ # of ClientToken changed. See --> modifyRequest()
+ modified[consts.RequestModified.PersistentUserData] = None
+ for i, fcParam in enumerate(self.FcParams.FcParams):
+ initialRequest[fcParam] = params[i]
+
+ # check if PriorityClass has changed
+ priorityClass = msg.get('PriorityClass', None)
+ if priorityClass is not None:
+ modified[consts.RequestModified.PriorityClass] = None
+ initialRequest['PriorityClass'] = priorityClass
+
+ initialRequest['FcModified'] = modified
+ self.events.RequestModified(initialRequest)
+ return True
+
+
+ elif msg.name == consts.Message.PersistentRequestRemoved:
+ if initialRequest is None:
+ return False
+
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Removed
+ self._finalizeRequest(msg, initialRequest, self.events.RequestRemoved)
+ return True
+
+
+ elif msg.name == consts.Message.SimpleProgress:
+ if initialRequest is None:
+ return False
+
+ initialRequest['FcProgressTotal'] = msg['Total']
+ initialRequest['FcProgressRequired'] = msg['Required']
+ initialRequest['FcProgressFailed'] = msg['Failed']
+ initialRequest['FcProgressFatalyFailed'] = msg['FatallyFailed']
+ initialRequest['FcProgressSucceeeded'] = msg['Succeeded']
+ self.events.RequestProgress(initialRequest)
+ return True
+
+ ## put related
+
+ elif msg.name == consts.Message.PersistentPut:
+
+ # unknown request... try to restore it
+ if initialRequest is None:
+ fcParams = self.FcParams.paramsFromRequest(msg)
+
+ # not one of our requests... so cancel it
+ if fcParams is None or CancelPersistentRequests:
+ self.sendMessage(
+ consts.Message.RemovePersistentRequest,
+ Identifier=requestIdentifier,
+ Global=msg['Global'],
+ )
+ return True
+
+ initialRequest = copy.deepcopy(msg)
+ requestType = fcParams[self.FcParams.IRequestType]
+ self._registerRequest(
+ initialRequest,
+ requestType,
+ identifier=requestIdentifier,
+ initTime=fcParams[self.FcParams.IInitTime],
+ userData=None,
+ persistentUserData=fcParams[self.FcParams.IPersistentUserData],
+ filenameCollision=fcParams[self.FcParams.IFilenameCollision],
+ )
+
+ # determine initial message name
+ if requestType in (consts.RequestType.PutData, consts.RequestType.PutFile):
+ initialRequest.name = consts.Message.ClientPut
+ elif requestType == consts.RequestType.PutDir:
+ initialRequest.name = consts.Message.ClientPutDiskDir
+ elif requestType == consts.RequestType.PutMultiple:
+ initialRequest.name = consts.Message.ClientPutComplexDir
+
+ #FIX: remove Started param from PersistentGet / Put
+ del initialRequest.params['Started']
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Restored
+ self.events.RequestRestored(initialRequest)
+ return True
+
+ # known request ..we don't handle that
+ return False
+
+
+ elif msg.name == consts.Message.PutFailed:
+ if initialRequest is None:
+ return False
+
+ code = msg['Code']
+ if code == consts.InsertError.Canceled:
+ return False
+
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
+ initialRequest['FcErrorMessage'] = msg
+ self._finalizeRequest(msg, initialRequest, self.events.RequestFailed)
+ return True
+
+
+ elif msg.name == consts.Message.PutFetchable:
+ if initialRequest is None:
+ # something went wrong
+ return False
+
+ self.events.RequestFetchable(initialRequest)
+ return True
+
+
+ elif msg.name == consts.Message.PutSuccessful:
+ if initialRequest is None:
+ return False
+ # TODO: StartupTime and CompletionTime are passed, but
+ # as long as no corrosponding params are passed in DataFound
+ # we ignore them
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
+ initialRequest['URI'] = msg['URI']
+ self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted)
+ return True
+
+
+ elif msg.name == consts.Message.URIGenerated:
+ if initialRequest is None:
+ return False
+ initialRequest['URI'] = msg['URI']
+ return True
+
+ elif msg.name == consts.Message.FinishedCompression:
+ if initialRequest is None:
+ return False
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Compressed
+ self.events.RequestCompressionFinished(initialRequest)
+ return True
+
+ elif msg.name == consts.Message.StartedCompression:
+ if initialRequest is None:
+ return False
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Compressing
+ self.events.RequestCompressionStarted(initialRequest)
+ return True
+
+ ####################################################
+ ##
+ ## Peer related messages
+ ##
+ ####################################################
+ elif msg.name == consts.Message.EndListPeers:
+ self.events.EndListPeers(msg)
+ return True
+
+ elif msg.name == consts.Message.EndListPeerNotes:
+ self.events.EndListPeerNotes(msg.params)
+ return True
+
+ elif msg.name == consts.Message.Peer:
+ self.events.Peer(msg)
+ return True
+
+ elif msg.name == consts.Message.PeerNote:
+ self.events.PeerNote(msg)
+ return True
+
+ elif msg.name == consts.Message.PeerRemoved:
+ self.events.PeerRemoved(msg)
+ return True
+
+ elif msg.name == consts.Message.UnknownNodeIdentifier:
+ self.events.PeerUnknown(msg)
+ return True
+
+ elif msg.name == consts.Message.UnknownPeerNoteType:
+ self.events.PeerNoteTypeUnknown(msg)
+ return True
+ ####################################################
+ ##
+ ## plugins
+ ##
+ ####################################################
+ elif msg.name == consts.Message.PluginInfo:
+ if initialRequest is None:
+ return False
+
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
+ self._finalizeRequest(msg, initialRequest, self.events.PluginInfo)
+ return True
+
+ elif msg.name == consts.Message.FCPPluginReply:
+ if initialRequest is None:
+ return False
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
+ initialRequest['FcPluginReply'] = msg
+ self._finalizeRequest(msg, initialRequest, self.events.PluginMessage)
+ return True
+
+ ####################################################
+ ##
+ ## others
+ ##
+ ####################################################
+ elif msg.name == consts.Message.CloseConnectionDuplicateClientName:
+ disconnectMsg = self.Message(
+ consts.Message.ClientDisconnected,
+ DisconnectReason=consts.DisconnectReason.DuplicateClientName,
+ Param=None,
+ )
+ self._close(disconnectMsg)
+ return True
+
+
+ elif msg.name == consts.Message.SSKKeypair:
+ if initialRequest is None:
+ return False
+
+ #TODO:no idea if the node may pass uris with prefixes like 'freenet:'... strip it anyways
+ insertURI = self.Uri(msg['InsertURI']).uri
+ requestURI = self.Uri(msg['RequestURI']).uri
+
+ if initialRequest['FcRequestType'] == consts.RequestType.GenerateUSKKeypair:
+ insertURI = insertURI.replace(consts.KeyType.SSK, consts.KeyType.USK, 1)
+ requestURI = requestURI.replace(consts.KeyType.SSK, consts.KeyType.USK, 1)
+
+ initialRequest['FcPrivateKey'] = insertURI
+ initialRequest['FcPublicKey'] = requestURI
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
+ self._finalizeRequest(msg, initialRequest, self.events.KeypairGenerated)
+ return True
+
+ elif msg.name == consts.Message.SubscribedUSKUpdate:
+ if initialRequest is None:
+ return False
+ self.events.USKUpdated(msg)
+ return True
+
+
+ # default
+ return False
+
+
+ def next(self, dispatch=True):
+ """Pumps the next message waiting
+ @param dispatch: if True the message is dispatched to L{handleMessage}
+ @note: use this method to run the client step by step. If you want to run the
+ client unconditionally use L{run}
+ """
+ msg = self.Message.fromSocket(self._socket)
+ if msg.name == consts.Message.ClientSocketDied:
+ self._logRuntime.critical(consts.LogMessages.SocketDied)
+ if dispatch:
+ disconnectMsg = self.Message(
+ consts.Message.ClientDisconnected,
+ DisconnectReason=consts.DisconnectReason.SocketDied,
+ Param=msg,
+ )
+ self._close(disconnectMsg)
+ #raise socket.error(msg['Param']['Details'])
+
+ elif msg.name == consts.Message.ClientSocketTimeout:
+ if dispatch:
+ self.events.Idle(msg)
+ else:
+ self._logMessage.debug(consts.LogMessages.MessageReceived + msg.pprint())
+ if dispatch:
+ self.handleMessage(msg)
+ return msg
+
+
+ def run(self):
+ """Runs the client unconditionally untill all requests have completed
+ @note: a KeyboardInterrupt will stop the client
+ """
+
+ #FIX: 0001931
+ # poll a few times to see if there are persistent requests waiting
+ t0 = time.time()
+ while time.time() - t0 <= self.MinimumRunTime:
+ try:
+ msg = self.next()
+ except KeyboardInterrupt:
+ self._logRuntime.info(consts.LogMessages.KeyboardInterrupt)
+ return
+ if msg.name == consts.Message.ClientSocketDied:
+ return
+
+ #n = 0
+ while True:
+ #n += 1
+ #if n > 50: break
+
+ # check if we have running requests. Assert False
+ haveRunningRequests = False
+ for request in self._requests.values():
+ if not request['FcRequestStatus'] & consts.RequestStatus.Completed:
+ haveRunningRequests = True
+ break
+
+ if not haveRunningRequests:
+ self._logRuntime.info(consts.LogMessages.AllRequestsCompleted)
+ break
+
+ try:
+ msg = self.next()
+ except KeyboardInterrupt:
+ self._logRuntime.info(consts.LogMessages.KeyboardInterrupt)
+ break
+
+ if msg.name == consts.Message.ClientSocketDied:
+ break
+
+
+ def sendMessage(self, name, data=None, **params):
+ """Sends a message to freenet
+ @param name: name of the message to send
+ @param data: data to atatch to the message
+ @param params: {para-name: param-calue, ...} of parameters to pass along
+ with the message (see freenet protocol)
+ @raise SocketError: if the socket connection to the node dies unexpectedly
+ If an error handler is passed to the client it is called emidiately before the error
+ is raised.
+
+ @note: you can use this method to send a message to the node, bypassing all
+ track keeping methods of the client
+ """
+ return self.sendMessageEx(self.Message(name, data=data, **params))
+
+
+ def sendMessageEx(self, msg):
+ """Sends a message to freenet
+ @param msg: (Message) message to send
+ @return: Message
+ @raise SocketError: if the socket connection to the node dies unexpectedly.
+ If an error handler is passed to the client it is called emidiately before the error
+ is raised.
+
+ @note: you can use this method to send a message to the node, bypassing all
+ track keeping methods of the client
+ """
+ self._logMessage.debug(consts.LogMessages.MessageSend + msg.pprint())
+ try:
+ msg.send(self._socket)
+ except socket.error, d:
+ self._logRuntime.critical(consts.LogMessages.SocketDied)
+ disconnectMsg = self.Message(
+ consts.Message.ClientDisconnected,
+ DisconnectReason=consts.DisconnectReason.SocketDied,
+ Param=self.Message(consts.Message.ClientSocketDied, Exception=socket.error, Details=d)
+ )
+ self._close(disconnectMsg)
+ raise socket.error(d)
+ return msg
+
+ #########################################################
+ ##
+ ## config related methods
+ ##
+ #########################################################
+ def getConfig(self,
+ withCurrent=True,
+ withDefaults=True,
+ withExpertFlag=True,
+ withForceWriteFlag=True,
+ withSortOrder=True,
+ withShortDescription=True,
+ withLongDescription=True,
+ ):
+ """
+ @event: ConfigData(event, msg)
+ """
+ self.sendMessage(
+ consts.Message.GetConfig,
+ WithSortOrder=withSortOrder,
+ WithCurrent=withCurrent,
+ WithDefaults=withDefaults,
+ WithExpertFlag=withExpertFlag,
+ WithForceWriteFlag=withForceWriteFlag,
+ WithShortDescription=withShortDescription,
+ WithLongDescription=withLongDescription,
+ )
+
+
+ def modifyConfig(self, params):
+ """Modifies node configuration values
+ @param params: (dict) containing parameters to modify
+ """
+ msg = self.Message(consts.Message.ModifyConfig)
+ msg.params = params
+ self.sendMessageEx(msg)
+
+
+ ########################################################
+ ##
+ ## ClientGet related methods
+ ##
+ ########################################################
+ def clientGet(self,
+ uri,
+ requestType,
+ userData,
+ persistentUserData,
+ filenameCollision,
+ **messageParams
+ ):
+ """Requests a key from the node
+ @param uri: (str) uri of the file to request (may contain prefixes like 'freenet:' or 'http://')
+ @param requestType: (L{consts.RequestType}) sub type of the message
+ @param userData: any non persistent data to associate to the request or None
+ @param persistentUserData: any string to associate to the request as persistent data or None
+ @param filenameCollision: what to do if the disk target alreaady exists. One of the FilenameCollision.* consts
+ @param messageParams: keyword arguments to pass along with the ClientGet message (uppercase first letter!!).
+ If the value of a keyword is None, it is ignored.
+
+ @return: (str) identifier of the request
+ """
+ uri = self.Uri(uri).uri
+ msg = self.Message(consts.Message.ClientGet, URI=uri)
+ for paramName, value in messageParams.items():
+ if value is not No...
[truncated message content] |
|
From: <ju...@us...> - 2008-02-26 09:47:01
|
Revision: 254
http://fclient.svn.sourceforge.net/fclient/?rev=254&view=rev
Author: jurner
Date: 2008-02-26 01:47:03 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
renames
Added Paths:
-----------
trunk/sandbox/fcp/client.py
trunk/sandbox/fcp/config.py
trunk/sandbox/fcp/consts.py
trunk/sandbox/fcp/events.py
trunk/sandbox/fcp/message.py
trunk/sandbox/fcp/params.py
trunk/sandbox/fcp/test_fcp/client.py
trunk/sandbox/fcp/test_fcp/test_client.py
trunk/sandbox/fcp/test_fcp/test_config.py
trunk/sandbox/fcp/test_fcp/test_message.py
trunk/sandbox/fcp/types.py
trunk/sandbox/fcp/uri.py
Removed Paths:
-------------
trunk/sandbox/fcp/fcp2_0_client.py
trunk/sandbox/fcp/fcp2_0_config.py
trunk/sandbox/fcp/fcp2_0_consts.py
trunk/sandbox/fcp/fcp2_0_events.py
trunk/sandbox/fcp/fcp2_0_message.py
trunk/sandbox/fcp/fcp2_0_params.py
trunk/sandbox/fcp/fcp2_0_types.py
trunk/sandbox/fcp/fcp2_0_uri.py
trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py
trunk/sandbox/fcp/test_fcp/test_fcp2_0_config.py
trunk/sandbox/fcp/test_fcp/test_fcp2_0_message.py
Copied: trunk/sandbox/fcp/client.py (from rev 253, trunk/sandbox/fcp/fcp2_0_client.py)
===================================================================
--- trunk/sandbox/fcp/client.py (rev 0)
+++ trunk/sandbox/fcp/client.py 2008-02-26 09:47:03 UTC (rev 254)
@@ -0,0 +1,2307 @@
+"""Freenet client protocol 2.0 implementation
+
+Compatibility: >= Freenet 0.7 Build #1107
+
+
+@newfield event: Event, Events
+@newfield requestparam: RequestParam, RequestParams
+
+@note: The client implementation never uses or watches the global queue. No implementation
+should ever do so. Global is evil.
+@note: the client is not thread save.
+
+
+Sample code. Connect to the freenet node::
+ client = FcpClient()
+ nodeHello = client.connect()
+ if nodeHello is None:
+ pass
+ # something went wrong ..could not connect to the freenet node
+ else:
+ pass
+ # everything went well ..we are connected now
+
+Request data associated to a freenet key::
+ myRequestIdentifier = client.getData('CHK@ABCDE.......')
+ myRequest = c.getRequest(myIdentifier)
+ client.run()
+ print myRequest.data
+
+Usually you would connect handlers to client events to do processing or handle errors::
+ def handleSuccess(event, request):
+ print 'Here is the data:', request.data
+
+ def handleFailure(event, request):
+ print 'Too bad, something went wrong'
+
+ client.events.RequestCompleted += handleSuccess
+ client.events.RequestFailed += handleFailure
+
+ client.getData('CHK@ABCDE.......')
+ c.run()
+
+
+Instead of calling run() you may run the client step by step::
+ client.getData('CHK@ABCDE.......')
+ for i in xrange(50):
+ client.next()
+
+
+You may disconnect event handlers aswell::
+
+ client.events.RequestCompleted -= handleSuccess
+ client.events.RequestFailed -= handleFailure
+
+
+Multiple event handlers may be connected / disconnected at once::
+
+ client.events += (
+ (client.events.RequestCompleted, handleSuccess),
+ (client.events.RequestFailed, handleFailure)
+ )
+
+
+"""
+
+#Bug reports filed and open:
+#--------------------------------------------------------------------------------------------------------------------------------------------
+# [0001931: Send EndListPersistentRequests following client connect]
+#
+# PendingRequests currently get lost if a.) the node goes down b.) if the client goes down unexpectedly.
+# This affects IdentifierCollision + FilenameCollision + ClientPut when a SSK needs to be created first
+#
+# we can handle this case none short of maintaining a file keeping messages. But still there is the
+# problem of knowing when the node has actually registered a request. The node does not send
+# an EndListPersistentRequests on connect so it is impossible to tell when or if to restore one of
+# the pending requests we stored.
+#
+#FIX: None
+#---------------------------------------------------------------------------------------------------------------------------------------------
+# [0001893: CloseConnectionDuplicateClientName bug or feature?]
+#
+# CloseConnectionDuplicateClientName
+# currently fcp takes down a our connection if another client (...) uses the same connection name.
+#
+#FIX: None
+#----------------------------------------------------------------------------------------------------------------------------------------------
+# [0001888: explicite connection locale]
+#
+# Many strings are already translated by freenet, but there is no way to tell the node wich language
+# to use to talk to a client. Maybe a good idea, maybe not.
+#
+#FIX: None
+#-----------------------------------------------------------------------------------------------------------------------------------------------
+# [0001781: unregister directories registered via TestDDARequest]
+#
+# With current state of the art DDA handling it is not possiblr to unregister directories (may pile
+# up in memory over time).
+#
+#FIX: None
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# [0002019: Socket dies if first message is not ClientHello]
+#
+# minor one
+#
+#FIX: None
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# [0001965: Persistence vs PersistenceType]
+#
+# PersistentGet passes persistence field as "PersistenceType", PersistentPut as "Persistence"
+# already fixed this here in the client
+#
+# FIX: implemented in client
+#-------------------------------------------------------------------------------------------------------------------------------------------------
+# [0002015: Drop the global queue]
+#
+# this one is somewhat related to [0001931: Send EndListPersistentRequests following client connect]
+#
+# We never use or watch the global queue. It is to dangerous. But problems remain when it comes
+# to restoring persistent requests. Shure these are our requests? Worst case is a client with a colliding
+# connection name flooding our client with an unknown number of left overs.
+#
+#FIX: None (that is, this case is handled as savely as possible - except from possible slowdowns - but no
+# guarantee that no unknown request may slip through)
+#-------------------------------------------------------------------------------------------------------------------------------------------------
+# [0001894: HandleCollision field in ClientGet]
+#
+# minor one. When downloading a file, filename collisions may occur. Fcp does not handle these very well
+# It checks if the tempfile (filename ?) can be created newly when the request is started. IIRC In the final
+# rename of the tempfile to filename no check is done and filename will get overwritten.
+#
+#FIX: we handle collisions in the client as savely as possible. But no guarantee either when a colliding file
+# (...) finds his way into the download directory while downloading another.
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# [0002083: RemovePersistentRequest ignores unknown requests]
+#
+# minor one, but related to it a major one: you can not change the Priority of requests with
+# Persistence=conncetion
+#
+#FIX: workaround for the "related" part
+#------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+# Todos
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# clean up
+#
+# x. move saveWriteFile and friends to a separate module
+#
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# Fcp types vs. Python types
+#
+# x. Fcp seems to use kibibytes. Autoconvert to kilobytes?
+# x. time intervals
+#
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# logging
+#
+# x. should uris (...) always be visible in log output? Certainly in memory. Maybe a specialized
+# "save" logger could be useful (like for user feedback).
+#
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# runtime
+#
+# x. if the socket dies the client disconnects automatically, clearing all requests.
+# No idea how to handle this. Would require at least an EndListPersistentRequest
+# from the node to check wich requests arrived at the node ..and an auto resend
+# requests the node does not know about.
+#
+#------------------------------------------------------------------------------------------------------------------------------------------------
+# request status
+#
+# x. have to set a dedicated flag when a request is about to be modified or removed
+# Fcp gets confused if we disconnect emidiately after sending a modify or remove request
+# Curretnly the RequestStatus.Completed flag is removed and later set again to get some
+# control over the process.
+#
+# TODO: check if this is a bug in Fcp
+# NOTE: seems to be fixed in [build 1112], fixes removed
+#-------------------------------------------------------------------------------------------------------------------------------------------------
+import atexit
+import copy
+import logging
+import os
+import socket
+import subprocess
+import sys
+import time
+
+
+#--> rel import hack
+class _RelImportHack(object):
+ def __init__(self, n):
+ fpath = os.path.abspath(__file__)
+ for i in xrange(n): fpath = os.path.dirname(fpath)
+ sys.path.insert(0, fpath)
+ def __del__(self): sys.path.pop(0)
+hack = _RelImportHack(2)
+
+
+import fcp.fcp2_0_consts as consts
+from fcp.fcp2_0_events import Events
+from fcp.fcp2_0_config import Config
+from fcp.fcp2_0_message import Message
+import fcp.fcp2_0_params as FcParams
+from fcp.fcp2_0_uri import Uri
+
+from fcp.fcp_lib import namespace
+from fcp.fcp_lib import tools
+
+
+del hack
+#<-- rel import hack
+
+logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
+#*************************************************************************************************
+#
+#*************************************************************************************************
+class FcpClient(object):
+ """
+ @ivar events: events the client supports
+ """
+
+ DefaultFcpHost = os.environ.get('FCP_HOST', '127.0.0.1').strip()
+ try:
+ DefaultFcpPort = int(os.environ.get('FCP_PORT', '').strip())
+ except ValueError:
+ DefaultFcpPort = 9481
+
+
+
+ #TODO: check if required
+ # suggested by Mathew Toseland to use about 32k for mimeType requests
+ # basic sizes of keys are: 1k for SSks and 32k for CHKs
+ # without MaxSize DataFound will have DataLength set to 0 (?!)
+ MaxSizeKeyInfo = 32768
+ MinimumRunTime = 1 # minimum time (seconds) the client will run when run() is called (FIX: 0001931)
+ SocketTimeout = 0.1
+ ExpectedFcpVersion = 2.0
+ ExpectedNodeBuild = 1107
+
+ consts = consts
+ Config = Config
+ Message = Message
+ FcParams = FcParams
+ Uri = Uri
+
+
+ def __init__(self,
+ connectionName=None,
+ debugVerbosity=None,
+ ):
+ """
+ @param connectionName: name of the connection or None to use an arbitrary connection name
+ @param debugVerbosity: verbosity level for debugging. Default is L{consts.DebugVerbosity.Warning}
+
+ """
+ self._connectionName = self.setConnectionName(connectionName)
+ self._ddaTests = [] # currently running DDA tests (request0, ... requestN)
+ self._requests = {} # currently running requests (requestIdentifier --> request)
+
+ self._logEvent = logging.getLogger(consts.LoggerNames.ClientEvents)
+ self._logMessage = logging.getLogger(consts.LoggerNames.ClientMessages)
+ self._logRuntime = logging.getLogger(consts.LoggerNames.ClientRuntime)
+
+ self._nodeHelloMessage = None
+ self._socket = None
+
+ self.events = Events()
+ for event in self.events:
+ event += self._captureEvent
+
+ self.setDebugVerbosity(consts.DebugVerbosity.Warning if debugVerbosity is None else debugVerbosity)
+ atexit.register(self.close)
+
+
+ ###############################################################
+ ##
+ ## private methods
+ ##
+ ###############################################################
+ def _close(self, msg):
+ """Closes the client
+ @param msg: message to pass to the ClientDisconnected event or None to not inform listeners
+ """
+ self._logRuntime.info(consts.LogMessages.ClientClose)
+
+ # clean left over DDA test tmp files
+ for initialRequest in self._ddaTests:
+ if initialRequest['FcTestDDA'].get('TmpFile', None) is not None:
+ tools.saveRemoveFile(initialRequest['FcTestDDA']['TmpFile'])
+
+ self._ddaTests = []
+ self._requests = {}
+
+ if self._socket is None:
+ #TODO: complain or not?
+ pass
+ else:
+ self._socket.close()
+ self._socket = None
+ if msg is not None:
+ self.events.ClientDisconnected(msg)
+
+
+ def _finalizeRequest(self, msg, request, event):
+ """Finalzes a request
+ @param msg: message that is the reason for finalizing
+ @param request: request to finalize
+ @param event: event to trigger or None
+
+ @note: this method sets the requests L{consts.RequestStatus.RemovedFromQueue} and
+ L{consts.RequestStatus.Completed} flags accordingly
+ @note: Fcp removes Get / Put requests with Persistence == connection emidiately
+ from its queue. Same goes all requests on ProtocolError. We inform the caller
+ that the request has been completed and remove it fom our queue if necessary.
+ Non Get / Put requests will be removed in any case.
+ """
+ removeRequest = msg.name in (consts.Message.ProtocolError, consts.Message.PersistentRequestRemoved)
+ if not removeRequest:
+ #NOTE: non Get / Put related requests do not have a Persistence param
+ removeRequest = request.params.get('Persistence', consts.Persistence.Connection) == consts.Persistence.Connection
+ if removeRequest:
+ request['FcRequestStatus'] |= consts.RequestStatus.RemovedFromQueue
+
+ request['FcRequestStatus'] |= consts.RequestStatus.Completed
+ if event is not None:
+ event(request)
+
+ if removeRequest:
+ del self._requests[request['Identifier']]
+
+
+ def _registerRequest(self,
+ msg,
+ requestType,
+ userData=None,
+ identifier=None,
+ initTime=None,
+ persistentUserData='',
+ filenameCollision=consts.FilenameCollision.HandleNever,
+ ):
+ """Registers a request
+ @param msg: message to register
+ @param requestType: (L{consts.RequestType}) type of request to register
+ @param filenameCollision: (L{consts.FilenameCollision}) how to handle filename collisions.
+ Default is L{consts.FilenameCollision.HandleNever}
+ @param identifier: (str) identifier of the request or None to create a new one
+ @param initTime: (int) init time of the request or None to set it to now
+ @param persistentUserData: (str) anyuser defined persistent data
+ @param userData: (any) any user defined non persistent data
+
+ @return: (str) identifer of therequest
+ @note: the identifier returned is unique to the client but may not be unique to the node
+ """
+ identifier = self.FcParams.newUuid(uuids=self._requests) if identifier is None else identifier
+
+ if requestType & (consts.RequestType.MaskGet | consts.RequestType.MaskPut):
+
+ msg.params.update({
+
+ # persistent params that will go into identifier
+ 'FcRequestType': requestType, # identifies sub message types
+ 'FcInitTime': time.time() if initTime is None else initTime, # when was the request started?
+ 'FcFilenameCollision': filenameCollision, # handle fielanem collisions?
+ 'FcPersistentUserData': persistentUserData, # any user defined persistent data
+
+ # non persistent params
+ 'FcRequestStatus': consts.RequestStatus.Null,
+ 'FcErrorMessage': None, # error message in case an error occured
+ 'FcUserData': userData, # any user defined runtime data here
+
+ # params for SSKKeypair
+ 'FcPrivateKey': None,
+ 'FcPublicKey': None,
+
+ # params from DataFound
+ 'FcMetadataContentType': '', # contecnt type
+ 'FcDataLength': '', # content size
+
+ # params from PersistentRequestModified
+ 'FcModified': {},
+
+ # params for DDA test
+ 'FcTestDDA': {},
+
+ # params for SimpleProgress
+ 'FcProgressTotal': '0',
+ 'FcProgressRequired': '0',
+ 'FcProgressFailed': '0',
+ 'FcProgressFatalyFailed': '0',
+ 'FcProgressSucceeeded': '0',
+
+ })
+ # equip msg with some persistent pparams
+ if msg.get('ClientToken', None) is None:
+ msg['ClientToken'] = self.FcParams.messageToParams(msg)
+
+ elif requestType & consts.RequestType.MaskGenerateKeypair:
+ msg.params.update({
+ 'FcRequestType': requestType, # identifies sub message types
+ 'FcRequestStatus': consts.RequestStatus.Null,
+ 'FcInitTime': initTime, # when was the request started?
+ 'FcModified': {},
+
+ 'FcPrivateKey': None,
+ 'FcPublicKey': None,
+ })
+
+ elif requestType & consts.RequestType.PluginMessage:
+ msg.params.update({
+ 'FcRequestType': requestType, # identifies sub message types
+ 'FcRequestStatus': consts.RequestStatus.Null,
+ 'FcInitTime': initTime, # when was the request started?
+ 'FcModified': {},
+
+ 'FcPluginReply': None,
+ })
+
+
+
+ else:
+ msg.params.update({
+ 'FcRequestType': requestType, # identifies sub message types
+ 'FcRequestStatus': consts.RequestStatus.Null,
+ 'FcInitTime': initTime, # when was the request started?
+ 'FcModified': {},
+ })
+
+ msg['FcRequestStatus'] |= consts.RequestStatus.Null
+ msg['Identifier'] = identifier
+ self._requests[identifier] = msg
+
+
+ def _captureEvent(self, event, request):
+ if event != self.events.Idle:
+ self._logEvent.debug(consts.LogMessages.EventTriggered + event.name)
+
+ ###############################################################
+ ##
+ ## connection related methods
+ ##
+ ###############################################################
+ def close(self):
+ """Closes the client
+ @note: make shure to call close() when done with the client
+ """
+ msg = self.Message(
+ consts.Message.ClientDisconnected,
+ DisconnectReason=consts.DisconnectReason.Close,
+ Param=None,
+ )
+ self._close(msg)
+
+
+ def closeFreenet(self):
+ """Shuts down the freenet node"""
+ self.sendMessage(consts.Message.Shutdown)
+
+
+ def connect(self, host=DefaultFcpHost, port=DefaultFcpPort, duration=20, timeout=0.5):
+ """Connects to the freenet node
+ @param host: (str) host of th node
+ @param port: (int) port of the node
+ @param duration: (int) how many seconds try to connect before giving up
+ @param timeout: (int) how much time to wait before another attempt to connect
+
+ @return: (L{fcp2_0_message.Message}) NodeHello or None if no connection could be established
+ """
+ nodeHello = None
+ for nodeHello in self.iterConnect(host=host, port=port, duration=duration, timeout=timeout):
+ pass
+ return nodeHello
+
+
+ def iterConnect(self, host=DefaultFcpHost, port=DefaultFcpPort, duration=20, timeout=0.5):
+ """Iterator to stablish a connection to a freenet node
+ @param host: (str) host of th node
+ @param port: (int) port of the node
+ @param duration: (int) how many seconds try to connect before giving up
+ @param timeout: (int) how much time to wait before another attempt to connect
+
+ @return: (L{fcp2_0_message.Message}) NodeHello if successful, None otherwise for the next iteration
+
+ @event: ClientConnected(event, message) is triggered as soon as the client is connected
+ """
+ self._logRuntime.info(consts.LogMessages.Connecting)
+
+ # try to Connect socket
+ if self._socket is not None:
+ self._close(None)
+
+ # poll untill freenet responds
+ timeElapsed = 0
+ while timeElapsed < duration:
+
+ # try to Connect socket
+ if self._socket is not None:
+ self._close(None)
+ self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self._socket.settimeout(self.SocketTimeout)
+ try:
+ self._socket.connect((host, port))
+ except socket.error, d:
+ yield None
+ else:
+ self._logRuntime.info(consts.LogMessages.Connected)
+
+ # send ClientHello and wait for NodeHello
+ #NOTE: thought I could leave ClientHelloing up to the caller
+ # but instad of responding with ClientHelloMustBeFirst
+ # as expected when not doing so, the node disconnects.
+ # So take it over here.
+ self.sendMessage(
+ consts.Message.ClientHello,
+ Name=self._connectionName,
+ ExpectedVersion=self.ExpectedFcpVersion,
+ )
+ while timeElapsed <= duration:
+ msg = self.next(dispatch=False)
+
+ if msg.name == consts.Message.ClientSocketTimeout:
+ timeElapsed += self.SocketTimeout
+ yield None
+
+ elif msg.name == consts.Message.NodeHello:
+ self._nodeHelloMessage = msg
+ # check if version is ok
+ if self.versionCheckNodeHello(msg):
+ self.events.ClientConnected(msg)
+ else:
+ disconnectMsg = self.Message(
+ consts.Message.ClientDisconnected,
+ DisconnectReason=consts.DisconnectReason.VersionMissmatch,
+ Param=msg,
+ )
+ self._close(disconnectMsg)
+ yield self._nodeHelloMessage
+ raise StopIteration
+
+ else:
+ self._logMessage.debug(consts.LogMessages.MessageReceived + msg.pprint())
+ break
+ break
+
+ # continue polling
+ self._logRuntime.info(consts.LogMessages.ConnectionRetry)
+ timeElapsed += timeout
+ time.sleep(timeout)
+
+ self._logRuntime.info(consts.LogMessages.ConnectingFailed)
+ disconnectMsg = self.Message(
+ consts.Message.ClientDisconnected,
+ DisconnectReason=consts.DisconnectReason.ConnectingFailed,
+ Param=None,
+ )
+ self._close(disconnectMsg)
+ raise StopIteration
+
+
+ def getConnectionName(self):
+ """Returns the connection name used by the client
+ @return: (str) connection name
+ """
+ return self._connectionName
+
+
+ def setConnectionName(self, connectionName=None):
+ """Sets the connection name to be used by the client
+ @param connectionName: (str) connection name or None to use an arbitrary connection name
+ @return: (str) connection name
+ """
+ self._connectionName = self.FcParams.newUuid() if connectionName is None else connectionName
+ return self._connectionName
+
+
+ def setDebugVerbosity(self, debugVerbosity):
+ """Sets the verbosity level of the client
+ @note: see L{consts.DebugVerbosity}
+ """
+ self._logEvent.setLevel(debugVerbosity)
+ self._logMessage.setLevel(debugVerbosity)
+ self._logRuntime.setLevel(debugVerbosity)
+
+
+ def startFreenet(self, cmdline):
+ """Starts freenet
+ @param cmdline: commandline to start freenet (like '/freenet/run.sh start' or 'c:\freenet\start.bat')
+ @return: (str) whatever freenet returns
+ """
+ #TODO: on windows it may be necessary to hide the command window
+ p = subprocess.Popen(
+ args=cmdline,
+ shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ stdout, stderr = p.communicate()
+ return stdout
+
+
+ def versionCheckNodeHello(self, nodeHelloMessage):
+ """Performa a version check of the client against the specified NodeHello message
+ @return: (bool) True if version is ok, False otherwise
+ @note: if this check returns False the client will emidiately disconnect in L{connect()}
+ and triggers a ClientDisconnected event. Overwrite to adjust
+ """
+ if nodeHelloMessage['FCPVersion'] >= self.ExpectedFcpVersion:
+ if nodeHelloMessage['Build'] >= self.ExpectedNodeBuild:
+ return True
+ return False
+
+ #########################################################
+ ##
+ ## runtime related methods
+ ##
+ #########################################################
+ def handleMessage(self, msg):
+ """Handles a message from the freenet node
+ @param msg: (Message) to handle
+ @return: True if the message was handled, False otherwise
+ """
+
+ CancelPersistentRequests = 0 # for testing... if True, cancels all PersistentRequests
+
+ # check if we have an initial request corrosponding to msg
+ requestIdentifier = msg.get('Identifier', None)
+ initialRequest = None if requestIdentifier is None else self._requests.get(requestIdentifier, None)
+ ####################################################
+ ##
+ ## errors
+ ##
+ ####################################################
+ if msg.name == consts.Message.IdentifierCollision:
+ if initialRequest is None:
+ return False
+
+ # resend request with new identifier
+ newIdentifier = self.FcParams.newUuid(uuids=self._requests)
+ self._requests[newIdentifier] = initialRequest
+ del self._requests[requestIdentifier]
+ initialRequest['Identifier'] = newIdentifier
+ initialRequest['FcModified'] = {consts.RequestModified.Identifier: requestIdentifier}
+ self.events.RequestModified(initialRequest)
+ self.sendMessageEx(initialRequest)
+ return True
+
+
+ elif msg.name == consts.Message.ProtocolError:
+ code = msg['Code']
+ if code == consts.ProtocolError.ShuttingDown:
+ disconnectMsg = self.Message(
+ consts.Message.ClientDisconnected,
+ DisconnectReason=consts.DisconnectReason.Shutdown,
+ Param=None,
+ )
+ self._close(disconnectMsg)
+ return True
+
+
+ if requestIdentifier is None:
+ self.events.ProtocolError(msg)
+ return True
+
+ if initialRequest is None:
+ return False
+
+
+ # handle DDA errors
+ elif code == consts.ProtocolError.DDADenied:
+ ddaRequestMsg = self.Message(consts.Message.TestDDARequest)
+ if initialRequest.name == consts.Message.ClientGet:
+ ddaRequestMsg['WantWriteDirectory'] = True
+ directory = os.path.dirname(initialRequest['Filename'])
+ else:
+ ddaRequestMsg['WantReadDirectory'] = True
+ directory = os.path.dirname(initialRequest['Filename'])
+ ddaRequestMsg['Directory'] = directory
+
+ # add params required for testing
+ initialRequest['FcTestDDA'] = {
+ 'Directory': directory,
+ 'Replied': False,
+ 'TmpFile': None,
+ 'WantWrite': ddaRequestMsg.get('WantWriteDirectory', False),
+ 'ErrorMsg': msg,
+ }
+ self._ddaTests.append(initialRequest)
+ self.sendMessageEx(ddaRequestMsg)
+ return True
+
+
+ # handle filename collisions
+ elif code == consts.ProtocolError.DiskTargetExists:
+ handleCollision = initialRequest.get('FcFilenameCollision', consts.FilenameCollision.HandleNever)
+ collisionHandled = bool(handleCollision & consts.FilenameCollision.CollisionHandled)
+
+ # rename filename
+ if handleCollision & consts.FilenameCollision.HandleRename:
+ filename = initialRequest['Filename']
+ initialRequest['FcFilenameCollision'] |= consts.FilenameCollision.CollisionHandled
+ newFilename = namespace.unique_filename(filename, extensions=1, ispostfixed=collisionHandled)
+ initialRequest['Filename'] = newFilename
+ initialRequest['FcModified'] = {consts.RequestModified.Filename: filename}
+ self.sendMessageEx(initialRequest)
+ self.events.RequestModified(initialRequest)
+ return True
+
+ # don't handle
+ else:
+ initialRequest['FcFilenameCollision'] &= ~consts.FilenameCollision.CollisionHandled
+
+
+ # handle plugin related request failures
+ elif code == consts.ProtocolError.NoSuchPlugin or code == consts.ProtocolError.AccessDenied:
+ if initialRequest.name == consts.Message.GetPluginInfo:
+ initialRequest['FcErrorMessage'] = msg
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
+ self._finalizeRequest(msg, initialRequest, self.events.PluginInfoFailed)
+ return True
+
+ # TODO: just a guess that FCPPluginMessage can trigger an AccessDenied error
+ elif initialRequest.name == consts.Message.FCPPluginMessage:
+ initialRequest['FcErrorMessage'] = msg
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
+ self._finalizeRequest(msg, initialRequest, self.events.PluginMessageFailed)
+ return True
+
+ # only requests should get through to here
+
+ # NOTE: Fcp already removed the request
+ initialRequest['FcErrorMessage'] = msg
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
+ self._finalizeRequest(msg, initialRequest, self.events.RequestFailed)
+ return True
+
+
+ ####################################################
+ ##
+ ## TestDDA
+ ##
+ ## We assume that a DDATest messages do not get mixed up. 1st TestDDARequest is first to
+ ## enter TestDDAReply and TestDDAComplete. Hopefuly the freenet devels will rework the
+ ## TestDDA drill.
+ ##
+ ####################################################
+ elif msg.name == consts.Message.TestDDAReply:
+ directory = msg['Directory']
+
+ # find message that triggered the call
+ for initialRequest in self._ddaTests:
+ if initialRequest['FcTestDDA']['Directory'] == directory:
+ if not initialRequest['FcTestDDA']['Replied']:
+ initialRequest['FcTestDDA']['Replied'] = True
+ break
+ else:
+ # fell through
+ raise ValueError('No inital message found in TestDDAReply')
+
+ # perform read test if necessary
+ fpathRead = msg.params.get('ReadFilename', None)
+ readContent = ''
+ if fpathRead is not None:
+ readContent = tools.saveReadFile(fpathRead)
+ if readContent is None:
+ readContent = ''
+
+ # perform write test if necessary
+ fpathWrite = msg.params.get('WriteFilename', None)
+ if fpathWrite is not None:
+ written = tools.saveWriteFile(fpathWrite, msg['ContentToWrite'])
+ if not written:
+ tools.saveRemoveFile(fpathWrite)
+ else:
+ initialRequest['FcTestDDA']['TmpFile'] = fpathWrite
+
+ self.sendMessage(
+ consts.Message.TestDDAResponse,
+ Directory=msg['Directory'],
+ ReadContent=readContent,
+ )
+ return True
+
+
+ elif msg.name == consts.Message.TestDDAComplete:
+ # clean up tmp file
+ directory = msg['Directory']
+
+ # find message that triggered the call
+ for initialRequest in self._ddaTests:
+ if initialRequest['FcTestDDA']['Directory'] == directory:
+ if initialRequest['FcTestDDA']['Replied']:
+ break
+ else:
+ # fell through
+ raise ValueError('No initial message found in TestDDAComplete')
+
+ # remove test and clean tmp data
+ self._ddaTests.remove(initialRequest)
+ if initialRequest['FcTestDDA']['TmpFile'] is not None:
+ tools.saveRemoveFile(initialRequest['FcTestDDA']['TmpFile'])
+ wantWrite = initialRequest.params['FcTestDDA']['WantWrite']
+
+ # check if test was sucessful
+ testFailed = False
+ if wantWrite:
+ testFailed = not msg.params.get('WriteDirectoryAllowed', False)
+ else:
+ testFailed = not msg.params.get('ReadDirectoryAllowed', False)
+
+ if testFailed:
+ #TODO: check if errorMsg gives reasonable feedback
+ initialRequest['FcRequestStatus'] = consts.RequestStatus.Error
+ initialRequest['FcErrorMessage'] = initialRequest['FcTestDDA']['ErrorMsg']
+ self._finalizeRequest(msg, initialRequest, self.events.RequestFailed)
+ return True
+
+ # else: resend message
+ self.sendMessageEx(initialRequest)
+ return True
+
+ ####################################################
+ ##
+ ## config related
+ ##
+ ####################################################
+ elif msg.name == consts.Message.ConfigData:
+ self.events.ConfigData(msg)
+ return True
+
+ elif msg.name == consts.Message.NodeData:
+ self.events.NodeData(msg)
+ return True
+
+ ####################################################
+ ##
+ ## get / put related
+ ##
+ ####################################################
+ elif msg.name == consts.Message.AllData:
+ if initialRequest is None:
+ return False
+
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
+ initialRequest.data = msg.data
+ self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted)
+ return True
+
+ elif msg.name == consts.Message.DataFound:
+ if initialRequest is None:
+ return False
+
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
+ initialRequest['FcMetadataContentType'] = msg.get('Metadata.ContentType', '')
+ initialRequest['FcDataLength'] = msg.get('DataLength', '')
+
+ # except from GetData all requests are complete here. Next GetData will run through AllData...
+
+ # For GetData with persistence != connection the node sends no All Data message
+ # whatever that is good for ..fix this here to get all GetData request to complete on
+ # All Data.
+ if initialRequest['FcRequestType'] == consts.RequestType.GetData:
+ if initialRequest['Persistence'] != consts.Persistence.Connection:
+ self.sendMessage(
+ consts.Message.GetRequestStatus,
+ Identifier=initialRequest['Identifier'],
+ Global=False,
+ OnlyData=True
+ )
+ else:
+ self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted)
+
+ return True
+
+
+ elif msg.name == consts.Message.GetFailed:
+ if initialRequest is None:
+ return False
+
+ code = msg['Code']
+ if code == consts.FetchError.Canceled:
+ return False
+
+ # check if it is one of our requests for key information
+ if code == consts.FetchError.TooBig and initialRequest['FcRequestType'] == consts.RequestType.GetKeyInfo:
+ initialRequest['FcMetadataContentType'] = msg.get('ExpectedMetadata.ContentType', '')
+ initialRequest['FcDataLength'] = msg.get('ExpectedDataLength', -1)
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
+ self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted)
+ else:
+ initialRequest['FcErrorMessage'] = msg
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
+ self._finalizeRequest(msg, initialRequest, self.events.RequestFailed)
+ return True
+
+
+ elif msg.name == consts.Message.PersistentGet:
+
+ # unknown request... try to restore it
+ if initialRequest is None:
+ fcParams = self.FcParams.paramsFromRequest(msg)
+
+ # not one of our requests... so cancel it
+ if fcParams is None or CancelPersistentRequests:
+ self.sendMessage(
+ consts.Message.RemovePersistentRequest,
+ Identifier=requestIdentifier,
+ Global=msg['Global'],
+ )
+ return True
+
+ initialRequest = copy.deepcopy(msg)
+ self._registerRequest(
+ initialRequest,
+ fcParams[self.FcParams.IRequestType],
+ identifier=requestIdentifier,
+ initTime=fcParams[self.FcParams.IInitTime],
+ userData=None,
+ persistentUserData=fcParams[self.FcParams.IPersistentUserData],
+ filenameCollision=fcParams[self.FcParams.IFilenameCollision],
+ )
+
+ initialRequest.name = consts.Message.ClientGet
+ #FIX: remove Started param from PersistentGet / Put
+ del initialRequest.params['Started']
+ #FIX: [0001965: Persistence vs PersistenceType]
+ if 'PersistenceType' in initialRequest.params:
+ initialRequest['Persistence'] = initialRequest.params.pop('PersistenceType')
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Restored
+ self.events.RequestRestored(initialRequest)
+ return True
+
+ # known request ..we don't handle that
+ return False
+
+
+ elif msg.name == consts.Message.PersistentRequestModified:
+ if initialRequest is None:
+ return False
+
+ modified = {}
+
+ # check if PersistentUserData has changed
+ params = self.FcParams.paramsFromRequest(initialRequest)
+ if params is not None:
+ clientToken = msg.get('ClientToken', None)
+ if clientToken is not None:
+
+ #TODO: its more or less a guess that PersistentUserData has changed
+ # ...as long as no other param is changed at runtime we are ok
+ # otherwise we would have to set flags to indicate wich member
+ # of ClientToken changed. See --> modifyRequest()
+ modified[consts.RequestModified.PersistentUserData] = None
+ for i, fcParam in enumerate(self.FcParams.FcParams):
+ initialRequest[fcParam] = params[i]
+
+ # check if PriorityClass has changed
+ priorityClass = msg.get('PriorityClass', None)
+ if priorityClass is not None:
+ modified[consts.RequestModified.PriorityClass] = None
+ initialRequest['PriorityClass'] = priorityClass
+
+ initialRequest['FcModified'] = modified
+ self.events.RequestModified(initialRequest)
+ return True
+
+
+ elif msg.name == consts.Message.PersistentRequestRemoved:
+ if initialRequest is None:
+ return False
+
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Removed
+ self._finalizeRequest(msg, initialRequest, self.events.RequestRemoved)
+ return True
+
+
+ elif msg.name == consts.Message.SimpleProgress:
+ if initialRequest is None:
+ return False
+
+ initialRequest['FcProgressTotal'] = msg['Total']
+ initialRequest['FcProgressRequired'] = msg['Required']
+ initialRequest['FcProgressFailed'] = msg['Failed']
+ initialRequest['FcProgressFatalyFailed'] = msg['FatallyFailed']
+ initialRequest['FcProgressSucceeeded'] = msg['Succeeded']
+ self.events.RequestProgress(initialRequest)
+ return True
+
+ ## put related
+
+ elif msg.name == consts.Message.PersistentPut:
+
+ # unknown request... try to restore it
+ if initialRequest is None:
+ fcParams = self.FcParams.paramsFromRequest(msg)
+
+ # not one of our requests... so cancel it
+ if fcParams is None or CancelPersistentRequests:
+ self.sendMessage(
+ consts.Message.RemovePersistentRequest,
+ Identifier=requestIdentifier,
+ Global=msg['Global'],
+ )
+ return True
+
+ initialRequest = copy.deepcopy(msg)
+ requestType = fcParams[self.FcParams.IRequestType]
+ self._registerRequest(
+ initialRequest,
+ requestType,
+ identifier=requestIdentifier,
+ initTime=fcParams[self.FcParams.IInitTime],
+ userData=None,
+ persistentUserData=fcParams[self.FcParams.IPersistentUserData],
+ filenameCollision=fcParams[self.FcParams.IFilenameCollision],
+ )
+
+ # determine initial message name
+ if requestType in (consts.RequestType.PutData, consts.RequestType.PutFile):
+ initialRequest.name = consts.Message.ClientPut
+ elif requestType == consts.RequestType.PutDir:
+ initialRequest.name = consts.Message.ClientPutDiskDir
+ elif requestType == consts.RequestType.PutMultiple:
+ initialRequest.name = consts.Message.ClientPutComplexDir
+
+ #FIX: remove Started param from PersistentGet / Put
+ del initialRequest.params['Started']
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Restored
+ self.events.RequestRestored(initialRequest)
+ return True
+
+ # known request ..we don't handle that
+ return False
+
+
+ elif msg.name == consts.Message.PutFailed:
+ if initialRequest is None:
+ return False
+
+ code = msg['Code']
+ if code == consts.InsertError.Canceled:
+ return False
+
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
+ initialRequest['FcErrorMessage'] = msg
+ self._finalizeRequest(msg, initialRequest, self.events.RequestFailed)
+ return True
+
+
+ elif msg.name == consts.Message.PutFetchable:
+ if initialRequest is None:
+ # something went wrong
+ return False
+
+ self.events.RequestFetchable(initialRequest)
+ return True
+
+
+ elif msg.name == consts.Message.PutSuccessful:
+ if initialRequest is None:
+ return False
+ # TODO: StartupTime and CompletionTime are passed, but
+ # as long as no corrosponding params are passed in DataFound
+ # we ignore them
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
+ initialRequest['URI'] = msg['URI']
+ self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted)
+ return True
+
+
+ elif msg.name == consts.Message.URIGenerated:
+ if initialRequest is None:
+ return False
+ initialRequest['URI'] = msg['URI']
+ return True
+
+ elif msg.name == consts.Message.FinishedCompression:
+ if initialRequest is None:
+ return False
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Compressed
+ self.events.RequestCompressionFinished(initialRequest)
+ return True
+
+ elif msg.name == consts.Message.StartedCompression:
+ if initialRequest is None:
+ return False
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Compressing
+ self.events.RequestCompressionStarted(initialRequest)
+ return True
+
+ ####################################################
+ ##
+ ## Peer related messages
+ ##
+ ####################################################
+ elif msg.name == consts.Message.EndListPeers:
+ self.events.EndListPeers(msg)
+ return True
+
+ elif msg.name == consts.Message.EndListPeerNotes:
+ self.events.EndListPeerNotes(msg.params)
+ return True
+
+ elif msg.name == consts.Message.Peer:
+ self.events.Peer(msg)
+ return True
+
+ elif msg.name == consts.Message.PeerNote:
+ self.events.PeerNote(msg)
+ return True
+
+ elif msg.name == consts.Message.PeerRemoved:
+ self.events.PeerRemoved(msg)
+ return True
+
+ elif msg.name == consts.Message.UnknownNodeIdentifier:
+ self.events.PeerUnknown(msg)
+ return True
+
+ elif msg.name == consts.Message.UnknownPeerNoteType:
+ self.events.PeerNoteTypeUnknown(msg)
+ return True
+ ####################################################
+ ##
+ ## plugins
+ ##
+ ####################################################
+ elif msg.name == consts.Message.PluginInfo:
+ if initialRequest is None:
+ return False
+
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
+ self._finalizeRequest(msg, initialRequest, self.events.PluginInfo)
+ return True
+
+ elif msg.name == consts.Message.FCPPluginReply:
+ if initialRequest is None:
+ return False
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
+ initialRequest['FcPluginReply'] = msg
+ self._finalizeRequest(msg, initialRequest, self.events.PluginMessage)
+ return True
+
+ ####################################################
+ ##
+ ## others
+ ##
+ ####################################################
+ elif msg.name == consts.Message.CloseConnectionDuplicateClientName:
+ disconnectMsg = self.Message(
+ consts.Message.ClientDisconnected,
+ DisconnectReason=consts.DisconnectReason.DuplicateClientName,
+ Param=None,
+ )
+ self._close(disconnectMsg)
+ return True
+
+
+ elif msg.name == consts.Message.SSKKeypair:
+ if initialRequest is None:
+ return False
+
+ #TODO:no idea if the node may pass uris with prefixes like 'freenet:'... strip it anyways
+ insertURI = self.Uri(msg['InsertURI']).uri
+ requestURI = self.Uri(msg['RequestURI']).uri
+
+ if initialRequest['FcRequestType'] == consts.RequestType.GenerateUSKKeypair:
+ insertURI = insertURI.replace(consts.KeyType.SSK, consts.KeyType.USK, 1)
+ requestURI = requestURI.replace(consts.KeyType.SSK, consts.KeyType.USK, 1)
+
+ initialRequest['FcPrivateKey'] = insertURI
+ initialRequest['FcPublicKey'] = requestURI
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
+ self._finalizeRequest(msg, initialRequest, self.events.KeypairGenerated)
+ return True
+
+ elif msg.name == consts.Message.SubscribedUSKUpdate:
+ if initialRequest is None:
+ return False
+ self.events.USKUpdated(msg)
+ return True
+
+
+ # default
+ return False
+
+
+ def next(self, dispatch=True):
+ """Pumps the next message waiting
+ @param dispatch: if True the message is dispatched to L{handleMessage}
+ @note: use this method to run the client step by step. If you want to run the
+ client unconditionally use L{run}
+ """
+ msg = self.Message.fromSocket(self._socket)
+ if msg.name == consts.Message.ClientSocketDied:
+ self._logRuntime.critical(consts.LogMessages.SocketDied)
+ if dispatch:
+ disconnectMsg = self.Message(
+ consts.Message.ClientDisconnected,
+ DisconnectReason=consts.DisconnectReason.SocketDied,
+ Param=msg,
+ )
+ self._close(disconnectMsg)
+ #raise socket.error(msg['Param']['Details'])
+
+ elif msg.name == consts.Message.ClientSocketTimeout:
+ if dispatch:
+ self.events.Idle(msg)
+ else:
+ self._logMessage.debug(consts.LogMessages.MessageReceived + msg.pprint())
+ if dispatch:
+ self.handleMessage(msg)
+ return msg
+
+
+ def run(self):
+ """Runs the client unconditionally untill all requests have completed
+ @note: a KeyboardInterrupt will stop the client
+ """
+
+ #FIX: 0001931
+ # poll a few times to see if there are persistent requests waiting
+ t0 = time.time()
+ while time.time() - t0 <= self.MinimumRunTime:
+ try:
+ msg = self.next()
+ except KeyboardInterrupt:
+ self._logRuntime.info(consts.LogMessages.KeyboardInterrupt)
+ return
+ if msg.name == consts.Message.ClientSocketDied:
+ return
+
+ #n = 0
+ while True:
+ #n += 1
+ #if n > 50: break
+
+ # check if we have running requests. Assert False
+ haveRunningRequests = False
+ for request in self._requests.values():
+ if not request['FcRequestStatus'] & consts.RequestStatus.Completed:
+ haveRunningRequests = True
+ break
+
+ if not haveRunningRequests:
+ self._logRuntime.info(consts.LogMessages.AllRequestsCompleted)
+ break
+
+ try:
+ msg = self.next()
+ except KeyboardInterrupt:
+ self._logRuntime.info(consts.LogMessages.KeyboardInterrupt)
+ break
+
+ if msg.name == consts.Message.ClientSocketDied:
+ break
+
+
+ def sendMessage(self, name, data=None, **params):
+ """Sends a message to freenet
+ @param name: name of the message to send
+ @param data: data to atatch to the message
+ @param params: {para-name: param-calue, ...} of parameters to pass along
+ with the message (see freenet protocol)
+ @raise SocketError: if the socket connection to the node dies unexpectedly
+ If an error handler is passed to the client it is called emidiately before the error
+ is raised.
+
+ @note: you can use this method to send a message to the node, bypassing all
+ track keeping methods of the client
+ """
+ return self.sendMessageEx(self.Message(name, data=data, **params))
+
+
+ def sendMessageEx(self, msg):
+ """Sends a message to freenet
+ @param msg: (Message) message to send
+ @return: Message
+ @raise SocketError: if the socket connection to the node dies unexpectedly.
+ If an error handler is passed to the client it is called emidiately before the error
+ is raised.
+
+ @note: you can use this method to send a message to the node, bypassing all
+ track keeping methods of the client
+ """
+ self._logMessage.debug(consts.LogMessages.MessageSend + msg.pprint())
+ try:
+ msg.send(self._socket)
+ except socket.error, d:
+ self._logRuntime.critical(consts.LogMessages.SocketDied)
+ disconnectMsg = self.Message(
+ consts.Message.ClientDisconnected,
+ DisconnectReason=consts.DisconnectReason.SocketDied,
+ Param=self.Message(consts.Message.ClientSocketDied, Exception=socket.error, Details=d)
+ )
+ self._close(disconnectMsg)
+ raise socket.error(d)
+ return msg
+
+ #########################################################
+ ##
+ ## config related methods
+ ##
+ #########################################################
+ def getConfig(self,
+ withCurrent=True,
+ withDefaults=True,
+ withExpertFlag=True,
+ withForceWriteFlag=True,
+ withSortOrder=True,
+ withShortDescription=True,
+ withLongDescription=True,
+ ):
+ """
+ @event: ConfigData(event, msg)
+ """
+ self.sendMessage(
+ consts.Message.GetConfig,
+ WithSortOrder=withSortOrder,
+ WithCurrent=withCurrent,
+ WithDefaults=withDefaults,
+ WithExpertFlag=withExpertFlag,
+ WithForceWriteFlag=withForceWriteFlag,
+ WithShortDescription=withShortDescription,
+ WithLongDescription=withLongDescription,
+ )
+
+
+ def modifyConfig(self, params):
+ """Modifies node configuration values
+ @param params: (dict) containing parameters to modify
+ """
+ msg = self.Message(consts.Message.ModifyConfig)
+ msg.params = params
+ self.sendMessageEx(msg)
+
+
+ ########################################################
+ ##
+ ## ClientGet related methods
+ ##
+ ########################################################
+ def clientGet(self,
+ uri,
+ requestType,
+ userData,
+ persistentUserData,
+ filenameCollision,
+ **messageParams
+ ):
+ """Requests a key from the node
+ @param uri: (str) uri of the file to request (may contain prefixes like 'freenet:' or 'http://')
+ @param requestType: (L{consts.RequestType}) sub type of the message
+ @param userData: any non persistent data to associate to the request or None
+ @param persistentUserData: any string to associate to the request as persistent data or None
+ @param filenameCollision: what to do if the disk target alreaady exists. One of the FilenameCollision.* consts
+ @param messageParams: keyword arguments to pass along with the ClientGet message (uppercase first letter!!).
+ If the value of a keyword is None, it is ignored.
+
+ @return: (str) identifier of the request
+ """
+ uri = self.Uri(uri).uri
+ msg = self.Message(consts.Message.ClientGet, URI=uri)
+ for paramName, value in messageParams.items():
+ if value is not None:
+ msg[paramName] = value
+
+ self._registerRequest(
+ msg,
+ requestType,
+ filenameCollision=filenameCollision,
+ persistentUserData=persistentUserData,
+ userData=userData,
+ )
+ self.sendMessageEx(msg)
+ return msg['Identifier']
+
+
+
+ def getData(self,
+ uri,
+
+ allowedMimeTypes=None,
+ binaryBlob=False,
+ dsOnly=False,
+ ignoreDS=False,
+ maxRetries=None,
+ maxSize=None,
+ persistence=consts.Persistence.Connection,
+ priorityClass=consts.Priority.Medium,
+
+ userData=None,
+ persistentUserData='',
+ ):
+ """Requests datae from the node
+
+ @param uri: uri of the data to request (may contain prefixes like 'freenet:' or 'http://')
+
+ @param allowedMimeTypes: (str) list of allowed mime types
+ @param binaryBlob: (bool) if True, the file is retrieved as binary blob file
+ @param dsOnly: (bool) if True, retrieves the file from the local data store only
+ @param ignoreDS: (bool) if True, ignores the local data store
+ @param maxRetries: (int) maximum number of retries or -1 to retry forver or None to leave it to the node to decide
+ @param maxSize: (int) maximum size of the file in bytes or None to set no limited
+ @param persistence: (L{consts.Persistence}) persistence of the request
+ @param priorityClass: (L{consts.Priority}) priority of the request
+ @param userData: any non persistent data to associate to the request
+ @param persistentUserData: any string to associate to the request as persistent data
+
+ @return: (str) request identifier
+
+ @event: L{Events.RequestCompleted} triggered as soon as the request is complete
+ @event: L{Events.RequestFailed} triggered if the request failes
+ @event: L{Events.RequestStarted} triggered as soon as the request is started
+ @event: L{Events.RequestModified} trigggered if the request identifier changes
+ or the request is modified otherwise (see L{modifyRequest})
+
+ @note: the identifier of the request may change at any time. You should be prepaired to handle
+ this
+ @note: if persistence is L{consts.Persistence.Connection} the request is removed from the client
+ as soon as it completes or failes
+ """
+ return self.clientGet(
+ uri,
+ consts.RequestType.GetData,
+ userData,
+ persistentUserData,
+ consts.FilenameCollision.HandleNever,
+
+ # Fcp params
+ AllowedMimeTypes = allowedMimeTypes,
+ BinaryBlob=binaryBlob,
+ Global=False,
+ DSOnly=dsOnly,
+ Identifier=None,
+ IgnoreDS=ignoreDS,
+ MaxRetries = maxRetries,
+ MaxSize = maxSize,
+ Persistence=persistence,
+ PriorityClass=priorityClass,
+ ReturnType=consts.ReturnType.Direct,
+ URI=self.Uri(uri).uri,
+ Verbosity=consts.Verbosity.ReportProgress,
+ )
+
+
+ def getFile(self,
+ uri,
+ filename,
+
+ allowedMimeTypes=None,
+ binaryBlob=False,
+ dsOnly=False,
+ ignoreDS=False,
+ maxRetries=None,
+ maxSize=None,
+ persistence=consts.Persistence.Connection,
+ priorityClass=consts.Priority.Medium,
+
+ userData=None,
+ persistentUserData='',
+ filenameCollision=consts.FilenameCollision.HandleNever,
+ ):
+ """Requests a file from the node
+
+ @param uri: uri of the file to request (may contain prefixes like 'freenet:' or 'http://')
+ @param filename: (full path) filename to store the file to
+
+ @param allowedMimeTypes: (str) list of allowed mime types
+ @param binaryBlob: if True, the file is retrieved as binary blob file
+ @param dsOnly: if True, retrieves the file from the local data store only
+ @param ignoreDS: If True, ignores the local data store
+ @param maxRetries: (int) maximum number of retries or -1 to retry forver or None to leave it to the node to decide
+ @param maxSize: (int) maximum size of the file in bytes or None to set no limited
+ @param persistence: (L{consts.Persistence}) persistence of the request
+ @param priorityClass: (L{consts.Priority}) priority of the request
+ @param filenameCollision: what to do if the disk target alreaady exists. One of the FilenameCollision.* consts
+ @param userData: any non persistent data to associate to the request
+ @param persistentUserData: any string to associate to the request as persistent data
+
+ @return: (str) request identifier
+
+ @event: RequestCompleted(event, message) triggered when the request is complete
+ @event: RequestFailed(event, message) triggered when the request failes
+ @event: RequestStarted(event, message) triggered when as the request is started
+ @event: RequestModified(event, message) trigggered if the request identifier changes,
+ filename changes or the request is modified otherwise (see L{modifyRequest})
+
+ @note: if persistence is L{consts.Persistence.Connection} the request is removed from the client
+ as soon as it completes or failes
+ """
+ return self.clientGet(
+ uri,
+ consts.RequestType.GetFile,
+ userData,
+ persistentUserData,
+ filenameCollision,
+
+ # Fcp params
+ AllowedMimeTypes = allowedMimeTypes,
+ BinaryBlob=binaryBlob,
+ Filename=filename,
+ Global=False,
+ DSOnly=dsOnly,
+ Identifier=None,
+ IgnoreDS=ignoreDS,
+ MaxRetries = maxRetries,
+ MaxSize = maxSize,
+ Persistence=persistence,
+ PriorityClass=priorityClass,
+ ReturnType=consts.ReturnType.Disk,
+ URI=self.Uri(uri).uri,
+ Verbosity=consts.Verbosity.ReportProgress,
+ )
+
+
+ def getKeyInfo(self,
+ uri,
+
+ dsOnly=False,
+ ignoreDS=False,
+ maxRetries=None,
+ persistence=consts.Persistence.Connection,
+ priorityClass=consts.Priority.Medium,
+
+ userData=None,
+ persistentUserData='',
+ ):
+ """Requests info about a key
+
+ @param uri: uri of the file to request (may contain prefixes like 'freenet:' or 'http://')
+
+ @param dsOnly: if True, retrieves the file from the local data store only
+ @param ignoreDS: If True, ignores the local data store
+ @param maxRetries: (int) maximum number of retries or -1 to retry forver or None to leave it to the node to decide
+ @param persistence: (L{consts.Persistence}) persistence of the request
+ @param priorityClass: (L{consts.Priority}) priority of the request
+ @param userData: any non persistent data to associate to the request
+ @param persistentUserData: any string to associate to the request as persistent data
+
+ @return: (str) request identifier
+
+ @event: RequestCompleted(event, message) triggered when the request is complete
+ @event: RequestFailed(event, message) triggered when the request failes
+ @event: RequestStarted(event, message) triggered when as the request is started
+ @event: RequestModified(event, message) trigggered if the request identifier changes
+ or the request is modified otherwise (see L{modifyRequest})
+
+ @note: if persistence is L{consts.Persistence.Connection} the request is removed from the client
+ as soon as it completes or failes
+ """
+ # how to retrieve meta info about a key? ...idea is to provoke a GetFailed (TooBig)
+ return self.clientGet(
+ uri,
+ consts.RequestType.GetKeyInfo,
+ userData,
+ persistentUserData,
+ consts.FilenameCollision.HandleNever,
+
+ # Fcp params
+ Global=False,
+ DSOnly=dsOnly,
+ Identifier=None,
+ IgnoreDS=ignoreDS,
+ MaxRetries = maxRetries,
+ MaxSize=self.MaxSizeKeyInfo,
+ Persistence=persistence,
+ PriorityClass=priorityClass,
+ ReturnType=consts.ReturnType.Nothing,
+ URI=self.Uri(uri).uri,
+ Verbosity=consts.Verbosity.ReportProgress,
+ )
+
+
+
+ #TODO: persists until connection is closed... can this request be removed?
+ def subscribeUSK(self, uri, dontPoll=True):
+ """Asks the node to notify the client when an USK is updated
+ @param uri: uri of the USK to subscribe to
+ @param dontPoll: if True, does whatever ???
+ @return: (str) identifer of the request
+
+ @note: this request can not be removed or modified and the {consts.RequestStatus.Completed}
+ flag is always set
+ """
+ msg = self.Message(
+ consts.Message.SubscribeUSK,
+ URI=uri,
+ DontPoll=dontPoll,
+ )
+ self._registerRequest(msg, consts.RequestType.SubscribeUSK)
+ msg['FcRequestStatus'] |= consts.RequestStatus.Completed
+ self.sendMessageEx(msg)
+ return msg['Identifier']
+
+
+ ########################################################
+ ##
+ ## CHK ClientPut related methods
+ ##
+ ########################################################
+ def clientPut(self,
+ requestType,
+ uri,
+ data=None,
+ persistentUserData='',
+ userData=None,
+ items=None,
+ **msgParams
+ ):
+ """Uploads to the node
+ @param requestType: (L{consts.RequestType}). Can be PutData, PutDir or PutMultiple
+ @param uri:
+ @param data: (str) for L{consts.RequestType.PutData} data to upload or None
+ @param persistentUserData: (str) persistent data to be assosiated to the request
+ @param userData: (any) any data to be associated to the request at runtime
+ @param items: for L{consts.RequestType.PutMultiple}, items to upload
+ @param msgParams: (dict) Fcp parameters to pass along with the message
+
+ @note: the Fcp message parameter 'Metadata.ContentType' may be passed as 'ContentType'
+ to this method
+ @note: to upload multiple items at once (see: PutComplexDir) pass a dict for each item
+ containig the following members:
+
+ - FcRequestType: L{consts.RequestType.PutData}, L{consts.RequestType.PutFile} or L{consts.RequestType.PutRedirect}
+ - Data: if requestType is L{consts.RequestType.PutData}, data to upload
+ - Filename: if requestType is L{consts.RequestType.PutFile}, filepath of the file to upload
+ - TargetURI: if requestType is L{consts.RequestType.PutRedirect}, uri to redirect to
+ - Name: name under wich the item will be accesible via freenet
+ - Metadata.ContentType: (optional) may be passed as 'ContentType'
+
+ All items will be accessible under one single key as 'Uri/Name'. The defaul...
[truncated message content] |
|
From: <ju...@us...> - 2008-02-26 09:43:13
|
Revision: 253
http://fclient.svn.sourceforge.net/fclient/?rev=253&view=rev
Author: jurner
Date: 2008-02-26 01:43:17 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
beautified relative importrs
Modified Paths:
--------------
trunk/sandbox/fcp/fcp2_0_client.py
trunk/sandbox/fcp/fcp2_0_config.py
trunk/sandbox/fcp/fcp2_0_events.py
trunk/sandbox/fcp/fcp2_0_message.py
trunk/sandbox/fcp/fcp2_0_params.py
trunk/sandbox/fcp/fcp2_0_types.py
trunk/sandbox/fcp/fcp2_0_uri.py
trunk/sandbox/fcp/scripts/gen_docs.py
trunk/sandbox/fcp/scripts/gen_messagecheatsheet.py
trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py
trunk/sandbox/fcp/test_fcp/test_fcp2_0_config.py
trunk/sandbox/fcp/test_fcp/test_fcp2_0_message.py
Modified: trunk/sandbox/fcp/fcp2_0_client.py
===================================================================
--- trunk/sandbox/fcp/fcp2_0_client.py 2008-02-26 09:09:30 UTC (rev 252)
+++ trunk/sandbox/fcp/fcp2_0_client.py 2008-02-26 09:43:17 UTC (rev 253)
@@ -177,16 +177,10 @@
# TODO: check if this is a bug in Fcp
# NOTE: seems to be fixed in [build 1112], fixes removed
#-------------------------------------------------------------------------------------------------------------------------------------------------
-
-
-
-
import atexit
import copy
-import cPickle
import logging
import os
-import random
import socket
import subprocess
import sys
@@ -194,31 +188,29 @@
#--> rel import hack
-class SysPathHack(object):
+class _RelImportHack(object):
def __init__(self, n):
fpath = os.path.abspath(__file__)
for i in xrange(n): fpath = os.path.dirname(fpath)
sys.path.insert(0, fpath)
def __del__(self): sys.path.pop(0)
-hack = SysPathHack(3)
+hack = _RelImportHack(2)
-from fcp_lib import namespace
+import fcp.fcp2_0_consts as consts
+from fcp.fcp2_0_events import Events
+from fcp.fcp2_0_config import Config
+from fcp.fcp2_0_message import Message
+import fcp.fcp2_0_params as FcParams
+from fcp.fcp2_0_uri import Uri
+from fcp.fcp_lib import namespace
+from fcp.fcp_lib import tools
+
del hack
#<-- rel import hack
-import fcp2_0_consts as consts
-from fcp2_0_events import Events
-from fcp2_0_config import Config
-from fcp2_0_message import Message
-import fcp2_0_params as FcParams
-from fcp2_0_uri import Uri
-
-from fcp_lib import tools
-
-
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
#*************************************************************************************************
#
Modified: trunk/sandbox/fcp/fcp2_0_config.py
===================================================================
--- trunk/sandbox/fcp/fcp2_0_config.py 2008-02-26 09:09:30 UTC (rev 252)
+++ trunk/sandbox/fcp/fcp2_0_config.py 2008-02-26 09:43:17 UTC (rev 253)
@@ -1,8 +1,24 @@
"""Sketch for fcp config tree"""
+import os, sys
import logging
-import fcp2_0_consts as consts
-import fcp2_0_types as types
+
+#--> rel import hack
+class _RelImportHack(object):
+ def __init__(self, n):
+ fpath = os.path.abspath(__file__)
+ for i in xrange(n): fpath = os.path.dirname(fpath)
+ sys.path.insert(0, fpath)
+ def __del__(self): sys.path.pop(0)
+hack = _RelImportHack(2)
+
+from fcp import fcp2_0_consts as consts
+from fcp import fcp2_0_types as types
+from fcp.fcp_lib import uuid
+
+
+del hack
+#<-- rel import hack
#****************************************************************************************
#
#****************************************************************************************
Modified: trunk/sandbox/fcp/fcp2_0_events.py
===================================================================
--- trunk/sandbox/fcp/fcp2_0_events.py 2008-02-26 09:09:30 UTC (rev 252)
+++ trunk/sandbox/fcp/fcp2_0_events.py 2008-02-26 09:43:17 UTC (rev 253)
@@ -2,9 +2,23 @@
"""
+import os, sys
-from fcp_lib import events
-import fcp2_0_consts as consts
+#--> rel import hack
+class _RelImportHack(object):
+ def __init__(self, n):
+ fpath = os.path.abspath(__file__)
+ for i in xrange(n): fpath = os.path.dirname(fpath)
+ sys.path.insert(0, fpath)
+ def __del__(self): sys.path.pop(0)
+hack = _RelImportHack(2)
+
+from fcp import fcp2_0_types as types
+from fcp.fcp_lib import events
+
+
+del hack
+#<-- rel import hack
#*******************************************************************************
#
#*******************************************************************************
Modified: trunk/sandbox/fcp/fcp2_0_message.py
===================================================================
--- trunk/sandbox/fcp/fcp2_0_message.py 2008-02-26 09:09:30 UTC (rev 252)
+++ trunk/sandbox/fcp/fcp2_0_message.py 2008-02-26 09:43:17 UTC (rev 253)
@@ -1,11 +1,25 @@
"""Freennet Client Protocol message
"""
-
+import os, sys
import socket
-import fcp2_0_consts as consts
-import fcp2_0_types as types
+#--> rel import hack
+class _RelImportHack(object):
+ def __init__(self, n):
+ fpath = os.path.abspath(__file__)
+ for i in xrange(n): fpath = os.path.dirname(fpath)
+ sys.path.insert(0, fpath)
+ def __del__(self): sys.path.pop(0)
+hack = _RelImportHack(2)
+
+from fcp import fcp2_0_consts as consts
+from fcp import fcp2_0_types as types
+from fcp.fcp_lib import uuid
+
+
+del hack
+#<-- rel import hack
#********************************************************************************
#
#********************************************************************************
Modified: trunk/sandbox/fcp/fcp2_0_params.py
===================================================================
--- trunk/sandbox/fcp/fcp2_0_params.py 2008-02-26 09:09:30 UTC (rev 252)
+++ trunk/sandbox/fcp/fcp2_0_params.py 2008-02-26 09:43:17 UTC (rev 253)
@@ -5,18 +5,17 @@
import time
#--> rel import hack
-class SysPathHack(object):
+class _RelImportHack(object):
def __init__(self, n):
fpath = os.path.abspath(__file__)
for i in xrange(n): fpath = os.path.dirname(fpath)
sys.path.insert(0, fpath)
def __del__(self): sys.path.pop(0)
-hack = SysPathHack(3)
+hack = _RelImportHack(2)
+from fcp.fcp_lib import uuid
-from fcp_lib import uuid
-
del hack
#<-- rel import hack
#*********************************************************************************************
Modified: trunk/sandbox/fcp/fcp2_0_types.py
===================================================================
--- trunk/sandbox/fcp/fcp2_0_types.py 2008-02-26 09:09:30 UTC (rev 252)
+++ trunk/sandbox/fcp/fcp2_0_types.py 2008-02-26 09:43:17 UTC (rev 253)
@@ -4,26 +4,24 @@
"""
import os, sys
+import base64
#--> rel import hack
-class SysPathHack(object):
+class _RelImportHack(object):
def __init__(self, n):
fpath = os.path.abspath(__file__)
for i in xrange(n): fpath = os.path.dirname(fpath)
sys.path.insert(0, fpath)
def __del__(self): sys.path.pop(0)
-hack = SysPathHack(3)
+hack =_RelImportHack(2)
+from fcp import fcp2_0_consts as consts
+from fcp.fcp_lib import numbers
-from fcp_lib import numbers
-
del hack
#<-- rel import hack
-import base64
-
-import fcp2_0_consts as consts
#*************************************************************************************
#
#*************************************************************************************
Modified: trunk/sandbox/fcp/fcp2_0_uri.py
===================================================================
--- trunk/sandbox/fcp/fcp2_0_uri.py 2008-02-26 09:09:30 UTC (rev 252)
+++ trunk/sandbox/fcp/fcp2_0_uri.py 2008-02-26 09:43:17 UTC (rev 253)
@@ -1,10 +1,26 @@
"""Freennet Client Protocol uri and related methods"""
+import os, sys
import base64
import re
import urlparse
-import fcp2_0_consts as consts
+#--> rel import hack
+class _RelImportHack(object):
+ def __init__(self, n):
+ fpath = os.path.abspath(__file__)
+ for i in xrange(n): fpath = os.path.dirname(fpath)
+ sys.path.insert(0, fpath)
+ def __del__(self): sys.path.pop(0)
+hack = _RelImportHack(2)
+
+
+from fcp import fcp2_0_consts as consts
+
+
+del hack
+#<-- rel import hack
+
#**************************************************************************************
# freenet base64 for keys
#**************************************************************************************
Modified: trunk/sandbox/fcp/scripts/gen_docs.py
===================================================================
--- trunk/sandbox/fcp/scripts/gen_docs.py 2008-02-26 09:09:30 UTC (rev 252)
+++ trunk/sandbox/fcp/scripts/gen_docs.py 2008-02-26 09:43:17 UTC (rev 253)
@@ -12,8 +12,20 @@
from epydoc import cli
import subprocess
-import fcpscripts_consts as consts
-import gen_messagecheatsheet
+#--> rel import hack
+class _RelImportHack(object):
+ def __init__(self, n):
+ fpath = os.path.abspath(__file__)
+ for i in xrange(n): fpath = os.path.dirname(fpath)
+ sys.path.insert(0, fpath)
+ def __del__(self): sys.path.pop(0)
+hack = _RelImportHack(3)
+
+from fcp.scripts import fcpscripts_consts as consts
+
+
+del hack
+#<-- rel import hack
#**************************************************************************************
#
#**************************************************************************************
Modified: trunk/sandbox/fcp/scripts/gen_messagecheatsheet.py
===================================================================
--- trunk/sandbox/fcp/scripts/gen_messagecheatsheet.py 2008-02-26 09:09:30 UTC (rev 252)
+++ trunk/sandbox/fcp/scripts/gen_messagecheatsheet.py 2008-02-26 09:43:17 UTC (rev 253)
@@ -23,7 +23,20 @@
import urllib
from xml.etree import cElementTree as ET
-import fcpscripts_consts as consts
+#--> rel import hack
+class _RelImportHack(object):
+ def __init__(self, n):
+ fpath = os.path.abspath(__file__)
+ for i in xrange(n): fpath = os.path.dirname(fpath)
+ sys.path.insert(0, fpath)
+ def __del__(self): sys.path.pop(0)
+hack = _RelImportHack(3)
+
+from fcp.scripts import fcpscripts_consts as consts
+
+
+del hack
+#<-- rel import hack
#*******************************************************************************
#
#*******************************************************************************
Modified: trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py
===================================================================
--- trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py 2008-02-26 09:09:30 UTC (rev 252)
+++ trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py 2008-02-26 09:43:17 UTC (rev 253)
@@ -9,20 +9,19 @@
import unittest
#--> rel import hack
-class SysPathHack(object):
+class _RelImportHack(object):
def __init__(self, n):
fpath = os.path.abspath(__file__)
for i in xrange(n): fpath = os.path.dirname(fpath)
sys.path.insert(0, fpath)
def __del__(self): sys.path.pop(0)
-hack = SysPathHack(2)
+hack = _RelImportHack(3)
+from fcp import fcp2_0_client
+from fcp.fcp2_0_client import FcpClient
+from fcp import fcp2_0_consts as consts
-import fcp2_0_client
-from fcp2_0_client import FcpClient
-import fcp2_0_consts as consts
-
del hack
#<-- rel import hack
Modified: trunk/sandbox/fcp/test_fcp/test_fcp2_0_config.py
===================================================================
--- trunk/sandbox/fcp/test_fcp/test_fcp2_0_config.py 2008-02-26 09:09:30 UTC (rev 252)
+++ trunk/sandbox/fcp/test_fcp/test_fcp2_0_config.py 2008-02-26 09:43:17 UTC (rev 253)
@@ -5,24 +5,21 @@
import unittest
#--> rel import hack
-def parentdir(n, fpath):
- fpath = os.path.abspath(fpath)
- for i in xrange(n):
- fpath = os.path.dirname(fpath)
- return fpath
-sys.path.insert(0, parentdir(2, __file__))
+class _RelImportHack(object):
+ def __init__(self, n):
+ fpath = os.path.abspath(__file__)
+ for i in xrange(n): fpath = os.path.dirname(fpath)
+ sys.path.insert(0, fpath)
+ def __del__(self): sys.path.pop(0)
+hack = _RelImportHack(3)
-
-from fcp2_0_client import FcpClient
+from fcp.fcp2_0_client import FcpClient
Message = FcpClient.Message
-import fcp2_0_types as types
+from fcp import fcp2_0_types as types
-
-sys.path.pop(0)
-del parentdir
+del hack
#<-- rel import hack
-
from dummy_socket import DummySocket
#****************************************************************************************
#
Modified: trunk/sandbox/fcp/test_fcp/test_fcp2_0_message.py
===================================================================
--- trunk/sandbox/fcp/test_fcp/test_fcp2_0_message.py 2008-02-26 09:09:30 UTC (rev 252)
+++ trunk/sandbox/fcp/test_fcp/test_fcp2_0_message.py 2008-02-26 09:43:17 UTC (rev 253)
@@ -5,19 +5,19 @@
import unittest
#--> rel import hack
-class SysPathHack(object):
+class _RelImportHack(object):
def __init__(self, n):
fpath = os.path.abspath(__file__)
for i in xrange(n): fpath = os.path.dirname(fpath)
sys.path.insert(0, fpath)
def __del__(self): sys.path.pop(0)
-hack = SysPathHack(2)
+hack = _RelImportHack(3)
-
-from fcp2_0_client import FcpClient
+from fcp.fcp2_0_client import FcpClient
Message = FcpClient.Message
-import fcp2_0_consts as consts
+from fcp import fcp2_0_consts as consts
+
del hack
#<-- rel import hack
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-26 09:09:38
|
Revision: 252
http://fclient.svn.sourceforge.net/fclient/?rev=252&view=rev
Author: jurner
Date: 2008-02-26 01:09:30 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
documentation fix
Modified Paths:
--------------
trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py
Modified: trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py
===================================================================
--- trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py 2008-02-26 09:08:58 UTC (rev 251)
+++ trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py 2008-02-26 09:09:30 UTC (rev 252)
@@ -76,7 +76,7 @@
class MySocketFactory(object):
"""Real and alive socket. Can be used to test against the running node. Not used currently
- Usage:
+ Usage::
DummySocketModule.socket = MySocketFactory()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-26 09:08:52
|
Revision: 251
http://fclient.svn.sourceforge.net/fclient/?rev=251&view=rev
Author: jurner
Date: 2008-02-26 01:08:58 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
beautification
Modified Paths:
--------------
trunk/sandbox/fcp/fcp_lib/events.py
Modified: trunk/sandbox/fcp/fcp_lib/events.py
===================================================================
--- trunk/sandbox/fcp/fcp_lib/events.py 2008-02-26 09:08:23 UTC (rev 250)
+++ trunk/sandbox/fcp/fcp_lib/events.py 2008-02-26 09:08:58 UTC (rev 251)
@@ -109,8 +109,8 @@
@note: all listeners will be called with the event a first parameter, followed
by optional args and kwargs
"""
- for o in self.observers:
- o(self, *args, **kwargs)
+ for observer in self.observers:
+ observer(self, *args, **kwargs)
def __contains__(self, observer):
"""Checks if an observer is aleady registered
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-26 09:08:25
|
Revision: 250
http://fclient.svn.sourceforge.net/fclient/?rev=250&view=rev
Author: jurner
Date: 2008-02-26 01:08:23 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
documentation fix
Modified Paths:
--------------
trunk/sandbox/fcp/fcp2_0_message.py
Modified: trunk/sandbox/fcp/fcp2_0_message.py
===================================================================
--- trunk/sandbox/fcp/fcp2_0_message.py 2008-02-26 09:07:59 UTC (rev 249)
+++ trunk/sandbox/fcp/fcp2_0_message.py 2008-02-26 09:08:23 UTC (rev 250)
@@ -70,7 +70,7 @@
def fromSocket(clss, socketObj):
"""Reads a message from a socket
@param socketObj: socket to read a message from
- @return: L{Message} next message from the socket. If the socket dies
+ @return: (Message) next message from the socket. If the socket dies
unexpectedly a L{consts.Message.ClientSocketDied} message is returned containing the parameters
'Exception' and 'Details'. If the socket times out a L{consts.Message.ClientSocketTimeout} message is returned.
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-26 09:07:54
|
Revision: 249
http://fclient.svn.sourceforge.net/fclient/?rev=249&view=rev
Author: jurner
Date: 2008-02-26 01:07:59 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
added tools module
Added Paths:
-----------
trunk/sandbox/fcp/fcp_lib/tools.py
Added: trunk/sandbox/fcp/fcp_lib/tools.py
===================================================================
--- trunk/sandbox/fcp/fcp_lib/tools.py (rev 0)
+++ trunk/sandbox/fcp/fcp_lib/tools.py 2008-02-26 09:07:59 UTC (rev 249)
@@ -0,0 +1,57 @@
+"""Fcp tools and helpers"""
+
+import os
+#**********************************************************************
+# namespace helpers
+#**********************************************************************
+def saveReadFile(fpath):
+ """Reads contents of a file in the savest manner possible
+ @param fpath: file to write
+ @return: contents of the file if successful, None otherwise
+ """
+ read = None
+ try:
+ fp = open(fpath, 'rb')
+ except: pass
+ else:
+ try:
+ read = fp.read()
+ except: pass
+ fp.close()
+ return read
+
+def saveRemoveFile(fpath):
+ """Savely removes a file
+ @param fpath: filepath of the file to remove or None
+ @return: True if the file was removed, False otherwise
+ """
+ if fpath is not None:
+ if os.path.isfile(fpath):
+ try:
+ os.remove(fpath)
+ except Exception, d:
+ pass
+ else:
+ return True
+ return False
+
+
+def saveWriteFile(fpath, data):
+ """Writes data to a file in the savest manner possible
+ @param fpath: file to write
+ @param data: data to write to file
+ @return: True if successful, False otherwise
+ """
+ written = False
+ try:
+ fp = open(fpath, 'wb')
+ except: pass
+ else:
+ try:
+ fp.write(data)
+ written = True
+ except:
+ fp.Close()
+ else:
+ fp.close()
+ return written
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-26 09:07:35
|
Revision: 248
http://fclient.svn.sourceforge.net/fclient/?rev=248&view=rev
Author: jurner
Date: 2008-02-26 01:07:39 -0800 (Tue, 26 Feb 2008)
Log Message:
-----------
moved helpers to fcp_lib/tools module
Modified Paths:
--------------
trunk/sandbox/fcp/fcp2_0_client.py
Modified: trunk/sandbox/fcp/fcp2_0_client.py
===================================================================
--- trunk/sandbox/fcp/fcp2_0_client.py 2008-02-24 11:52:23 UTC (rev 247)
+++ trunk/sandbox/fcp/fcp2_0_client.py 2008-02-26 09:07:39 UTC (rev 248)
@@ -214,65 +214,12 @@
from fcp2_0_config import Config
from fcp2_0_message import Message
import fcp2_0_params as FcParams
-from fcp2_0_requests import Upload
from fcp2_0_uri import Uri
-logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
-#**********************************************************************
-# helpers
-#**********************************************************************
-def saveReadFile(fpath):
- """Reads contents of a file in the savest manner possible
- @param fpath: file to write
- @return: contents of the file if successful, None otherwise
- """
- read = None
- try:
- fp = open(fpath, 'rb')
- except: pass
- else:
- try:
- read = fp.read()
- except: pass
- fp.close()
- return read
+from fcp_lib import tools
-def saveRemoveFile(fpath):
- """Savely removes a file
- @param fpath: filepath of the file to remove or None
- @return: True if the file was removed, False otherwise
- """
- if fpath is not None:
- if os.path.isfile(fpath):
- try:
- os.remove(fpath)
- except Exception, d:
- pass
- else:
- return True
- return False
-
-def saveWriteFile(fpath, data):
- """Writes data to a file in the savest manner possible
- @param fpath: file to write
- @param data: data to write to file
- @return: True if successful, False otherwise
- """
- written = False
- try:
- fp = open(fpath, 'wb')
- except: pass
- else:
- try:
- fp.write(data)
- written = True
- except:
- fp.Close()
- else:
- fp.close()
- return written
-
+logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
#*************************************************************************************************
#
#*************************************************************************************************
@@ -304,10 +251,8 @@
Message = Message
FcParams = FcParams
Uri = Uri
- Upload = Upload
+
-
-
def __init__(self,
connectionName=None,
debugVerbosity=None,
@@ -350,7 +295,7 @@
# clean left over DDA test tmp files
for initialRequest in self._ddaTests:
if initialRequest['FcTestDDA'].get('TmpFile', None) is not None:
- saveRemoveFile(initialRequest['FcTestDDA']['TmpFile'])
+ tools.saveRemoveFile(initialRequest['FcTestDDA']['TmpFile'])
self._ddaTests = []
self._requests = {}
@@ -738,8 +683,7 @@
ddaRequestMsg['WantReadDirectory'] = True
directory = os.path.dirname(initialRequest['Filename'])
ddaRequestMsg['Directory'] = directory
-
-
+
# add params required for testing
initialRequest['FcTestDDA'] = {
'Directory': directory,
@@ -824,16 +768,16 @@
fpathRead = msg.params.get('ReadFilename', None)
readContent = ''
if fpathRead is not None:
- readContent = saveReadFile(fpathRead)
+ readContent = tools.saveReadFile(fpathRead)
if readContent is None:
readContent = ''
# perform write test if necessary
fpathWrite = msg.params.get('WriteFilename', None)
if fpathWrite is not None:
- written = saveWriteFile(fpathWrite, msg['ContentToWrite'])
+ written = tools.saveWriteFile(fpathWrite, msg['ContentToWrite'])
if not written:
- saveRemoveFile(fpathWrite)
+ tools.saveRemoveFile(fpathWrite)
else:
initialRequest['FcTestDDA']['TmpFile'] = fpathWrite
@@ -861,7 +805,7 @@
# remove test and clean tmp data
self._ddaTests.remove(initialRequest)
if initialRequest['FcTestDDA']['TmpFile'] is not None:
- saveRemoveFile(initialRequest['FcTestDDA']['TmpFile'])
+ tools.saveRemoveFile(initialRequest['FcTestDDA']['TmpFile'])
wantWrite = initialRequest.params['FcTestDDA']['WantWrite']
# check if test was sucessful
@@ -881,9 +825,7 @@
# else: resend message
self.sendMessageEx(initialRequest)
return True
-
-
-
+
####################################################
##
## config related
@@ -896,8 +838,7 @@
elif msg.name == consts.Message.NodeData:
self.events.NodeData(msg)
return True
-
-
+
####################################################
##
## get / put related
@@ -1424,8 +1365,6 @@
If the value of a keyword is None, it is ignored.
@return: (str) identifier of the request
-
-
"""
uri = self.Uri(uri).uri
msg = self.Message(consts.Message.ClientGet, URI=uri)
@@ -1645,7 +1584,7 @@
def subscribeUSK(self, uri, dontPoll=True):
"""Asks the node to notify the client when an USK is updated
@param uri: uri of the USK to subscribe to
- @param dontPoll: if True, whatever ???
+ @param dontPoll: if True, does whatever ???
@return: (str) identifer of the request
@note: this request can not be removed or modified and the {consts.RequestStatus.Completed}
@@ -1681,7 +1620,7 @@
@param uri:
@param data: (str) for L{consts.RequestType.PutData} data to upload or None
@param persistentUserData: (str) persistent data to be assosiated to the request
- @param userdata: (any) any data to be associated to the request at runtime
+ @param userData: (any) any data to be associated to the request at runtime
@param items: for L{consts.RequestType.PutMultiple}, items to upload
@param msgParams: (dict) Fcp parameters to pass along with the message
@@ -1771,7 +1710,7 @@
self.sendMessageEx(msg)
return msg['Identifier']
-
+
def putRedirect(self,
name,
targetURI,
@@ -1786,9 +1725,9 @@
@param targetURI: (str) uri to redirect to
@param maxRetries: (int) maximum number of tretries or -1 to leave the decission up to the node
@param persistence: (L{consts.Persistence}) of the request
- @param priority: (L{consts.Priority}) priority of the request
+ @param priorityClass: (L{consts.Priority}) priority of the request
@param persistentUserData: (str) persistent data to be assosiated to the request
- @param userdata: (any) any data to be associated to the request at runtime
+ @param userData: (any) any data to be associated to the request at runtime
@return: (str) request identifier
"""
msg = self.Message(
@@ -1850,6 +1789,7 @@
Verbosity=consts.Verbosity.ReportProgress | consts.Verbosity.ReportCompression,
)
+
def chkPutDir(self,
directory,
allowUnreadableFiles=False,
@@ -1866,9 +1806,8 @@
):
"""
- @param TargetFilename: (str) filename to append to the CHK key or None (may not contain slashes)
+ @param targetFilename: (str) filename to append to the CHK key or None (may not contain slashes)
"""
-
return self.clientPut(
consts.RequestType.PutDir,
consts.KeyType.CHK,
@@ -1876,8 +1815,7 @@
data=None,
persistentUserData=persistentUserData,
userData=userData,
-
-
+
# fcp params
Filename=directory,
AllowUnreadableFiles=allowUnreadableFiles,
@@ -1911,7 +1849,7 @@
):
"""
- @param TargetFilename: (str) filename to append to the CHK key or None (may not contain slashes)
+ @param targetFilename: (str) filename to append to the CHK key or None (may not contain slashes)
"""
return self.clientPut(
@@ -1959,12 +1897,11 @@
@param items:
- @param TargetFilename: (str) filename to append to the CHK key or None (may not contain slashes)
+ @param targetFilename: (str) filename to append to the CHK key or None (may not contain slashes)
"""
-
return self.clientPut(
consts.RequestType.PutMultiple,
consts.KeyType.CHK,
@@ -1973,8 +1910,7 @@
persistentUserData=persistentUserData,
userData=userData,
items=items,
-
-
+
# fcp params
Filename=directory,
AllowUnreadableFiles=allowUnreadableFiles,
@@ -2097,7 +2033,7 @@
All attempts to modify other requests will fail
@note: a RequestModified event is triggered as soon as the request has actually been modified
@note: you can not change the priority of requests with Persistence=L{consts.Persistence.Connection}.
- All attempts to do so are ignored. Too bad, but doing so is simply not implemented in the client protocol.
+ All attempts to do so are ignored. Too bad, but doing so is not implemented in the client protocol.
"""
initialRequest = self._requests[requestIdentifier]
@@ -2169,8 +2105,8 @@
@note: you can use this method to resend get / put requests.All attempts to resend other requests
will fail
- @note: actually a new request is created and registered. Todo so, the request passed is copied and removed from
- the queue (if necessary). The new request will have FcInitTime reseet and FcUserData amd FcPersistentUserData
+ @note: actually a new request is created and registered. Todo so, the request passed is copied. If it is a persistent
+ request, it will be removed. The new request will have FcInitTime reset and FcUserData amd FcPersistentUserData
taken over from the old request
"""
requestType = request.get('FcRequestType', consts.RequestType.Null)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-24 11:52:31
|
Revision: 247
http://fclient.svn.sourceforge.net/fclient/?rev=247&view=rev
Author: jurner
Date: 2008-02-24 03:52:23 -0800 (Sun, 24 Feb 2008)
Log Message:
-----------
too much trouble, split requests up into client methods. Del module.
Removed Paths:
-------------
trunk/sandbox/fcp/fcp2_0_requests.py
Deleted: trunk/sandbox/fcp/fcp2_0_requests.py
===================================================================
--- trunk/sandbox/fcp/fcp2_0_requests.py 2008-02-24 11:50:43 UTC (rev 246)
+++ trunk/sandbox/fcp/fcp2_0_requests.py 2008-02-24 11:52:23 UTC (rev 247)
@@ -1,263 +0,0 @@
-"""fcp request objects"""
-
-import fcp2_0_consts as consts
-#******************************************************************************************************************
-#
-#******************************************************************************************************************
-#TODO: if only one item is added its name is ignored so far. How to handle self.targetName vs. item['Name']
-#TODO: Metadata.ContentType vs. ContentType is pretty inconsistent
-class Upload(object):
- """Wrapper class to manage a freenet uploads
-
- @ivar defaultItem: (int) for directories or multiple uploads the name of this item is used as
- default item when a page is displayed
- @ivar directoryAdded: (bool) True if the upload contains a directory, False otherwise
- @ivar items: (list) of dicts containing paramaters for each upload
- @ivar keyType: L{consts.KeyType} the type of key to upload
- @ivar params: (dict) request parameters
- @ivar privateKey: (str) private keey (required for SSK or USK uploads)
- @ivar targetName: (str) for CHKs the name to be appended to the CHK. For SSKs and USKs the
- (target-name/version) part of the key
- @ivar targetNames: (list) of names already in use (for multi-uploads)
-
- @note: you can upload one or more items of any kind (data, files, redirects), except from directories
- wich have to be the only item to upload
- @note: if you want to upload a single redirect keyType has to be set to L{consts.KeyType.KSK}
- """
-
- PrivateParamNames = ('Data', 'RequestType', 'Name')
-
-
- def __init__(self,
- keyType,
- dontCompress=None,
- earlyEncode=None,
- maxRetries=None,
- persistence=consts.Persistence.Connection,
- priorityClass=consts.Priority.Medium,
-
- privateKey=None,
- targetName=None,
- ):
- """
- @param keyType: (L{consts.KeyType}) the desired key type to upload
- @param dontCompress:
- @param earlyEncode:
- @param maxRetries:
- @param persistence:
- @param priorityClass:
-
- @param privateKey: (str) privateKey if keyType is SSK or USK
- @param targetName:
- """
- if keyType not in consts.KeyType.TypesAll:
- raise ValueError('Invalid key type: %r' % keyType)
- if keyType in (consts.KeyType.SSK, consts.KeyType.USK) :
- if privateKey is None:
- raise ValueError('For %s a public key is required' % keyType)
- if not targetName:
- raise ValueError('For %s a target name is required' % keyType)
- elif keyType in (consts.KeyType.CHK, consts.KeyType.KSK) and privateKey is not None:
- raise ValueError('For %s no public key is required' % keyType)
-
- self.defaultItem = 0
- self.directoryAdded = False
- self.items = []
- self.keyType = keyType
- self.params = {
- 'DontCompress': dontCompress,
- 'EarlyEncode': earlyEncode,
- 'MaxRetries': maxRetries,
- 'Persistence': persistence,
- 'PriorityClass': priorityClass,
- }
- self.privateKey = privateKey
- self.targetName = targetName
- self.targetNames = [] # record to check if names are unique (assert order is arbitrary)
-
-
- def _addItem(self, isDefault=False, **params):
- """Private method to add an upload item"""
- if self.directoryAdded:
- raise ValueError('A directory has already been added, no other items allowed')
-
- if params['RequestType'] == consts.RequestType.PutDir:
- if self.directoryAdded:
- raise ValueError('An item has already been added, no additional directory allowed')
- else:
- self.directoryAdded = True
-
- name = params['Name']
- if name in self.targetNames:
- raise ValueError('Target name already exists: %r' % name)
-
- self.targetNames.append(name)
- self.items.append(params)
-
- if isDefault:
- self.defaultItem =len(self.items) -1
-
-
- def addData(self, name, data, contentType=None, isDefault=False):
- """Adds data to be uploaded
- @param name: target name
- @param data: (str) data to upload
- @param contentType: (str) content type of the data (if desired)
- @param isDefault: (bool) if True, the item is the default item
- """
- return self._addItem(
- isDefault=isDefault,
-
- RequestType=consts.RequestType.PutData,
- Data=data,
- ContentType=contentType,
- DataLength=len(data),
- Name=name,
- UploadFrom=consts.UploadFrom.Direct
- )
-
-
- def addDirectory(self, name, directory, allowUnreadableFiles=False, defaultName=None):
- """Adds a directory to be uploaded
- @param name: target name
- @param directory: (abspath) of the directory to be uploaded
- @param defaultName: (for SSKs and USKs, the file to display when the key is requested)
-
- @note: if you add a directory, every attempt to add anything else will fail
- """
- return self._addItem(
- RequestType=consts.RequestType.PutDir,
- AllowUnreadableFiles=allowUnreadableFiles,
- Filename=directory,
- Name=name,
- DefaultName=defaultName,
- )
-
-
- def addFile(self, name, filename, contentType=None, isDefault=False):
- """Adds a file to be uploaded
- @param name: target name
- @param filename: (abspath) of the file to be uploaded
- @param contentType: (str) content type of the file (if desired)
- @param isDefault: (bool) if True, the item is the default item
- """
- return self._addItem(
- isDefault=isDefault,
-
- RequestType=consts.RequestType.PutFile,
- ContentType=contentType,
- Filename=filename,
- Name=name,
- UploadFrom=consts.UploadFrom.Disk,
- )
-
-
- def addRedirect(self, name, redirect, isDefault=False):
- """Adds a redirect to be uploaded
- @param name: target name
- @param redirect: (freenet-key) to redirect to
- @param isDefault: (bool) if True, the item is the default item
- """
- return self._addItem(
- isDefault=isDefault,
-
- RequestType=consts.RequestType.PutRedirect,
- Name=name,
- TargetURI=redirect,
- UploadFrom=consts.UploadFrom.Redirect
- )
-
-
- def getMessage(self, messageClass):
- """Returns the message for the request, ready to send the request to the node
- @param messageClass: (L{fcp2_0_message.Message}) class to fill in
- @return: (tuple) (L{consts.RequestType}, L{fcp2_0_message.Message}) or (None, None)
- if ther is nothing to upload
- """
- n = len(self.items)
- if n == 0:
- return None, None
-
- elif n == 1:
- requestType = self.items[0]['RequestType']
-
- if requestType == consts.RequestType.PutDir:
- msg = messageClass(consts.Message.ClientPutDiskDir)
- params = self.items[0]
- for param, value in params.items():
- if value is None or param in self.PrivateParamNames:
- continue
- msg[param] = value
-
- item = self.items[self.defaultItem]
- msg['DefaultName'] = item['Name']
-
- else:
- msg = messageClass(consts.Message.ClientPut)
- item = self.items[0]
- for param, value in item.items():
- if value is None or param in self.PrivateParamNames:
- continue
- if param == 'ContentType':
- param = 'Metadata.ContentType'
- msg[param] = value
-
- # handle some specilal cases
- if requestType == consts.RequestType.PutData:
- msg.data = item['Data']
- elif requestType == consts.RequestType.PutRedirect:
- if self.keyType != consts.KeyType.KSK:
- raise ValueError('For redirects keyType must be %s' % consts.KeyType.KSK)
-
- else:
- requestType = consts.RequestType.PutMultiple
- msg = messageClass(consts.Message.ClientPutComplexDir)
- data = None
- for n, itemParams in enumerate(self.items):
- for param, value in itemParams.items():
- if param == 'Data':
- if data is None:
- data = ''
- data += value
- continue
-
- if param == 'Name':
- param = 'Files.%s.%s' % (n, param)
- msg[param] = value
- continue
-
- if value is None or param in self.PrivateParamNames:
- continue
-
- if param == 'ContentType':
- param = 'Metadata.ContentType'
- param = 'Files.%s.%s' % (n, param)
- msg[param] = value
-
- item = self.items[self.defaultItem]
- msg['DefaultName'] = item['Name']
- if data is not None:
- msg.data = data
-
- # determine Uri
- if self.keyType == consts.KeyType.CHK:
- msg['URI'] = consts.KeyType.CHK
- if self.targetName:
- msg['TargetFilename'] = self.targetName
- elif self.keyType == consts.KeyType.KSK:
- msg['URI'] = consts.KeyType.KSK + self.targetName
- elif self.keyType == consts.KeyType.SSK:
- msg['URI'] = self.privateKey + self.targetName
- elif self.keyType == consts.KeyType.USK:
- msg['URI'] = self.privateKey + self.targetName
-
- # set params and some defaults
- msg['Global'] = False
- msg['Verbosity'] = consts.Verbosity.ReportProgress | consts.Verbosity.ReportCompression
- for param, value in self.params.items():
- if value is None:
- continue
- msg[param] = value
-
- return requestType, msg
-
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-24 11:50:40
|
Revision: 246
http://fclient.svn.sourceforge.net/fclient/?rev=246&view=rev
Author: jurner
Date: 2008-02-24 03:50:43 -0800 (Sun, 24 Feb 2008)
Log Message:
-----------
del
Modified Paths:
--------------
trunk/sandbox/fcp/fcp2_0_requests.py
Modified: trunk/sandbox/fcp/fcp2_0_requests.py
===================================================================
--- trunk/sandbox/fcp/fcp2_0_requests.py 2008-02-24 11:50:25 UTC (rev 245)
+++ trunk/sandbox/fcp/fcp2_0_requests.py 2008-02-24 11:50:43 UTC (rev 246)
@@ -22,6 +22,7 @@
@note: you can upload one or more items of any kind (data, files, redirects), except from directories
wich have to be the only item to upload
+ @note: if you want to upload a single redirect keyType has to be set to L{consts.KeyType.KSK}
"""
PrivateParamNames = ('Data', 'RequestType', 'Name')
@@ -80,7 +81,7 @@
if self.directoryAdded:
raise ValueError('A directory has already been added, no other items allowed')
- if params['RequestType'] == self.RequestTypeDirectory:
+ if params['RequestType'] == consts.RequestType.PutDir:
if self.directoryAdded:
raise ValueError('An item has already been added, no additional directory allowed')
else:
@@ -116,7 +117,7 @@
)
- def addDirectory(name, directory, allowUnreadableFiles=False, defaultName=None):
+ def addDirectory(self, name, directory, allowUnreadableFiles=False, defaultName=None):
"""Adds a directory to be uploaded
@param name: target name
@param directory: (abspath) of the directory to be uploaded
@@ -143,14 +144,14 @@
return self._addItem(
isDefault=isDefault,
- RequestType=sconsts.RequestType.PutFile,
+ RequestType=consts.RequestType.PutFile,
ContentType=contentType,
Filename=filename,
Name=name,
UploadFrom=consts.UploadFrom.Disk,
)
- #TODO: isDefault for redirects???
+
def addRedirect(self, name, redirect, isDefault=False):
"""Adds a redirect to be uploaded
@param name: target name
@@ -161,8 +162,6 @@
isDefault=isDefault,
RequestType=consts.RequestType.PutRedirect,
- ContentType=contentType,
- DataLength=len(data),
Name=name,
TargetURI=redirect,
UploadFrom=consts.UploadFrom.Redirect
@@ -186,7 +185,7 @@
msg = messageClass(consts.Message.ClientPutDiskDir)
params = self.items[0]
for param, value in params.items():
- if value is None or param in PrivateParamNames:
+ if value is None or param in self.PrivateParamNames:
continue
msg[param] = value
@@ -195,18 +194,23 @@
else:
msg = messageClass(consts.Message.ClientPut)
- for param, value in params.items():
- if value is None or param in PrivateParamNames:
+ item = self.items[0]
+ for param, value in item.items():
+ if value is None or param in self.PrivateParamNames:
continue
if param == 'ContentType':
param = 'Metadata.ContentType'
msg[param] = value
- if params['RequestType'] == self.RequestTypeData:
- msg.data = params['Data']
+ # handle some specilal cases
+ if requestType == consts.RequestType.PutData:
+ msg.data = item['Data']
+ elif requestType == consts.RequestType.PutRedirect:
+ if self.keyType != consts.KeyType.KSK:
+ raise ValueError('For redirects keyType must be %s' % consts.KeyType.KSK)
else:
- requestType = consts.PutMultipole
+ requestType = consts.RequestType.PutMultiple
msg = messageClass(consts.Message.ClientPutComplexDir)
data = None
for n, itemParams in enumerate(self.items):
@@ -222,7 +226,7 @@
msg[param] = value
continue
- if value is None or param in PrivateParamNames:
+ if value is None or param in self.PrivateParamNames:
continue
if param == 'ContentType':
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-24 11:50:22
|
Revision: 245
http://fclient.svn.sourceforge.net/fclient/?rev=245&view=rev
Author: jurner
Date: 2008-02-24 03:50:25 -0800 (Sun, 24 Feb 2008)
Log Message:
-----------
added tests for putRedirect()
Modified Paths:
--------------
trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py
Modified: trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py
===================================================================
--- trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py 2008-02-24 11:48:04 UTC (rev 244)
+++ trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py 2008-02-24 11:50:25 UTC (rev 245)
@@ -548,7 +548,6 @@
self.assertHasNextEvent(None)
self.failUnless(myIdentifier in requestsAll)
- myRequest = self.fcpClient.getRequest(myIdentifier)
self.assertEqual(myIdentifier, myRequest['Identifier'])
self.assertEqual(myRequest['FcRequestStatus'], consts.RequestStatus.Null)
@@ -955,7 +954,79 @@
#***********************************************************************************
#
#***********************************************************************************
-#TODO: class TestClientPut(BaseTestConnectedClient):
+#TODO:
+#
+#
+#
+class TestClientPut(BaseTestClient):
+
+
+ def testPutRedirect_Success(self):
+ # request a arbitrary file
+ myIdentifier = self.fcpClient.putRedirect(
+ 'my-redirect-name',
+ 'SSK@arbitrary-uri',
+ )
+ myRequest = self.fcpClient.getRequest(myIdentifier)
+ requestsAll = self.fcpClient.getRequests()
+
+ self.assertHasNextMessage(consts.Message.ClientPut)
+ self.failUnless(myIdentifier in requestsAll)
+
+ self.sendResponseMessage(
+ 'PutSuccessful',
+ Identifier=myIdentifier,
+ URI='KSK@my-redirect-name'
+ )
+
+ self.assertHasNextEvent(
+ self.fcpClient.events.RequestCompleted,
+ consts.Message.ClientPut,
+ ('FcRequestStatus', consts.RequestStatus.Success |
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
+ ),
+ )
+
+ self.assertHasNextEvent(None)
+ self.assertHasNextMessage(None)
+ self.failIf(requestsAll)
+
+
+ def testPutRedirect_Failure(self):
+ # request a arbitrary file
+ myIdentifier = self.fcpClient.putRedirect(
+ 'my-redirect-name',
+ 'SSK@arbitrary-uri',
+ )
+ myRequest = self.fcpClient.getRequest(myIdentifier)
+ requestsAll = self.fcpClient.getRequests()
+
+ self.assertHasNextMessage(consts.Message.ClientPut)
+ self.failUnless(myIdentifier in requestsAll)
+
+ self.sendResponseMessage(
+ 'PutFailed',
+ Identifier=myIdentifier,
+ Code='5', # rout not found
+ )
+
+ self.assertHasNextEvent(
+ self.fcpClient.events.RequestFailed,
+ consts.Message.ClientPut,
+ ('FcRequestStatus', consts.RequestStatus.Error |
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
+ ),
+ )
+
+ self.assertHasNextEvent(None)
+ self.assertHasNextMessage(None)
+ self.failIf(requestsAll)
+
+
+
+
#***********************************************************************************
#
@@ -1856,6 +1927,7 @@
TestConnect,
TestDisconnectReason,
TestClientGet,
+ TestClientPut,
TestRequests,
TestRestoreRequests,
TestDDA,
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-24 11:48:13
|
Revision: 244
http://fclient.svn.sourceforge.net/fclient/?rev=244&view=rev
Author: jurner
Date: 2008-02-24 03:48:04 -0800 (Sun, 24 Feb 2008)
Log Message:
-----------
continued working on uploads
Modified Paths:
--------------
trunk/sandbox/fcp/fcp2_0_client.py
Modified: trunk/sandbox/fcp/fcp2_0_client.py
===================================================================
--- trunk/sandbox/fcp/fcp2_0_client.py 2008-02-23 08:18:18 UTC (rev 243)
+++ trunk/sandbox/fcp/fcp2_0_client.py 2008-02-24 11:48:04 UTC (rev 244)
@@ -1661,67 +1661,12 @@
self.sendMessageEx(msg)
return msg['Identifier']
-
- def putRedirect(self,
- name,
- targetURI,
-
- maxRetries=None,
- persistence=consts.Persistence.Connection,
- priorityClass=consts.Priority.Medium,
-
- userData=None,
- persistentUserData='',
- ):
- """Uploads a redirect
- @param name: name of the redirect
- @param targetURI: (str) uri to redirect to
- @return: (str) request identifier
- """
- msg = self.Message(
- consts.Message.ClientPut,
- URI=consts.KeyType.KSK + name,
- Persistence=persistence,
- PriorityClass=priorityClass,
- TargetURI=targetURI,
- UploadFrom=consts.UploadFrom.Redirect,
- )
- self._registerRequest(
- msg,
- consts.RequestType.PutRedirect,
- persistentUserData=persistentUserData,
- userData=userData,
- )
- self.sendMessageEx(msg)
- return msg['Identifier']
-
########################################################
##
## CHK ClientPut related methods
##
########################################################
- def putUpload(self, upload, userData=None, persistentUserData=''):
-
- requestType, msg = upload.getMessage(self.Message)
- if requestType is None:
- raise ValueError('Nothing to upload')
-
- self._registerRequest(
- msg,
- requestType,
- persistentUserData=persistentUserData,
- userData=userData,
- )
-
- if upload.keyType in (consts.KeyType.SSK, consts.KeyType.USK):
- msg['FcPrivateKey'] = upload.privateKey
- #NOTE: the caller may use the 'FcPrivateKey' member to store the private key
-
-
- self.sendMessageEx(msg)
- return msg['Identifier']
-
def clientPut(self,
requestType,
uri,
@@ -1729,29 +1674,94 @@
persistentUserData='',
userData=None,
items=None,
- **messageParams
+ **msgParams
):
+ """Uploads to the node
+ @param requestType: (L{consts.RequestType}). Can be PutData, PutDir or PutMultiple
+ @param uri:
+ @param data: (str) for L{consts.RequestType.PutData} data to upload or None
+ @param persistentUserData: (str) persistent data to be assosiated to the request
+ @param userdata: (any) any data to be associated to the request at runtime
+ @param items: for L{consts.RequestType.PutMultiple}, items to upload
+ @param msgParams: (dict) Fcp parameters to pass along with the message
+ @note: the Fcp message parameter 'Metadata.ContentType' may be passed as 'ContentType'
+ to this method
+ @note: to upload multiple items at once (see: PutComplexDir) pass a dict for each item
+ containig the following members:
+
+ - FcRequestType: L{consts.RequestType.PutData}, L{consts.RequestType.PutFile} or L{consts.RequestType.PutRedirect}
+ - Data: if requestType is L{consts.RequestType.PutData}, data to upload
+ - Filename: if requestType is L{consts.RequestType.PutFile}, filepath of the file to upload
+ - TargetURI: if requestType is L{consts.RequestType.PutRedirect}, uri to redirect to
+ - Name: name under wich the item will be accesible via freenet
+ - Metadata.ContentType: (optional) may be passed as 'ContentType'
+
+ All items will be accessible under one single key as 'Uri/Name'. The default item (the item when
+ only 'Uri' is requested from freenet) is always the first item in the list.
+ """
if requestType in (consts.RequestType.PutData, consts.RequestType.PutFile):
msgName = consts.Message.ClientPut
elif requestType == consts.RequestType.PutDir:
msgName = consts.Message.ClientPutDiskDir
+ elif requestType == consts.RequestType.PutMultiple:
+ msgName = consts.Message.ClientPutComplexDir
else:
- msgName = consts.Message.ClientPutComplexDir
-
+ raise ValueError('Unsupported request type')
+
msg = self.Message(msgName, URI=uri)
- for paramName, value in messageParams.items():
+ contentType = msgParams.get('ContentType', None)
+ if contentType is not None:
+ del msgParams['ContentType']
+ msgParams['Metadata.ContentType'] = contentType
+ for param, value in msgParams.items():
if value is not None:
- if paramName == 'ContentType':
- param = 'Metadata.ContentType'
- msg[paramName] = value
+ msg[param] = value
+
if data is not None:
+ if requestType != consts.RequestType.PutData:
+ raise ValueError('Data can only be passed along with PutData uploads')
msg.data = data
- if items:
- pass
-
-
+ if items is not None:
+ mapping = {
+ consts.RequestType.PutData: consts.UploadFrom.Direct,
+ consts.RequestType.PutFile: consts.UploadFrom.Disk,
+ consts.RequestType.PutRedirect: consts.UploadFrom.Redirect,
+ }
+
+ if requestType != consts.RequestType.PutMultiple:
+ raise ValueError('Items can only be passed along with PutMultiple uploads')
+
+ data = ''
+ for n, item in enumerate(items):
+ requestType = item.get('FcRequestType', None)
+ if requestType is None:
+ raise ValueError('No request type specified for item: %s' % n)
+ uploadFrom = mapping.get(requestType, None)
+ if uploadFrom is None:
+ raise valueError('Unsupported request type for item %s: %s' % (n, requestType))
+
+ contentType = item.get('ContentType', None)
+ if conetntType is not None:
+ del msgParams['ContentType']
+ item['Metadata.ContentType'] = contentType
+
+ msg.params['Files.%s.UploadFrom' % n] = uploadFrom
+ for param, value in item.items():
+ if param.startswith('Fc'):
+ continue
+ elif param == 'Data':
+ data += data
+ msg.params['Files.%s.DataLength' % n] = len(data)
+ continue
+ msg.params['Files.%s.%s' % (n, param)] = value
+
+ msg['DefaultName'] = items[0].get('Name', '')
+ if data:
+ msg.data = data
+
+ #
self._registerRequest(
msg,
requestType,
@@ -1762,6 +1772,42 @@
return msg['Identifier']
+ def putRedirect(self,
+ name,
+ targetURI,
+ maxRetries=None,
+ persistence=consts.Persistence.Connection,
+ priorityClass=consts.Priority.Medium,
+ userData=None,
+ persistentUserData='',
+ ):
+ """Uploads a redirect to another key
+ @param name: name of the redirect
+ @param targetURI: (str) uri to redirect to
+ @param maxRetries: (int) maximum number of tretries or -1 to leave the decission up to the node
+ @param persistence: (L{consts.Persistence}) of the request
+ @param priority: (L{consts.Priority}) priority of the request
+ @param persistentUserData: (str) persistent data to be assosiated to the request
+ @param userdata: (any) any data to be associated to the request at runtime
+ @return: (str) request identifier
+ """
+ msg = self.Message(
+ consts.Message.ClientPut,
+ URI=consts.KeyType.KSK + name,
+ Persistence=persistence,
+ PriorityClass=priorityClass,
+ TargetURI=targetURI,
+ UploadFrom=consts.UploadFrom.Redirect,
+ )
+ self._registerRequest(
+ msg,
+ consts.RequestType.PutRedirect,
+ persistentUserData=persistentUserData,
+ userData=userData,
+ )
+ self.sendMessageEx(msg)
+ return msg['Identifier']
+
#CHK
def chkPutData(self,
data,
@@ -1970,8 +2016,8 @@
##
########################################################
def uskPutData(self,
+ insertURI,
data,
- insertURI,
contentType=None,
dontCompress=None,
@@ -1982,9 +2028,12 @@
userData=None,
persistentUserData=''
-
-
):
+ """Uploads data
+
+ """
+
+
return self.clientPut(
consts.RequestType.PutData,
insertURI,
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-23 08:18:14
|
Revision: 243
http://fclient.svn.sourceforge.net/fclient/?rev=243&view=rev
Author: jurner
Date: 2008-02-23 00:18:18 -0800 (Sat, 23 Feb 2008)
Log Message:
-----------
adapt to removed Fcp bugfix
Modified Paths:
--------------
trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py
Modified: trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py
===================================================================
--- trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py 2008-02-23 08:17:33 UTC (rev 242)
+++ trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py 2008-02-23 08:18:18 UTC (rev 243)
@@ -808,7 +808,6 @@
# blah.. more here
)
- print consts.RequestStatus.humanReadable(myRequest['FcRequestStatus'])
self.assertHasNextEvent(
self.fcpClient.events.RequestFailed,
consts.Message.ClientGet,
@@ -1135,7 +1134,7 @@
# status of our request should be set to removed emidiately, but it should
# not be removed from the client
- self.assertEqual(myRequest['FcRequestStatus'], consts.RequestStatus.Removed)
+ self.assertEqual(myRequest['FcRequestStatus'], consts.RequestStatus.Removed | consts.RequestStatus.Completed)
self.failUnless(myIdentifier in self.fcpClient.getRequests())
# client schould send a RemovePersistentRequest
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-23 08:17:28
|
Revision: 242
http://fclient.svn.sourceforge.net/fclient/?rev=242&view=rev
Author: jurner
Date: 2008-02-23 00:17:33 -0800 (Sat, 23 Feb 2008)
Log Message:
-----------
removed Fcp bugfix ++ Completd flag is now set in finalizeRequest()
Modified Paths:
--------------
trunk/sandbox/fcp/fcp2_0_client.py
Modified: trunk/sandbox/fcp/fcp2_0_client.py
===================================================================
--- trunk/sandbox/fcp/fcp2_0_client.py 2008-02-21 13:14:57 UTC (rev 241)
+++ trunk/sandbox/fcp/fcp2_0_client.py 2008-02-23 08:17:33 UTC (rev 242)
@@ -167,7 +167,20 @@
# requests the node does not know about.
#
#------------------------------------------------------------------------------------------------------------------------------------------------
+# request status
+#
+# x. have to set a dedicated flag when a request is about to be modified or removed
+# Fcp gets confused if we disconnect emidiately after sending a modify or remove request
+# Curretnly the RequestStatus.Completed flag is removed and later set again to get some
+# control over the process.
+#
+# TODO: check if this is a bug in Fcp
+# NOTE: seems to be fixed in [build 1112], fixes removed
+#-------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
import atexit
import copy
import cPickle
@@ -371,7 +384,8 @@
removeRequest = request.params.get('Persistence', consts.Persistence.Connection) == consts.Persistence.Connection
if removeRequest:
request['FcRequestStatus'] |= consts.RequestStatus.RemovedFromQueue
-
+
+ request['FcRequestStatus'] |= consts.RequestStatus.Completed
if event is not None:
event(request)
@@ -761,37 +775,25 @@
# handle plugin related request failures
- elif code == consts.ProtocolError.NoSuchPlugin:
+ elif code == consts.ProtocolError.NoSuchPlugin or code == consts.ProtocolError.AccessDenied:
if initialRequest.name == consts.Message.GetPluginInfo:
initialRequest['FcErrorMessage'] = msg
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error | consts.RequestStatus.Completed
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
self._finalizeRequest(msg, initialRequest, self.events.PluginInfoFailed)
return True
+
+ # TODO: just a guess that FCPPluginMessage can trigger an AccessDenied error
elif initialRequest.name == consts.Message.FCPPluginMessage:
initialRequest['FcErrorMessage'] = msg
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error | consts.RequestStatus.Completed
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
self._finalizeRequest(msg, initialRequest, self.events.PluginMessageFailed)
return True
- elif code == consts.ProtocolError.AccessDenied:
- if initialRequest.name == consts.Message.PluginInfo:
- self.events.PluginInfoFailed(initialRequest)
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Completed
- del self._requests[requestIdentifier]
- return True
- # TODO: just a guess that FCPPluginMessage can trigger an AccessDenied error
- elif initialRequest.name == consts.Message.FCPPluginMessage:
- self.events.PluginMessageFailed(initialRequest)
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Completed
- del self._requests[requestIdentifier]
- return True
-
-
# only requests should get through to here
# NOTE: Fcp already removed the request
initialRequest['FcErrorMessage'] = msg
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error | consts.RequestStatus.Completed
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
self._finalizeRequest(msg, initialRequest, self.events.RequestFailed)
return True
@@ -871,7 +873,7 @@
if testFailed:
#TODO: check if errorMsg gives reasonable feedback
- initialRequest['FcRequestStatus'] = consts.RequestStatus.Error | consts.RequestStatus.Completed
+ initialRequest['FcRequestStatus'] = consts.RequestStatus.Error
initialRequest['FcErrorMessage'] = initialRequest['FcTestDDA']['ErrorMsg']
self._finalizeRequest(msg, initialRequest, self.events.RequestFailed)
return True
@@ -905,7 +907,7 @@
if initialRequest is None:
return False
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success | consts.RequestStatus.Completed
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
initialRequest.data = msg.data
self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted)
return True
@@ -932,7 +934,6 @@
OnlyData=True
)
else:
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Completed
self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted)
return True
@@ -950,11 +951,11 @@
if code == consts.FetchError.TooBig and initialRequest['FcRequestType'] == consts.RequestType.GetKeyInfo:
initialRequest['FcMetadataContentType'] = msg.get('ExpectedMetadata.ContentType', '')
initialRequest['FcDataLength'] = msg.get('ExpectedDataLength', -1)
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success | consts.RequestStatus.Completed
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted)
else:
initialRequest['FcErrorMessage'] = msg
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error | consts.RequestStatus.Completed
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
self._finalizeRequest(msg, initialRequest, self.events.RequestFailed)
return True
@@ -1034,7 +1035,7 @@
if initialRequest is None:
return False
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Removed | consts.RequestStatus.Completed
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Removed
self._finalizeRequest(msg, initialRequest, self.events.RequestRemoved)
return True
@@ -1106,7 +1107,7 @@
if code == consts.InsertError.Canceled:
return False
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error | consts.RequestStatus.Completed
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Error
initialRequest['FcErrorMessage'] = msg
self._finalizeRequest(msg, initialRequest, self.events.RequestFailed)
return True
@@ -1127,7 +1128,7 @@
# TODO: StartupTime and CompletionTime are passed, but
# as long as no corrosponding params are passed in DataFound
# we ignore them
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success | consts.RequestStatus.Completed
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
initialRequest['URI'] = msg['URI']
self._finalizeRequest(msg, initialRequest, self.events.RequestCompleted)
return True
@@ -1194,14 +1195,14 @@
if initialRequest is None:
return False
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success | consts.RequestStatus.Completed
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
self._finalizeRequest(msg, initialRequest, self.events.PluginInfo)
return True
elif msg.name == consts.Message.FCPPluginReply:
if initialRequest is None:
return False
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success | consts.RequestStatus.Completed
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
initialRequest['FcPluginReply'] = msg
self._finalizeRequest(msg, initialRequest, self.events.PluginMessage)
return True
@@ -1235,7 +1236,7 @@
initialRequest['FcPrivateKey'] = insertURI
initialRequest['FcPublicKey'] = requestURI
- initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success | consts.RequestStatus.Completed
+ initialRequest['FcRequestStatus'] |= consts.RequestStatus.Success
self._finalizeRequest(msg, initialRequest, self.events.KeypairGenerated)
return True
@@ -2072,8 +2073,6 @@
self.events.RequestModified(initialRequest)
return
-
- initialRequest['FcRequestStatus'] &= ~consts.RequestStatus.Completed
msg = self.Message(
consts.Message.ModifyPersistentRequest,
Identifier=initialRequest['Identifier'],
@@ -2102,7 +2101,6 @@
msg = self.Message(consts.Message.PersistentRequestRemoved, Identifier=requestIdentifier, Global=False)
self._finalizeRequest(msg, initialRequest, self.events.RequestRemoved)
else:
- initialRequest['FcRequestStatus'] &= ~consts.RequestStatus.Completed
self.sendMessage(
consts.Message.RemovePersistentRequest,
Global=False,
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-21 13:15:24
|
Revision: 241
http://fclient.svn.sourceforge.net/fclient/?rev=241&view=rev
Author: jurner
Date: 2008-02-21 05:14:57 -0800 (Thu, 21 Feb 2008)
Log Message:
-----------
minor change
Modified Paths:
--------------
trunk/sandbox/fcp/__init__.py
Modified: trunk/sandbox/fcp/__init__.py
===================================================================
--- trunk/sandbox/fcp/__init__.py 2008-02-21 13:13:53 UTC (rev 240)
+++ trunk/sandbox/fcp/__init__.py 2008-02-21 13:14:57 UTC (rev 241)
@@ -1,6 +1,6 @@
"""Python wrapper for the freenet client protocol
-See: [http://www.freenetproject.org]
+See: [http://www.freenetproject.org] and [http://wiki.freenetproject.org/FreenetFCPSpec2Point0]
"""
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-21 13:14:20
|
Revision: 240
http://fclient.svn.sourceforge.net/fclient/?rev=240&view=rev
Author: jurner
Date: 2008-02-21 05:13:53 -0800 (Thu, 21 Feb 2008)
Log Message:
-----------
fix: messages containing data always use terminating 'Data'. Hmm ..Fcp seems to accept both...
Modified Paths:
--------------
trunk/sandbox/fcp/fcp2_0_message.py
Modified: trunk/sandbox/fcp/fcp2_0_message.py
===================================================================
--- trunk/sandbox/fcp/fcp2_0_message.py 2008-02-21 13:12:03 UTC (rev 239)
+++ trunk/sandbox/fcp/fcp2_0_message.py 2008-02-21 13:13:53 UTC (rev 240)
@@ -29,9 +29,7 @@
@ivar name: message name
@ivar params: message params
"""
-
-
-
+
# we add a few private params...
ParamPrefixPrivate = 'Fc' # params prefixed with this are skipped when generating the message
@@ -67,7 +65,7 @@
error = clss(consts.Message.ClientSocketDied, Exception=socket.error, Details=d)
return error, p
-
+
@classmethod
def fromSocket(clss, socketObj):
"""Reads a message from a socket
@@ -102,6 +100,13 @@
line = ''.join(buf)
buf = []
+
+
+ #NOTE: messages carying data may end with 'EndMessage' or 'Data'.
+ # This is a bit messed up in Fcp. We assume here all messages from the
+ # node end with Data if data is passed. Alternative would be to check for both
+ # and rely on the 'DataLength' member to indicate if data is included. This
+ # should work for all messages except 'DataFound'
if line == 'EndMessage':
break
@@ -172,8 +177,11 @@
out.append('>> %s=%s' % (param, value))
- #TODO: append data?
- out.append('>>EndMessage')
+ if self.data is None:
+ out.append('>>EndMessage')
+ else:
+ out.append('>>Data')
+ out.append(self.data)
return '\n'.join(out)
@@ -201,8 +209,14 @@
out.append('%s=%s' % (param, value))
- out.append('EndMessage')
- out.append('' if self.data is None else self.data)
+ if self.data is None:
+ out.append('EndMessage\n')
+ else:
+ out.append('Data')
+ out.append(self.data)
return '\n'.join(out)
+
+
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-21 13:12:55
|
Revision: 239
http://fclient.svn.sourceforge.net/fclient/?rev=239&view=rev
Author: jurner
Date: 2008-02-21 05:12:03 -0800 (Thu, 21 Feb 2008)
Log Message:
-----------
fix: messages containing data always use terminating 'Data'. Hmm ..Fcp seems to accept both...
Modified Paths:
--------------
trunk/sandbox/fcp/test_fcp/test_fcp2_0_message.py
Modified: trunk/sandbox/fcp/test_fcp/test_fcp2_0_message.py
===================================================================
--- trunk/sandbox/fcp/test_fcp/test_fcp2_0_message.py 2008-02-21 13:11:07 UTC (rev 238)
+++ trunk/sandbox/fcp/test_fcp/test_fcp2_0_message.py 2008-02-21 13:12:03 UTC (rev 239)
@@ -103,7 +103,7 @@
data='ABCDE'
)
msg.send(s)
- self.failUnless(s.bytes == 'AllData\nDataLength=5\nEndMessage\nABCDE')
+ self.failUnless(s.bytes == 'AllData\nDataLength=5\nData\nABCDE')
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ju...@us...> - 2008-02-21 13:11:20
|
Revision: 238
http://fclient.svn.sourceforge.net/fclient/?rev=238&view=rev
Author: jurner
Date: 2008-02-21 05:11:07 -0800 (Thu, 21 Feb 2008)
Log Message:
-----------
RequestStatus.Completed flag is now set before listeners are informed
Modified Paths:
--------------
trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py
Modified: trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py
===================================================================
--- trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py 2008-02-21 13:10:08 UTC (rev 237)
+++ trunk/sandbox/fcp/test_fcp/test_fcp2_0_client.py 2008-02-21 13:11:07 UTC (rev 238)
@@ -621,7 +621,8 @@
self.fcpClient.events.RequestCompleted,
consts.Message.ClientGet,
('FcRequestStatus', consts.RequestStatus.Success |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
data=data
)
@@ -648,7 +649,7 @@
self.assertHasNextEvent(
self.fcpClient.events.RequestCompleted,
consts.Message.ClientGet,
- ('FcRequestStatus', consts.RequestStatus.Success),
+ ('FcRequestStatus', consts.RequestStatus.Success | consts.RequestStatus.Completed),
data=data
)
self.failUnless(myIdentifier in requestsAll)
@@ -693,10 +694,10 @@
self.fcpClient.events.RequestFailed,
consts.Message.ClientGet,
('FcRequestStatus', consts.RequestStatus.Error |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
- self.failUnless(myRequest['FcRequestStatus'] & consts.RequestStatus.Completed)
self.assertHasNextEvent(None)
self.assertHasNextMessage(None)
@@ -722,10 +723,9 @@
self.assertHasNextEvent(
self.fcpClient.events.RequestFailed,
consts.Message.ClientGet,
- ('FcRequestStatus', consts.RequestStatus.Error),
+ ('FcRequestStatus', consts.RequestStatus.Error | consts.RequestStatus.Completed),
)
self.failUnless(myIdentifier in requestsAll)
- self.failUnless(myRequest['FcRequestStatus'] & consts.RequestStatus.Completed)
self.assertHasNextEvent(None)
self.assertHasNextMessage(None)
@@ -768,7 +768,8 @@
self.fcpClient.events.RequestCompleted,
consts.Message.ClientGet,
('FcRequestStatus', consts.RequestStatus.Success |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
self.failIf(myIdentifier in requestsAll)
@@ -806,15 +807,17 @@
Global='false',
# blah.. more here
)
+
+ print consts.RequestStatus.humanReadable(myRequest['FcRequestStatus'])
self.assertHasNextEvent(
self.fcpClient.events.RequestFailed,
consts.Message.ClientGet,
('FcRequestStatus', consts.RequestStatus.Error |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
self.failIf(myIdentifier in requestsAll)
- self.failUnless(myRequest['FcRequestStatus'] & consts.RequestStatus.Completed)
self.assertHasNextEvent(None)
self.assertHasNextMessage(None)
@@ -855,7 +858,8 @@
self.fcpClient.events.RequestCompleted,
consts.Message.ClientGet,
('FcRequestStatus', consts.RequestStatus.Success |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
self.failIf(myIdentifier in requestsAll)
@@ -897,7 +901,8 @@
self.fcpClient.events.RequestCompleted,
consts.Message.ClientGet,
('FcRequestStatus', consts.RequestStatus.Success |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
self.failUnless(myRequest['FcRequestStatus'] & consts.RequestStatus.Completed)
@@ -938,7 +943,8 @@
self.fcpClient.events.RequestFailed,
consts.Message.ClientGet,
('FcRequestStatus', consts.RequestStatus.Error |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
self.failUnless(myRequest['FcRequestStatus'] & consts.RequestStatus.Completed)
@@ -1079,8 +1085,8 @@
# of our request should be removed emidiately,
self.assertEqual(myRequest['FcRequestStatus'], consts.RequestStatus.Removed |
- consts.RequestStatus.Completed |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
)
self.failIf(myIdentifier in self.fcpClient.getRequests())
@@ -1089,7 +1095,8 @@
self.fcpClient.events.RequestRemoved,
consts.Message.ClientGet,
('FcRequestStatus', consts.RequestStatus.Removed |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
self.failIf(self.fcpClient.getRequests())
@@ -1147,7 +1154,8 @@
self.fcpClient.events.RequestRemoved,
consts.Message.ClientGet,
('FcRequestStatus', consts.RequestStatus.Removed |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
@@ -1176,7 +1184,8 @@
self.fcpClient.events.RequestRemoved,
consts.Message.ClientGet,
('FcRequestStatus', consts.RequestStatus.Removed |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
@@ -1217,7 +1226,8 @@
self.fcpClient.events.RequestRemoved,
consts.Message.ClientGet,
('FcRequestStatus', consts.RequestStatus.Removed |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
@@ -1594,7 +1604,8 @@
('Identifier', myIdentifier),
('PluginName', 'hi there'),
('FcRequestStatus', consts.RequestStatus.Success |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
@@ -1632,7 +1643,8 @@
#('PluginName', 'hi there'),
('Identifier', myIdentifier),
('FcRequestStatus', consts.RequestStatus.Error |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
@@ -1672,7 +1684,8 @@
('PluginName', 'hi there'),
('Identifier', myIdentifier),
('FcRequestStatus', consts.RequestStatus.Success |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
reply = msg['FcPluginReply']
@@ -1712,7 +1725,8 @@
#('PluginName', 'hi there'),
('Identifier', myIdentifier),
('FcRequestStatus', consts.RequestStatus.Error |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
@@ -1752,7 +1766,8 @@
('FcPublicKey','SSK@public'),
('FcPrivateKey','SSK@private'),
('FcRequestStatus', consts.RequestStatus.Success |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
self.failIf(myIdentifier in requestsAll)
@@ -1783,7 +1798,8 @@
('FcPublicKey','USK@public'),
('FcPrivateKey','USK@private'),
('FcRequestStatus', consts.RequestStatus.Success |
- consts.RequestStatus.RemovedFromQueue
+ consts.RequestStatus.RemovedFromQueue |
+ consts.RequestStatus.Completed
),
)
self.failIf(myIdentifier in requestsAll)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|