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. |