fclient-commit Mailing List for fclient (Page 27)
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-03-06 11:58:59
|
Revision: 312 http://fclient.svn.sourceforge.net/fclient/?rev=312&view=rev Author: jurner Date: 2008-03-06 03:59:02 -0800 (Thu, 06 Mar 2008) Log Message: ----------- bit of this and that Modified Paths: -------------- trunk/sandbox/fcp2/consts.py Modified: trunk/sandbox/fcp2/consts.py =================================================================== --- trunk/sandbox/fcp2/consts.py 2008-03-06 11:58:32 UTC (rev 311) +++ trunk/sandbox/fcp2/consts.py 2008-03-06 11:59:02 UTC (rev 312) @@ -197,6 +197,7 @@ @cvar DuplicateClientName: another client opend a connection with the same connection name @cvar Shutdown: regular shutdown of the connection @cvar SocketDied: connection to the node died unexpectingly + @cvar SocketShutdown: the node shut down the connection unexpectingly @cvar VersionMissmatch: node or Fcp version did not match """ Close = 0x0 @@ -204,7 +205,9 @@ DuplicateClientName = 0x2 Shutdown = 0x4 SocketDied = 0x8 - VersionMissmatch = 0x10 + SocketShutdown = 0x10 + VersionMissmatch = 0x20 + UnknownNodeHello = 0x40 class FilenameCollision(BaseBitFlags): @@ -251,20 +254,29 @@ ClientRuntime = Client + '.Runtime' Config = Fcp + '.Config' + ClientIOHandler = Client + '.IOHandler' + + + + + class LogMessages: """Strings used for log infos""" - Connecting = 'connecting to node...' + Connecting = 'connecting' Connected = 'connected to node' - ConnectionRetry = 'connecting to node failed... retrying' ConnectingFailed = 'connecting to node failed' + Retry = 'Retrying' - ClientClose = 'closing client' + Closing = 'Closing' - MessageSend = 'send' - MessageReceived = 'received' + Sending = 'Sending' + Received = 'Received' + SocketDied = 'Socket died' + SocketShutdown = 'Socket shutdown by node' + KeyboardInterrupt = 'keyboard interrupt' # kick out SocketDied = 'socket died' AllRequestsCompleted = 'All requests completed' This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-03-06 11:58:27
|
Revision: 311 http://fclient.svn.sourceforge.net/fclient/?rev=311&view=rev Author: jurner Date: 2008-03-06 03:58:32 -0800 (Thu, 06 Mar 2008) Log Message: ----------- use iohandler now Modified Paths: -------------- trunk/sandbox/fcp2/client.py Modified: trunk/sandbox/fcp2/client.py =================================================================== --- trunk/sandbox/fcp2/client.py 2008-03-06 11:57:34 UTC (rev 310) +++ trunk/sandbox/fcp2/client.py 2008-03-06 11:58:32 UTC (rev 311) @@ -182,7 +182,6 @@ import atexit import copy import logging -import socket import subprocess import time @@ -199,8 +198,9 @@ from fcp2 import consts from fcp2 import config from fcp2 import events -from fcp2 import message from fcp2 import fcparams +from fcp2 import message +from fcp2 import iohandler from fcp2 import types from fcp2 import key @@ -225,8 +225,7 @@ @cvar MaxSizeKeyInfo: (bytes) maximum request size for key info requests @cvar inimumRunTime: (seconds) minimum runtime when the L{run} method is called. Required to make shure persistent requests can be taken up from the node. - @cvar SocketTimeout: (seconds) default socket timeout - + @ivar events: events the client supports @@ -242,8 +241,7 @@ DefaultFcpPort = int(os.environ.get('FCP_PORT', '9481')) MaxSizeKeyInfo = 32768 MinimumRunTime = 1 # FIX: 0001931 - SocketTimeout = 0.1 - + consts = consts config = config message = message @@ -271,7 +269,7 @@ } self._nodeHelloMessage = None self._requests = {} # currently running requests (requestIdentifier --> request) - self._socket = None + self.ioHandler = iohandler.IOHandler() for event in self.events: event += self._captureEvent @@ -294,7 +292,7 @@ @todo: complain if the client is already closed? """ - self._loggers['Runtime'].info(consts.LogMessages.ClientClose) + self._loggers['Runtime'].info(consts.LogMessages.Closing) # clean left over DDA test tmp files for initialRequest in self._ddaTests: @@ -304,14 +302,9 @@ self._ddaTests = [] self._requests = {} - if self._socket is None: - # complain or not? - pass - else: - self._socket.close() - self._socket = None - if msg is not None: - self.events.ClientDisconnected(msg) + self.ioHandler.close() + if msg is not None: + self.events.ClientDisconnected(msg) def _finalizeRequest(self, msg, request, event): @@ -488,43 +481,31 @@ @event: ClientConnected(event, message) is triggered as soon as the client is connected """ - self._loggers['Runtime'].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._loggers['Runtime'].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( + #TODO: we have to yield a few round here to make NodeHello injection work in unittests + # no idea exactly how many... + disconnectReason = None + disconnectParam = None + t0 = time.time() + for result in self.ioHandler.iterConnect(duration=duration, timeout=timeout, host=host, port=port): + yield None + timeElapsed = time.time() - t0 + + # try to get handshake + if result: + errorMsg = self.sendMessage( consts.Message.ClientHello, Name=self._connectionName, ExpectedVersion=self.ExpectedFcpVersion, ) + yield None + if errorMsg is None: + timeElapsed = 0 while timeElapsed <= duration: + yield None msg = self.next(dispatch=False) - if msg.name == consts.Message.ClientSocketTimeout: - timeElapsed += self.SocketTimeout + timeElapsed += max(self.ioHandler.io.Timeout, 0.1) yield None elif msg.name == consts.Message.NodeHello: @@ -532,35 +513,29 @@ # check if version is ok if self.versionCheckNodeHello(msg): self.events.ClientConnected(msg) + yield self._nodeHelloMessage + raise StopIteration else: - disconnectMsg = message.Message( - consts.Message.ClientDisconnected, - DisconnectReason=consts.DisconnectReason.VersionMissmatch, - Param=msg, - ) - self._close(disconnectMsg) - yield self._nodeHelloMessage - raise StopIteration + disconnectReason = consts.DisconnectReason.VersionMissmatch + disconnectParam = msg + break else: - self._loggers['Message'].debug(consts.LogMessages.MessageReceived + msg.pprint()) + disconnectReason = consts.DisconnectReason.UnkownNodeHello + disconnectParam = msg break - break - - # continue polling - self._loggers['Runtime'].info(consts.LogMessages.ConnectionRetry) - timeElapsed += timeout - time.sleep(timeout) - self._loggers['Runtime'].info(consts.LogMessages.ConnectingFailed) + + if disconnectReason is None: + disconnectReason=consts.DisconnectReason.ConnectingFailed disconnectMsg = message.Message( consts.Message.ClientDisconnected, - DisconnectReason=consts.DisconnectReason.ConnectingFailed, - Param=None, + DisconnectReason=disconnectReason, + Param=disconnectParam, ) self._close(disconnectMsg) - raise StopIteration - + raise StopIteration + def getConnectionName(self): """Returns the connection name used by the client @@ -584,6 +559,7 @@ """ for logger in self._loggers.values(): logger.setLevel(debugVerbosity) + self.ioHandler.setDebugVerbosity(debugVerbosity) def startFreenet(self, cmdline): @@ -624,7 +600,7 @@ @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 @@ -1197,28 +1173,26 @@ @note: use this method to run the client step by step. If you want to run the client unconditionally use L{run} """ - msg = message.Message.fromSocket(self._socket) - if msg.name == consts.Message.ClientSocketDied: - self._loggers['Runtime'].critical(consts.LogMessages.SocketDied) + try: + msg = self.ioHandler.readMessage() + except iohandler.IOTimeout, details: + msg = message.Message(consts.Message.ClientSocketTimeout) if dispatch: - disconnectMsg = message.Message( + self.events.Idle(msg) + except iohandler.IOBroken, details: + msg = message.Message( consts.Message.ClientDisconnected, DisconnectReason=consts.DisconnectReason.SocketDied, - Param=msg, + Param=details, ) - self._close(disconnectMsg) - #raise socket.error(msg['Param']['Details']) - - elif msg.name == consts.Message.ClientSocketTimeout: - if dispatch: - self.events.Idle(msg) + self._close(msg) + raise iohandler.IOBroken(details) else: - self._loggers['Message'].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 @@ -1268,10 +1242,8 @@ @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 """ @@ -1280,29 +1252,27 @@ 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. - + @param msg: (L{message.Message}) message to send + @return: (L{message.Message}) disconnect if something went wrong + + @note: If an error occurs the client is closed @note: you can use this method to send a message to the node, bypassing all track keeping methods of the client """ - self._loggers['Message'].debug(consts.LogMessages.MessageSend + msg.pprint()) + errorMsg = None try: - msg.send(self._socket) - except socket.error, d: - self._loggers['Runtime'].critical(consts.LogMessages.SocketDied) - disconnectMsg = message.Message( + self.ioHandler.sendMessageEx(msg) + except iohandler.IOBroken, details: + errorMsg = message.Message( consts.Message.ClientDisconnected, DisconnectReason=consts.DisconnectReason.SocketDied, - Param=message.Message(consts.Message.ClientSocketDied, Exception=socket.error, Details=d) + Param=details ) - self._close(disconnectMsg) - raise socket.error(d) - return msg + self._close(errorMsg) + raise iohandler.IOBroken(details) + return errorMsg + ######################################################### ## ## config related methods This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-03-06 11:57:29
|
Revision: 310 http://fclient.svn.sourceforge.net/fclient/?rev=310&view=rev Author: jurner Date: 2008-03-06 03:57:34 -0800 (Thu, 06 Mar 2008) Log Message: ----------- separated a module to handle message io Added Paths: ----------- trunk/sandbox/fcp2/iohandler.py Added: trunk/sandbox/fcp2/iohandler.py =================================================================== --- trunk/sandbox/fcp2/iohandler.py (rev 0) +++ trunk/sandbox/fcp2/iohandler.py 2008-03-06 11:57:34 UTC (rev 310) @@ -0,0 +1,385 @@ + + +import os, sys +import logging +import socket +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) + +from fcp2 import consts +from fcp2 import message +from fcp2 import types + +del hack +#<-- rel import hack + +logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) +logging.addLevelName(consts.DebugVerbosity.Quiet, '') +#***************************************************************************** +# +#***************************************************************************** +class MessageParseError(Exception): + """Exception raised when a message could not be parsed succesfuly""" + +class IOConnectFailed(Exception): + """Exception raised if the object can not be connected""" + +class IOClosed(Exception): + """Exception raised if the object is closed""" + +class IOBroken(Exception): + """Exception raised if the IO connection is broken""" + +class IOTimeout(Exception): + """Exception raised when the io connection is closed""" + + +class IOObject(object): + Timeout = 0 + BufferSize = 4096 + + def __init__(self, ): + pass + + def connect(self, **kwargs): + raise IOConnectFailed('Failed') + + def read(self, n): + raise IOBroken('Broken') + + def write(self, bytes): + raise IOBroken('Broken') + + def close(self): + raise IOClosed('Closed') + + def isOpen(self): + return False + + def setTimeout(self, n): + pass + + +#***************************************************************************** +# +#***************************************************************************** +class SocketIO(IOObject): + Timeout = 0.1 + BufferSize = 4096 + + def __init__(self): + self.socket = None + + def connect(self, **kwargs): + if self.isOpen(): + self.close() + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + self.socket.connect((kwargs['host'], kwargs['port'])) + except socket.error, details: + raise IOConnectFailed(details) + + def read(self, n): + try: + p = self.socket.recv(n) + if p == '': + raise socket.error('Socket closed by host') + except socket.timeout, details: + raise IOTimeout(details) + except socket.error, details: + self.close() + raise IOBroken(details) + else: + return p + + def write(self, bytes): + try: + self.socket.sendall(bytes) + except socket.error, details: + self.close() + raise IOBroken(details) + + def close(self): + if self.socket is None: + raise IOClosed('Closed') + self.socket.close() + self.socket = None + + def isOpen(self): + return self.socket is not None + + def setTimeout(self, n): + self.socket.settimeout(n) + +#***************************************************************************** +# +#***************************************************************************** +class IOHandler(object): + + TerminatorEndMessage = '\nEndMessage\n' + TerminatorData = '\nData\n' + + + def __init__(self, ioPrototype=SocketIO): + self._ioPrototype = ioPrototype + self._log = logging.getLogger(consts.LoggerNames.ClientIOHandler) + self._receiveBuffer = '' + + self.io = None + + def connect(self, duration=20, timeout=0.5, **kwargs): + for result in self.iterConnect(duration=duration, timeout=timeout, **kwargs): pass + return result + + + def iterConnect(self, duration=20, timeout=0.5, **kwargs): + + if not duration >= 0: + raise ValueError('duration must be >= 0') + if not timeout >= 0: + raise ValueError('timeout must be >= 0') + + if self.isOpen(): + self.close() + + timeElapsed = 0 + while timeElapsed <= duration: + + self._log.info(consts.LogMessages.Connecting + ' %r' % kwargs) + self.io = self._ioPrototype() + try: + self.io.connect(**kwargs) + except IOConnectFailed, details: + self._log.info(consts.LogMessages.ConnectingFailed + ' %s %s' % (IOConnectFailed, details)) + yield False + else: + self.io.setTimeout(self.io.Timeout) + self._log.info(consts.LogMessages.Connected) + yield True + break + + # continue polling + self._log.info(consts.LogMessages.Retry) + timeElapsed += timeout + time.sleep(timeout) + + raise StopIteration + + + def close(self): + self._log.debug(consts.LogMessages.Closing) + self._receiveBuffer = '' + if self.io is not None and self.io.isOpen(): + self.io.close() + self.io = None + + + def isOpen(self): + if self.io is not None: + return self.io.isOpen() + return False + + + def readBytes(self, n): + """Reads n bytes from socket + @param n: (int) number of bytes to read + @return: (tuple) (error-message, bytes-read). If no error was encountered, error-message will be None + """ + try: + #TODO: if \r\n is possible in Fcp, replace it by \n + p = self.io.read(n) + if not p: + raise ValueError('No bytes received and IO did not raise as expected?!?') + self._receiveBuffer += p + except IOBroken, details: + self.close() + self._log.critical(consts.LogMessages.SocketDied) + return IOBroken, details + except IOTimeout, details: # nothing in the queue + return IOTimeout, details + return None, None + + + def readMessage(self): + """Reads the next a message from io + @return: (Message) next message from the socket + + @note: if something goes wrong the according exception is raised + """ + # read message from io + # + #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' + hasData = False + eof = -1 + while eof < 0: + eof = self._receiveBuffer.find(self.TerminatorEndMessage) + if eof > -1: + eof += len(self.TerminatorEndMessage) + else: + eof = self._receiveBuffer.find(self.TerminatorData) + if eof > -1: + eof += len(self.TerminatorData) + hasData = True + if eof < 0: + exception, details = self.readBytes(self.io.BufferSize) + if exception is not None: + raise exception(details) + + # prep message + chunk, self._receiveBuffer = self._receiveBuffer[ :eof], self._receiveBuffer[eof: ] + p = [i for i in chunk.split('\n') if i] # Fcp ignores empty lines, so do we + p.pop() + if not p: + raise MessageParseError('Missing message name') + msgName = p.pop(0) + msg = message.Message(msgName) + paramTypes = types.MessageParamTypes.get(msgName, None) + + # process param --> value fields + # + #NOTE:usually if data is passed DataLength determines how much have to handle + # special case ClientPutComplexDir where it is passed in Files.(N).DataLength. + # Additionally Files.(N).DataLength is converted to int here. + clientPutComplexDirDataLength = 0 + isClientPutComplexDir = msgName == consts.Message.ClientPutComplexDir + for line in p: + paramName, sep, paramValue = line.partition('=') + + # covert fcp to python value if necessary + if paramTypes is not None: + paramType = paramTypes.get(paramName, None) + if paramType is not None: + paramValue = paramType.fcpToPython(paramValue) + msg[paramName] = paramValue + + # handle special case PutComplexDir + if isClientPutComplexDir: + tmp_paramName = paramName.split('.') + if len(tmp_paramName) == 3: + if tmp_paramName[-1] == 'DataLength': + n = types.FcpTypeInt.fcpToPython(paramValue) + clientPutComplexDirDataLength += n + msg[paramName] = n + + # get associated data if necessary + if hasData: + if isClientPutComplexDir: + n = clientPutComplexDirDataLength + else: + n = msg['DataLength'] + if n > 0: + while self._receiveBuffer: + if len(self._receiveBuffer) >= n: + msg.data, self._receiveBuffer = self._receiveBuffer[ :n], self._receiveBuffer[n: ] + break + + exception, details = self.readBytes(self.io.BufferSize) + if exception == IOTimeout: # try again later + self._receiveBuffer = chunk + self._receiveBuffer + elif exception is not None: + raise exception(details) + + self._log.debug(consts.LogMessages.Received + msg.pprint()) + return msg + + + + 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(message.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._log.debug(consts.LogMessages.Sending + msg.pprint()) + try: + self.io.write(msg.toString()) + except IOBroken, details: + self.close() + self._log.critical(consts.LogMessages.SocketDied) + raise IOBroken(details) + + + def setDebugVerbosity(self, debugVerbosity): + self._log.setLevel(debugVerbosity) + + + def setIOPrototype(self, ioObject): + """ + @note: if the connection is open the connection is closed in the call + """ + if self.isOpen(): + self.close() + + if ioObject.BufferSize <= 0: + raise ValueError('IOObject.BufferSize must be > 0') + self._ioPrototype = ioObject + + +#*********************************************************************************************** +# +#*********************************************************************************************** +if __name__ == '__main__': + + c = IOHandler() + def cb(event, *params): + print event + #print event == c.events.MessageReceived + #print event.msg + + + #for e in c.events: + # e += cb + + if c.connect(duration=1, host='127.0.0.1', port=9481): + + + c.sendMessageEx(message.Message(consts.Message.ClientHello, Name='foo', ExpectedVersion="2,0")) + msg = c.readMessage() + + + #print 222, c.nextMessage() + + c.close() + + + + + + + + + \ 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-03-04 17:39:46
|
Revision: 309 http://fclient.svn.sourceforge.net/fclient/?rev=309&view=rev Author: jurner Date: 2008-03-04 09:39:46 -0800 (Tue, 04 Mar 2008) Log Message: ----------- fix for new key module Modified Paths: -------------- trunk/sandbox/fcp2/test_fcp/test_client.py Modified: trunk/sandbox/fcp2/test_fcp/test_client.py =================================================================== --- trunk/sandbox/fcp2/test_fcp/test_client.py 2008-03-04 17:39:14 UTC (rev 308) +++ trunk/sandbox/fcp2/test_fcp/test_client.py 2008-03-04 17:39:46 UTC (rev 309) @@ -2069,7 +2069,7 @@ myKey = 'USK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA' msg = client.message.Message( consts.Message.ClientPut, - URI=myKey + '/foo', + URI=myKey + '/foo/0', Persistence=consts.Persistence.Connection, ) self.fcpClient._registerRequest(msg, consts.RequestType.PutData) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-03-04 17:39:07
|
Revision: 308 http://fclient.svn.sourceforge.net/fclient/?rev=308&view=rev Author: jurner Date: 2008-03-04 09:39:14 -0800 (Tue, 04 Mar 2008) Log Message: ----------- use new key module ++ many a things I can't remember now Modified Paths: -------------- trunk/sandbox/fcp2/client.py Modified: trunk/sandbox/fcp2/client.py =================================================================== --- trunk/sandbox/fcp2/client.py 2008-03-04 17:38:18 UTC (rev 307) +++ trunk/sandbox/fcp2/client.py 2008-03-04 17:39:14 UTC (rev 308) @@ -202,7 +202,7 @@ from fcp2 import message from fcp2 import fcparams from fcp2 import types -from fcp2 import uri +from fcp2 import key from fcp2.fcp_lib import namespace from fcp2.fcp_lib import tools @@ -249,7 +249,7 @@ message = message fcparams = fcparams types = types - Uri = uri + key = key def __init__(self, @@ -1167,8 +1167,8 @@ return False #TODO:no idea if the node may pass uris with prefixes like 'freenet:'... strip it anyways - insertURI = uri.Uri(msg['InsertURI']).uri - requestURI = uri.Uri(msg['RequestURI']).uri + insertURI = key.stripKey(msg['InsertURI']) + requestURI = key.stripKey(msg['RequestURI']) if initialRequest['FcRequestType'] == consts.RequestType.GenerateUSKKeypair: insertURI = insertURI.replace(consts.KeyType.SSK, consts.KeyType.USK, 1) @@ -1367,7 +1367,6 @@ @return: (str) identifier of the request """ - key = uri.Uri(key).uri msg = message.Message(consts.Message.ClientGet, URI=key) for paramName, value in messageParams.items(): if value is not None: @@ -1591,7 +1590,7 @@ """ msg = message.Message( consts.Message.SubscribeUSK, - URI=uri.Uri(key).uri, + URI=key, DontPoll=dontPoll, ) self._registerRequest(msg, consts.RequestType.SubscribeUSK) @@ -1646,6 +1645,7 @@ else: raise ValueError('Unsupported request type') + #TODO: autoconvert keys to python classes??? msg = message.Message(msgName, URI=key) contentType = msgParams.get('ContentType', None) if contentType is not None: @@ -1741,6 +1741,47 @@ return msg['Identifier'] + def putData(self, + key, + data, + + contentType=None, + dontCompress=None, + maxRetries=None, + persistence=consts.Persistence.Connection, + priorityClass=consts.Priority.Medium, + targetFilename=None, + + userData=None, + persistentUserData='', + + ): + return self.clientPut( + consts.RequestType.PutData, + key, + + data=data, + persistentUserData=persistentUserData, + userData=userData, + + # fcp params + ContentType=contentType, + DataLength=len(data), + #EarlyEncode='false', + #GetCHKOnly='false', + Global=False, + Identifier=None, + MaxRetries=maxRetries, + DontCompress=dontCompress, + Persistence=persistence, + PriorityClass=priorityClass, + TargetFilename=targetFilename, + UploadFrom=consts.UploadFrom.Direct, + Verbosity=consts.Verbosity.ReportProgress | consts.Verbosity.ReportCompression, + ) + + + def putRedirect(self, name, targetURI, @@ -1844,6 +1885,7 @@ def chkPutDir(self, directory, allowUnreadableFiles=False, + contentType=None, dontCompress=None, defaultName=None, @@ -1859,32 +1901,14 @@ """Uploads the contents of a directory @param directory: (str) directory to upload - - @param contentType: (str) content type. If not specified, the node will guess the content type - @param defaultName: (str) the default item to display when the key is requested - @param dontCompress: (bool) if True, the node won't try to compress the data - @param maxRetries: (int) maximum number of retries or -1 to retry forver or None to leave it to the node to decide - @param priorityClass: (L{consts.Priority}) priority of the request - @paramtargetFilename: (str) filename to append to the key (may not contain slashes) - - @param userData: any non persistent data to associate to the request - @param persistentUserData: any string to associate to the request as persistent data - - @event: (L{events.Event.RequestCompleted}) triggered when the request is complete - @event: (L{events.Event.RequestFailed}) triggered when the request failes - @event: (L{events.Event.RequestFetchable}) triggered as soon as the request is fetchable - @event: (L{events.Event.RequestCompressing}) triggered when the request is about to be compressed - @event: (L{events.Event.RequestCompressed}) triggered as soon as compressing of the request is completed - - @note: if the upload is successful the node will create a L{consts.KeyType.CHK} key under wich - the data can be retreieved. The key can be accessed as 'URI' member of the request as soon - as the L{events.Event.RequestFetchable} or the L{events.Event.RequestCompleted} event - is triggered. - - @note: when uploaded items of the directory can be accessed under Key/MyItemName/MyItemSubname + @param allowUnreadableFiles: if True, unreadable files in the directory are ignored, if False the request fails + if it encounters an unreadavle file. + @note: for other params see L{chkPutData} + @note: once uploaded, items of the directory can be accessed under Key/MyItemName/MyItemSubname + @todo: EarlyEncode and GetCHKOnly message params not implemented - @todo: 2MiB allowed? Have to test this + @todo: 2MiB compressed zize allowed? """ return self.clientPut( consts.RequestType.PutDir, @@ -1929,26 +1953,8 @@ """Uploads a file @param filename: (bytes) data to upload - @param contentType: (str) content type. If not specified, the node will guess the content type - @param dontCompress: (bool) if True, the node won't try to compress the data - @param maxRetries: (int) maximum number of retries or -1 to retry forver or None to leave it to the node to decide - @param priorityClass: (L{consts.Priority}) priority of the request - @paramtargetFilename: (str) filename to append to the key (may not contain slashes) + @note: for other params see L{chkPutData} - @param userData: any non persistent data to associate to the request - @param persistentUserData: any string to associate to the request as persistent data - - @event: (L{events.Event.RequestCompleted}) triggered when the request is complete - @event: (L{events.Event.RequestFailed}) triggered when the request failes - @event: (L{events.Event.RequestFetchable}) triggered as soon as the request is fetchable - @event: (L{events.Event.RequestCompressing}) triggered when the request is about to be compressed - @event: (L{events.Event.RequestCompressed}) triggered as soon as compressing of the request is completed - - @note: if the upload is successful the node will create a L{consts.KeyType.CHK} key under wich - the data can be retreieved. The key can be accessed as 'URI' member of the request as soon - as the L{events.Event.RequestFetchable} or the L{events.Event.RequestCompleted} event - is triggered. - @todo: EarlyEncode and GetCHKOnly message params not implemented """ return self.clientPut( @@ -1996,26 +2002,7 @@ @param items: (list) list of items to upload - @param contentType: (str) content type. If not specified, the node will guess the content type - @param dontCompress: (bool) if True, the node won't try to compress the data - @param maxRetries: (int) maximum number of retries or -1 to retry forver or None to leave it to the node to decide - @param priorityClass: (L{consts.Priority}) priority of the request - @paramtargetFilename: (str) filename to append to the key (may not contain slashes) - - @param userData: any non persistent data to associate to the request - @param persistentUserData: any string to associate to the request as persistent data - - @event: (L{events.Event.RequestCompleted}) triggered when the request is complete - @event: (L{events.Event.RequestFailed}) triggered when the request failes - @event: (L{events.Event.RequestFetchable}) triggered as soon as the request is fetchable - @event: (L{events.Event.RequestCompressing}) triggered when the request is about to be compressed - @event: (L{events.Event.RequestCompressed}) triggered as soon as compressing of the request is completed - - @note: if the upload is successful the node will create a L{consts.KeyType.CHK} key under wich - the data can be retreieved. The key can be accessed as 'URI' member of the request as soon - as the L{events.Event.RequestFetchable} or the L{events.Event.RequestCompleted} event - is triggered. - + @note: for other params see L{chkPutData} @note: to upload multiple items at once pass a dict for each item containig the following members: - FcRequestType: L{consts.RequestType.PutData}, L{consts.RequestType.PutFile} or L{consts.RequestType.PutRedirect} @@ -2064,7 +2051,7 @@ def sskPutData(self, data, privateKey, - + contentType=None, dontCompress=None, maxRetries=None, @@ -2075,6 +2062,18 @@ userData=None, persistentUserData='', ): + """Uploads data that can be updated by the owner + + @param data: (bytes) data to upload + @params privateKey: see: private key as generated by L{generateKeypair} + '/' + name + + @note: for other params see L{chkPutData} + @note: use this method to upload updatable data. First you need to create a public / private + keypair. The private key is used for uploading, the public key for retrieving the data. + You should add a name to the keypairs like: "privateKey/MyData" and "publicKey/MyData". + This may aswell be used to implement a basic edition scheme: "privateKey/MyEdition-0", + "privateKey/MyEdition-1" + """ return self.clientPut( consts.RequestType.PutData, privateKey, @@ -2086,6 +2085,7 @@ # fcp params ContentType=contentType, DataLength=len(data), + #EarlyEncode='false', #GetCHKOnly='false', Global=False, @@ -2114,8 +2114,8 @@ ## ######################################################## def uskPutData(self, - insertURI, data, + privateKey, contentType=None, dontCompress=None, @@ -2134,7 +2134,7 @@ return self.clientPut( consts.RequestType.PutData, - insertURI, + privateKey, #insertURI + 'foo/0/', userData=userData, persistentUserData=persistentUserData, @@ -2284,19 +2284,20 @@ # reset key if necessary if requestType & consts.RequestType.MaskPut: - requestUri = uri.Uri(request['URI']) - if requestUri.keyType == consts.KeyType.CHK: + requestKey = key.KeyBase.fcpToPython(request['URI']) + if requestKey is None: + raise ValueError('Ups, URI of the request seems not to be valid') + + if requestKey.KeyType == consts.KeyType.CHK: newRequest['URI'] = consts.KeyType.CHK - elif requestUri.keyType == consts.KeyType.SSK: + elif requestKey.KeyType == consts.KeyType.SSK: newRequest['URI'] = request['FcPrivateKey'] - filename = requestUri.fileName() - if filename: - newRequest['URI'] += '/' + filename - elif requestUri.keyType == consts.KeyType.USK: + if requestKey.filename: + newRequest['URI'] += '/' + requestKey.filename + elif requestKey.KeyType == consts.KeyType.USK: newRequest['URI'] = request['FcPrivateKey'] - filename = requestUri.fileName() - if filename: - newRequest['URI'] += '/' + filename + if requestKey.filename: + newRequest['URI'] += '/' + requestKey.filename self._registerRequest( newRequest, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-03-04 17:38:15
|
Revision: 307 http://fclient.svn.sourceforge.net/fclient/?rev=307&view=rev Author: jurner Date: 2008-03-04 09:38:18 -0800 (Tue, 04 Mar 2008) Log Message: ----------- new key module providing more in depth handling of freenet keys Added Paths: ----------- trunk/sandbox/fcp2/key.py Added: trunk/sandbox/fcp2/key.py =================================================================== --- trunk/sandbox/fcp2/key.py (rev 0) +++ trunk/sandbox/fcp2/key.py 2008-03-04 17:38:18 UTC (rev 307) @@ -0,0 +1,272 @@ +"""Fcp keys""" + +import os, sys +import base64 +import re +import urlparse + +#--> 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 fcp2 import consts + + +del hack +#<-- rel import hack +#************************************************************************************** +# consts +#************************************************************************************** +ReMatchExact = '\A%s\Z' + +#************************************************************************************** +# freenet base64 for keys +#************************************************************************************** +def base64UrlsaveDecode(string): + """Decodes a base64 urlsave encoded string as encoded by freenet + @param string: string to decode + @return: decoded string + + @raise TypeError: if the string can not be decoded + @note: this function handles non-standard encoding as used by freenet (see: freenet/src/support/base64.java) + """ + # freenet uses - for + and ~ for / + altchars = '-~' + + # padding may be ommitted or not + padding = 4 - len(string) % 4 + if padding: + string += '=' * padding + return base64.b64decode(string, altchars) + + +def stripKey(key): + """Strips all uri stuff from a key + @param key: (str) key to strip + @return: (str) key + """ + return urlparse.urlsplit(key)[2] + +#**************************************************************************************** +# freenet keys +# +# KeyType@32 bytes hash, 32 bytes encryption key, 5 bytes extra +# +# all byte components are base64 encoded. Freenet uses base64 without padding +# along with the following altchars for urlsave encode: - for + and ~ for / +# see: freenet/support/base64.java +# +# so a key as the user gets it to see is: +# KeyType@43 bytes, 43 bytes, 7 bytes ..of [A-Za-z0-9\-~] +# +# see: [freenet/src/support/base64.java] +# +#*************************************************************************************** +class KeyBase(object): + """ + >>> key = KeyBase.fcpToPython('CHK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo') + >>> key.pythonToFcp() + 'CHK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/' + >>> key = KeyBase.fcpToPython('CHK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/') + >>> key.pythonToFcp() + 'CHK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/' + + >>> key = KeyBase.fcpToPython('SSK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo') + >>> key.pythonToFcp() + 'SSK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/' + >>> key = KeyBase.fcpToPython('SSK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/') + >>> key.pythonToFcp() + 'SSK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/' + + >>> key = KeyBase.fcpToPython('USK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/0') + >>> key.pythonToFcp() + 'USK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/0/' + >>> key = KeyBase.fcpToPython('USK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/0/') + >>> key.pythonToFcp() + 'USK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/0/' + + >>> key = KeyBase.fcpToPython('KSK@abcde') + >>> key.pythonToFcp() + 'KSK@abcde/' + >>> key = KeyBase.fcpToPython('KSK@abcde/') + >>> key.pythonToFcp() + 'KSK@abcde/' + + """ + + KeyTypesAll = {} + + @classmethod + def fcpToPython(clss, string): + key = stripKey(string) + for clssKeyType in clss.KeyTypesAll.values(): + result = clssKeyType.fromString(key) + if result is not None: + return result + + + +class CHK(KeyBase): + """""" + _key_pattern_ = ''' + (?P<keyType>CHK@) + (?P<keyData> + (?P<hash>[a-z0-9\-~]{43}), + (?P<cryptoKey>[a-z0-9\-~]{43}), + (?P<extra>[a-z0-9\-~]{7}) + ) + (?: / (?P<filename>[^/]+?) (?: /)?)? + ''' + KeyType = consts.KeyType.CHK + KeyPattern = re.compile(_key_pattern_, re.I | re.X) + ExactKeyPattern = re.compile(ReMatchExact % _key_pattern_, re.I | re.X) + + def __init__(self, filename=None): + """Creates a CHK key + + @param filename: (str) filename to add to the key or None + """ + self.keyData = None + self.filename = filename + + def pythonToFcp(self): + out = self.KeyType + if self.keyData is not None: + out += self.keyData + '/' + if self.filename is not None: + out += self.filename + '/' + return out + + @classmethod + def fromString(clss, string): + result = clss.ExactKeyPattern.match(string) + if result is not None: + d = result.groupdict() + clss = clss(filename=d['filename']) + clss.keyData = d['keyData'] + return clss + + +KeyBase.KeyTypesAll[CHK.KeyType] = CHK + + +class SSK(KeyBase): + _key_pattern_ = ''' + (?P<keyType>SSK@) + (?P<keyData> + (?P<hash>[a-z0-9\-~]{43}), + (?P<cryptoKey>[a-z0-9\-~]{43}), + (?P<extra>[a-z0-9\-~]{7}) + ) + (?: / (?P<filename>[^/]+?)) + (?: /)? + ''' + KeyType = consts.KeyType.SSK + KeyPattern = re.compile(_key_pattern_, re.I | re.X) + ExactKeyPattern = re.compile(ReMatchExact % _key_pattern_, re.I | re.X) + + def __init__(self, keyData, filename): + self.filename = filename + self.keyData = keyData + + def pythonToFcp(self): + out = self.KeyType + if self.keyData is not None: + out += self.keyData + '/' + if self.filename is not None: + out += self.filename + '/' + return out + + @classmethod + def fromString(clss, string): + result = clss.ExactKeyPattern.match(string) + if result is not None: + d = result.groupdict() + return clss(d['keyData'], d['filename']) + +KeyBase.KeyTypesAll[SSK.KeyType] = SSK + + +class KSK(KeyBase): + _key_pattern_ = ''' + (?P<keyType>KSK@) + (?P<filename>[^/]+?) + (?: /)? + ''' + KeyType = consts.KeyType.KSK + KeyPattern = re.compile(_key_pattern_, re.I | re.X) + ExactKeyPattern = re.compile(ReMatchExact % _key_pattern_, re.I | re.X) + + + def __init__(self, filename): + self.filename = filename + + def pythonToFcp(self): + out = self.KeyType + if self.filename is not None: + out += self.filename + '/' + return out + + @classmethod + def fromString(clss, string): + result = clss.ExactKeyPattern.match(string) + if result is not None: + d = result.groupdict() + clss = clss(filename=d['filename']) + return clss + + +KeyBase.KeyTypesAll[KSK.KeyType] = KSK + + +class USK(KeyBase): + _key_pattern_ = ''' + (?P<keyType>USK@) + (?P<keyData> + (?P<hash>[a-z0-9\-~]{43}), + (?P<cryptoKey>[a-z0-9\-~]{43}), + (?P<extra>[a-z0-9\-~]{7}) + ) + (?: / (?P<filename>[^/]+?) ) + (?: / (?P<edition>[\d]+)) + (?: /)? + ''' + + KeyType = consts.KeyType.USK + KeyPattern = re.compile(_key_pattern_, re.I | re.X) + ExactKeyPattern = re.compile(ReMatchExact % _key_pattern_, re.I | re.X) + + def __init__(self, keyData, filename, edition=0): + self.edition = edition + self.filename = filename + self.keyData = keyData + + def pythonToFcp(self): + out = self.KeyType + if self.keyData is not None: + out += self.keyData + '/' + if self.filename is not None: + out += self.filename + '/' + if self.edition is not None: + out += self.edition + '/' + return out + + @classmethod + def fromString(clss, string): + result = clss.ExactKeyPattern.match(string) + if result is not None: + d = result.groupdict() + return clss(d['keyData'], d['filename'], edition=d['edition']) + +KeyBase.KeyTypesAll[USK.KeyType] = USK +#***************************************************************************** +# +#***************************************************************************** +if __name__ == '__main__': + import doctest + doctest.testmod() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-03-04 17:37:20
|
Revision: 306 http://fclient.svn.sourceforge.net/fclient/?rev=306&view=rev Author: jurner Date: 2008-03-04 09:37:20 -0800 (Tue, 04 Mar 2008) Log Message: ----------- no longer needed, use key.py instead Removed Paths: ------------- trunk/sandbox/fcp2/uri.py Deleted: trunk/sandbox/fcp2/uri.py =================================================================== --- trunk/sandbox/fcp2/uri.py 2008-03-04 17:36:51 UTC (rev 305) +++ trunk/sandbox/fcp2/uri.py 2008-03-04 17:37:20 UTC (rev 306) @@ -1,131 +0,0 @@ -"""Freennet Client Protocol uri and related methods""" - -import os, sys -import base64 -import re -import urlparse - -#--> 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 fcp2 import consts - - -del hack -#<-- rel import hack - -#************************************************************************************** -# freenet base64 for keys -#************************************************************************************** -def base64UrlsaveDecode(string): - """Decodes a base64 urlsave encoded string as encoded by freenet - @param string: string to decode - @return: decoded string - - @raise TypeError: if the string can not be decoded - @note: this function handles non-standard encoding as used by freenet (see: freenet/src/support/base64.java) - """ - # freenet uses - for + and ~ for / - altchars = '-~' - - # padding may be ommitted or not - padding = 4 - len(string) % 4 - if padding: - string += '=' * padding - return base64.b64decode(string, altchars) - -#**************************************************************************************** -# freenet keys -# -# KeyType@32 bytes hash, 32 bytes encryption key, 5 bytes extra -# -# all byte components are base64 encoded. Freenet uses base64 without padding -# along with the following altchars for urlsave encode: - for + and ~ for / -# see: freenet/support/base64.java -# -# so a key as the user gets it to see is: -# KeyType@43 bytes, 43 bytes, 7 bytes ..of [A-Za-z0-9\-~] -# -# see: [freenet/src/support/base64.java] -# -#*************************************************************************************** -KeyPat = re.compile( -r''' -^(CHK@ | SSK@ | SVK@ | USK@) -( - [a-z0-9\-~]{43}, - [a-z0-9\-~]{43}, - [a-z0-9\-~]{7} -) -''', re.I | re.X) #TODO: ignorecase? - - -def keyType(uri): - """Returns the ky type of a freenet key or None if the type could not be determined""" - if uri.startswith(consts.KeyType.KSK): - return consts.KeyType.KSK - result = KeyPat.match(uri) - if result is None: - return None - return result.group(1) - -#********************************************************************* -# -#********************************************************************* -def stripUri(uri): - """Strips scheme and location parts from an uri""" - result = urlparse.urlsplit(uri)[2] - result = result.lstrip('/') - return result - - -class Uri(object): - """Class wrappinf a freenet Uri - - @ivar keyType: L{consts.KeyType} of the uri - @ivar uri: (str) uri contained in the instance - """ - - KeyType = consts.KeyType - - - def __init__(self, uri): - """ - @param uri: (str) freenet uri (may be an uri like http://..CHK@ or - freenet:CHK@ or whatever or a a freenet key) - """ - self.uri = stripUri(uri) - result = keyType(self.uri) - self.keyType = self.KeyType.Invalid if result is None else result - - - def __nonzero__(self): - """Checks if the uri contained in the instance is a vaild freenet uri""" - return self.keyType != self.KeyType.Invalid - - - def split(self): - """Splits the uri - @return: tuple(freenet-key, file-name) - """ - if self.keyType != self.KeyType.Invalid: - head, sep, tail = self.uri.partition('/') - return head, tail - return self.uri, '' - - - def fileName(self): - """Returns the filename part of the uri - @return: str - """ - head, tail = self.split() - if tail: - return tail - return '' - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-03-04 17:36:48
|
Revision: 305 http://fclient.svn.sourceforge.net/fclient/?rev=305&view=rev Author: jurner Date: 2008-03-04 09:36:51 -0800 (Tue, 04 Mar 2008) Log Message: ----------- ... Modified Paths: -------------- trunk/sandbox/fcp2/uri.py Modified: trunk/sandbox/fcp2/uri.py =================================================================== --- trunk/sandbox/fcp2/uri.py 2008-02-29 16:26:02 UTC (rev 304) +++ trunk/sandbox/fcp2/uri.py 2008-03-04 17:36:51 UTC (rev 305) @@ -129,6 +129,3 @@ return tail return '' - - - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-29 16:26:00
|
Revision: 304 http://fclient.svn.sourceforge.net/fclient/?rev=304&view=rev Author: jurner Date: 2008-02-29 08:26:02 -0800 (Fri, 29 Feb 2008) Log Message: ----------- time deltas and byte amounts are converted now to python types Modified Paths: -------------- trunk/sandbox/fcp2/types.py Modified: trunk/sandbox/fcp2/types.py =================================================================== --- trunk/sandbox/fcp2/types.py 2008-02-29 16:25:42 UTC (rev 303) +++ trunk/sandbox/fcp2/types.py 2008-02-29 16:26:02 UTC (rev 304) @@ -5,6 +5,7 @@ import os, sys import base64 +import re #--> rel import hack class _RelImportHack(object): @@ -128,47 +129,85 @@ return int(value) / 1000 class FcpTypeTimeDelta(FcpType): - """ - @todo: how to handle time deltas? No idea... - """ + """Time durations passed as tuple((int) number, modifier). + + For modifiers see : L{consts.TimeDurationPostfix}. Number can be -1 + aswell, meaniong 'not set' or 'undefined'. + + >>> FcpTypeTimeDelta.fcpToPython('1000day') + (1000, 'day') + + >>> FcpTypeTimeDelta.fcpToPython('arbitrary') + (-1, '') + + >>> FcpTypeTimeDelta.pythonToFcp( (1000, 'day') ) + '1000day' + + """ + NumberPattern = re.compile('''(\A \d+)''', re.X) + + @classmethod + def pythonToFcp(clss, value): + return '%s%s' % value + + @classmethod + def fcpToPython(clss, value): + value = value.lower() + result = clss.NumberPattern.split(value) + if len(result) == 3: + foo, foundInt, tail = result + if tail in consts.TimeDeltaPostfix.MembersAll: + num = int(foundInt) + return (num, tail) + return (-1, consts.TimeDeltaPostfix.Second) +class FcpTypePercent(FcpTypeFloat): pass +class FcpTypeUri(FcpType): pass + class FcpTypeIP(FcpType): pass class FcpTypeIPList(FcpType): pass class FcpTypeIPort(FcpType): pass class FcpTypeStringList(FcpType): pass class FcpTypeDirname(FcpType): pass class FcpTypeFilename(FcpType): pass -class FcpTypeNumBytes(FcpType): +class FcpTypeByteAmount(FcpType): + """Byte amounts are passed as tuple((int, float) number, modifier). + + For modifiers see : L{consts.ByteAmountPostfix}. Number of bytes can be -1 + aswell, meaniong 'not set' or 'undefined'. + + >>> FcpTypeByteAmount.fcpToPython('1000k') + (1000, 'k') + + >>> FcpTypeByteAmount.fcpToPython('1.3k') + (1.3, 'k') + + >>> FcpTypeByteAmount.fcpToPython('arbitrary') + (-1, '') + + >>> FcpTypeByteAmount.pythonToFcp( (1000, 'k') ) + '1000k' + """ - @todo: how to handle byte ammounts? No idea... - """ + NumberPattern = re.compile('''(\A \d+ \. \d+) | (\A \d+)''', re.X) - NamesBinary = ('', 'K', 'M', 'G', 'T', 'P', 'E') - NamesCommon = ('', 'k', 'm', 'g', 't', 'p', 'e') - @classmethod def pythonToFcp(clss, value): - return format_num_bytes(value, binary=True, names=clss.NamesBinary) + return '%s%s' % value @classmethod def fcpToPython(clss, value): - result = -1 - if value and value != '-1': - if value[-1] in clss.NamesBinary: - names = clss.NamesBinary - binary = True - else: - names = clss.NamesCommon - binary = False - try: - result = numbers.num_bytes_to_bytes(value, binary=binary, names=names) - except ValueError: - pass - return result - - - - + result = clss.NumberPattern.split(value) + if len(result) == 4: + foo, foundFloat, foundInt, tail = result + if tail in consts.ByteAmountPostfix.MembersAll: + if foundFloat: + num = float(foundFloat) + else: + num = int(foundInt) + return (num, tail) + return (-1, consts.ByteAmountPostfix.Bytes) + class FcpTypePercent(FcpTypeFloat): pass class FcpTypeUri(FcpType): pass @@ -276,9 +315,9 @@ 'logger.dirname': FcpTypeDirname, 'logger.enabled': FcpTypeBool, 'logger.interval': FcpTypeTimeDelta, - 'logger.maxCachedBytes': FcpTypeNumBytes, - 'logger.maxCachedLines': FcpTypeNumBytes, # ??? - 'logger.maxZippedLogsSize': FcpTypeNumBytes, # ??? + 'logger.maxCachedBytes': FcpTypeByteAmount, + 'logger.maxCachedLines': FcpTypeByteAmount, # ??? + 'logger.maxZippedLogsSize': FcpTypeByteAmount, # ??? 'logger.priority': FcpTypeChoiceLoggerPriority, 'logger.priorityDetail': FcpType, # ???? is it Detailed priority thresholds ??? @@ -286,7 +325,7 @@ 'node.assumeNATed': FcpTypeBool, 'node.bindTo': FcpTypeIP, 'node.clientThrottleFile': FcpTypeFilename, - 'node.databaseMaxMemory': FcpTypeNumBytes, + 'node.databaseMaxMemory': FcpTypeByteAmount, 'node.disableHangCheckers': FcpTypeBool, 'node.disableProbabilisticHTLs': FcpTypeBool, 'node.downloadAllowedDirs': FcpTypeChoiceNodeDownloadAllowedDirs, @@ -299,7 +338,7 @@ 'node.enableULPRDataPropagation': FcpTypeBool, 'node.extraPeerDataDir': FcpTypeDirname, 'node.includeLocalAddressesInNoderefs': FcpTypeBool, - 'node.inputBandwidthLimit': FcpTypeNumBytes, # -1 is possible as value aswell + 'node.inputBandwidthLimit': FcpTypeByteAmount, # -1 is possible as value aswell 'node.ipAddressOverride': FcpTypeIP, 'node.l10n': FcpType, # ??? 'node.lazyResume': FcpTypeBool, @@ -309,12 +348,12 @@ 'node.name': FcpTypeString, 'node.nodeDir': FcpTypeDirname, 'node.oneConnectionPerIP': FcpTypeBool, - 'node.outputBandwidthLimit': FcpTypeNumBytes, + 'node.outputBandwidthLimit': FcpTypeByteAmount, 'node.passOpennetPeersThroughDarknet': FcpTypeBool, 'node.persistentTempDir': FcpTypeDirname, 'node.storeDir': FcpTypeDirname, 'node.storeForceBigShrinks': FcpTypeBool, - 'node.storeSize': FcpTypeNumBytes, + 'node.storeSize': FcpTypeByteAmount, 'node.storeType': FcpTypeString, 'node.tempDir': FcpTypeDirname, 'node.tempIPAddressHint': FcpTypeIP, # ??? @@ -324,7 +363,7 @@ 'node.testnet.enabled': FcpTypeBool, 'node.load.aggressiveGC': FcpType, # ??? - 'node.load.freeHeapBytesThreshold': FcpTypeNumBytes, + 'node.load.freeHeapBytesThreshold': FcpTypeByteAmount, 'node.load.freeHeapPercentThreshold': FcpTypePercent, 'node.load.memoryChecker': FcpTypeBool, 'node.load.nodeThrottleFile': FcpTypeFilename, @@ -762,5 +801,10 @@ MessageParamTypes['Peer'] = MessageParamTypes['AddPeer'] = PeerMessageParams +#******************************************************************************************** +# +#******************************************************************************************** +if __name__ == '__main__': + import doctest + doctest.testmod() - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-29 16:25:38
|
Revision: 303 http://fclient.svn.sourceforge.net/fclient/?rev=303&view=rev Author: jurner Date: 2008-02-29 08:25:42 -0800 (Fri, 29 Feb 2008) Log Message: ----------- added consts for time deltas and byte amounts Modified Paths: -------------- trunk/sandbox/fcp2/consts.py Modified: trunk/sandbox/fcp2/consts.py =================================================================== --- trunk/sandbox/fcp2/consts.py 2008-02-29 13:03:27 UTC (rev 302) +++ trunk/sandbox/fcp2/consts.py 2008-02-29 16:25:42 UTC (rev 303) @@ -35,6 +35,33 @@ FcpFalse = 'false' +class ByteAmountPostfix: + Bytes = '' + Kilobytes = 'k' + Kibibytes = 'K' + Megabyres = 'm' + Mebibytes = 'K' + Gigabytes = 'g' + Gibibytes = 'G' + Petabytes = 'p' + Petibytes = 'P' + Exabytes = 'e' + Exibytes = 'E' + + MembersAll = ( + Bytes, + Kilobytes, + Kibibytes, + Megabyres, + Mebibytes, + Gigabytes, + Gibibytes, + Petabytes, + Petibytes, + Exabytes, + Exibytes, + ) + class ConfigDataType: """Basic data types in config messages""" Boolean = 'boolean' @@ -144,55 +171,6 @@ Canceled = 10 -class ProtocolError(Exception): - """All protocol errors supported by the client""" - - def __init__(self, msg): - """ - @param msg: (Message) ProtocolError message or its parameters dict - """ - self.value = '%s (%s, %s)' % ( - msg.get('CodeDescription', 'Unknown error') , - msg['Code'], - msg.get('ExtraDescription', '???'), - ) - def __str__(self): return self.value - - ClientHelloMustBeFirst = 1 - NoLateClientHellos = 2 - MessageParseError = 3 - UriParseError = 4 - MissingField = 5 - ErrorParsingNumber = 6 - InvalidMessage = 7 - InvalidField = 8 - FileNotFound = 9 - DiskTargetExists = 10 # handled: - SameDirectoryExpected = 11 - CouldNotCreateFile = 12 - CouldNotWriteFile = 13 - CouldNotRenameFile = 14 - NoSuchIdentifier = 15 - NotSupported = 16 - InternalError = 17 - ShuttingDown = 18 # handled: - NoSuchNodeIdentifier = 19 # Unused since 995 - UrlParseError = 20 - ReferenceParseError = 21 - FileParseError = 22 - NotAFile = 23 - AccessDenied = 24 - DDADenied = 25 # handled: - CouldNotReadFile = 26 - ReferenceSignature = 27 - CanNotPeerWithSelf = 28 - PeerExists = 29 - OpennetDisabled = 30 - DarknetPeerOnly = 31 - NoSuchPlugin = 32 - -# others - class ConnectReason: """Reason for connecting to the node @cvar Connect: reason is a regualr connect @@ -369,6 +347,54 @@ ClientDisconnected = 'FcClientDisconnected' +class ProtocolError(Exception): + """All protocol errors supported by the client""" + + def __init__(self, msg): + """ + @param msg: (Message) ProtocolError message or its parameters dict + """ + self.value = '%s (%s, %s)' % ( + msg.get('CodeDescription', 'Unknown error') , + msg['Code'], + msg.get('ExtraDescription', '???'), + ) + def __str__(self): return self.value + + ClientHelloMustBeFirst = 1 + NoLateClientHellos = 2 + MessageParseError = 3 + UriParseError = 4 + MissingField = 5 + ErrorParsingNumber = 6 + InvalidMessage = 7 + InvalidField = 8 + FileNotFound = 9 + DiskTargetExists = 10 # handled: + SameDirectoryExpected = 11 + CouldNotCreateFile = 12 + CouldNotWriteFile = 13 + CouldNotRenameFile = 14 + NoSuchIdentifier = 15 + NotSupported = 16 + InternalError = 17 + ShuttingDown = 18 # handled: + NoSuchNodeIdentifier = 19 # Unused since 995 + UrlParseError = 20 + ReferenceParseError = 21 + FileParseError = 22 + NotAFile = 23 + AccessDenied = 24 + DDADenied = 25 # handled: + CouldNotReadFile = 26 + ReferenceSignature = 27 + CanNotPeerWithSelf = 28 + PeerExists = 29 + OpennetDisabled = 30 + DarknetPeerOnly = 31 + NoSuchPlugin = 32 + + class RequestStatus(BaseBitFlags): """Request status flags @cvar Null: no status @@ -416,6 +442,25 @@ Unknown = 'UNKNOWN STATUS' +class PeerNoteType: + """All known peer note types""" + Private = '1' + + +class Persistence: + Connection = 'connection' + Reboot = 'reboot' + Forever = 'forever' + + +class Priority: + Highest = '0' + Higher = '1' + High = '2' + Medium = '3' + Low = '4' + + class RequestType(BaseBitFlags): """Consts indicating the type of a request""" @@ -443,25 +488,6 @@ MaskPut = PutData | PutFile | PutDir | PutMultiple | PutRedirect -class PeerNoteType: - """All known peer note types""" - Private = '1' - - -class Persistence: - Connection = 'connection' - Reboot = 'reboot' - Forever = 'forever' - - -class Priority: - Highest = '0' - Higher = '1' - High = '2' - Medium = '3' - Low = '4' - - class RequestModified(BaseBitFlags): """Flags indicating what aspect of a request has been modified @cvar Filename: the filename has been modified @@ -485,6 +511,24 @@ Nothing = 'none' +class TimeDeltaPostfix: + Second = '' + Minute = 'minute' + Hour = 'hour' + Day = 'day' + Month = 'month' + Year = 'year' + + MembersAll = ( + Second, + Minute, + Hour, + Day, + Month, + Year, + ) + + class UploadFrom: Direct = 'direct' Disk = 'disk' This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-29 13:05:01
|
Revision: 302 http://fclient.svn.sourceforge.net/fclient/?rev=302&view=rev Author: jurner Date: 2008-02-29 05:03:27 -0800 (Fri, 29 Feb 2008) Log Message: ----------- fixed re pattern for freenet keys Modified Paths: -------------- trunk/sandbox/fcp2/uri.py Modified: trunk/sandbox/fcp2/uri.py =================================================================== --- trunk/sandbox/fcp2/uri.py 2008-02-29 13:02:56 UTC (rev 301) +++ trunk/sandbox/fcp2/uri.py 2008-02-29 13:03:27 UTC (rev 302) @@ -57,7 +57,7 @@ #*************************************************************************************** KeyPat = re.compile( r''' -^(CHK | SSK | SVK | USK @) +^(CHK@ | SSK@ | SVK@ | USK@) ( [a-z0-9\-~]{43}, [a-z0-9\-~]{43}, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-29 13:02:53
|
Revision: 301 http://fclient.svn.sourceforge.net/fclient/?rev=301&view=rev Author: jurner Date: 2008-02-29 05:02:56 -0800 (Fri, 29 Feb 2008) Log Message: ----------- added some unittests for resendRequest() Modified Paths: -------------- trunk/sandbox/fcp2/test_fcp/test_client.py Modified: trunk/sandbox/fcp2/test_fcp/test_client.py =================================================================== --- trunk/sandbox/fcp2/test_fcp/test_client.py 2008-02-29 13:02:31 UTC (rev 300) +++ trunk/sandbox/fcp2/test_fcp/test_client.py 2008-02-29 13:02:56 UTC (rev 301) @@ -1390,9 +1390,17 @@ self.assertRaises(ValueError, self.fcpClient.chkPutMultiple, items) - + # some sloppy tests for other key types + def testSSKPutData(self): + myIdentifier = self.fcpClient.chkPutData( + 'arbitrary data' + ) + + + + #*********************************************************************************** # #*********************************************************************************** @@ -2006,7 +2014,117 @@ #*********************************************************************************** # #*********************************************************************************** -#TODO: class TestNodeAndPeers(BaseTestConnectedClient): +#TODO: class TestNodeAndPeers(BaseTestConnectedClient): +#*********************************************************************************** +# +#*********************************************************************************** +#TODO: some tests not yet implemented +class TestResendRequests(BaseTestClient): + + def test_resend_CHK(self): + myKey = 'CHK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo' + msg = client.message.Message( + consts.Message.ClientPut, + URI=myKey, + Persistence=consts.Persistence.Connection, + ) + self.fcpClient._registerRequest(msg, consts.RequestType.PutData) + myIdentifier = msg['Identifier'] + requestsAll = self.fcpClient.getRequests() + + newIdentifier = self.fcpClient.resendRequest(msg) + + self.failIf(myIdentifier in requestsAll) + self.failUnless(newIdentifier in requestsAll) + + self.assertHasNextMessage( + consts.Message.ClientPut, + ('URI', 'CHK@') + ) + + def test_resend_SSK(self): + myKey = 'SSK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA' + msg = client.message.Message( + consts.Message.ClientPut, + URI=myKey + '/foo', + Persistence=consts.Persistence.Connection, + ) + self.fcpClient._registerRequest(msg, consts.RequestType.PutData) + msg['FcPrivateKey'] = myKey + myIdentifier = msg['Identifier'] + requestsAll = self.fcpClient.getRequests() + + newIdentifier = self.fcpClient.resendRequest(msg) + + self.failIf(myIdentifier in requestsAll) + self.failUnless(newIdentifier in requestsAll) + + self.assertHasNextMessage( + consts.Message.ClientPut, + ('URI', myKey + '/foo') + ) + + + def test_resend_USK(self): + myKey = 'USK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA' + msg = client.message.Message( + consts.Message.ClientPut, + URI=myKey + '/foo', + Persistence=consts.Persistence.Connection, + ) + self.fcpClient._registerRequest(msg, consts.RequestType.PutData) + msg['FcPrivateKey'] = myKey + myIdentifier = msg['Identifier'] + requestsAll = self.fcpClient.getRequests() + + newIdentifier = self.fcpClient.resendRequest(msg) + + self.failIf(myIdentifier in requestsAll) + self.failUnless(newIdentifier in requestsAll) + + self.assertHasNextMessage( + consts.Message.ClientPut, + ('URI', myKey + '/foo') + ) + + def test_resend_KSK(self): + myKey = 'KSK@abs' + msg = client.message.Message( + consts.Message.ClientPut, + URI=myKey, + Persistence=consts.Persistence.Connection, + ) + self.fcpClient._registerRequest(msg, consts.RequestType.PutData) + msg['FcPrivateKey'] = myKey + myIdentifier = msg['Identifier'] + requestsAll = self.fcpClient.getRequests() + + newIdentifier = self.fcpClient.resendRequest(msg) + + self.failIf(myIdentifier in requestsAll) + self.failUnless(newIdentifier in requestsAll) + + self.assertHasNextMessage( + consts.Message.ClientPut, + ('URI', myKey) + ) + + + + def test_resend_getKeyInfo(self): + pass + + def test_resend_getData(self): + pass + + def test_resend_getFile(self): + pass + + def test_resend_getFile(self): + pass + + def test_resend_unsupportedRequest(self): + pass #*********************************************************************************** # @@ -2295,9 +2413,9 @@ TestClientPut, TestRequests, TestRestoreRequests, + TestResendRequests, TestDDA, TestCollisions, - TestPlugins, TestGenerateKeypair, TestSubscribeUSK, @@ -2315,7 +2433,7 @@ if __name__ == "__main__": test() - +test() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-29 13:02:27
|
Revision: 300 http://fclient.svn.sourceforge.net/fclient/?rev=300&view=rev Author: jurner Date: 2008-02-29 05:02:31 -0800 (Fri, 29 Feb 2008) Log Message: ----------- fixes for resendRequest() Modified Paths: -------------- trunk/sandbox/fcp2/client.py Modified: trunk/sandbox/fcp2/client.py =================================================================== --- trunk/sandbox/fcp2/client.py 2008-02-27 16:56:03 UTC (rev 299) +++ trunk/sandbox/fcp2/client.py 2008-02-29 13:02:31 UTC (rev 300) @@ -2061,8 +2061,42 @@ ## SSK ClientPut related methods ## ######################################################## - def sskPutData(self): - pass + def sskPutData(self, + data, + privateKey, + + contentType=None, + dontCompress=None, + maxRetries=None, + persistence=consts.Persistence.Connection, + priorityClass=consts.Priority.Medium, + targetFilename=None, + + userData=None, + persistentUserData='', + ): + return self.clientPut( + consts.RequestType.PutData, + privateKey, + + data=data, + persistentUserData=persistentUserData, + userData=userData, + + # fcp params + ContentType=contentType, + DataLength=len(data), + #EarlyEncode='false', + #GetCHKOnly='false', + Global=False, + Identifier=None, + MaxRetries=maxRetries, + DontCompress=dontCompress, + Persistence=persistence, + PriorityClass=priorityClass, + UploadFrom=consts.UploadFrom.Direct, + Verbosity=consts.Verbosity.ReportProgress | consts.Verbosity.ReportCompression, + ) def sskPutDir(self): pass @@ -2234,6 +2268,9 @@ request, it will be removed. The new request will have FcInitTime reset and FcUserData amd FcPersistentUserData taken over from the old request + @note: for SSK and USK puts, the private key is taken from request['FcPrivateKey']. Adjust private (and public + key) if necessary + @todo: reset init time or not? Currently it is not reset. """ requestType = request.get('FcRequestType', consts.RequestType.Null) @@ -2245,7 +2282,22 @@ oldUserData, request['FcUserData'] = request['FcUserData'], None newRequest = copy.deepcopy(request) - # remove and cancel request + # reset key if necessary + if requestType & consts.RequestType.MaskPut: + requestUri = uri.Uri(request['URI']) + if requestUri.keyType == consts.KeyType.CHK: + newRequest['URI'] = consts.KeyType.CHK + elif requestUri.keyType == consts.KeyType.SSK: + newRequest['URI'] = request['FcPrivateKey'] + filename = requestUri.fileName() + if filename: + newRequest['URI'] += '/' + filename + elif requestUri.keyType == consts.KeyType.USK: + newRequest['URI'] = request['FcPrivateKey'] + filename = requestUri.fileName() + if filename: + newRequest['URI'] += '/' + filename + self._registerRequest( newRequest, requestType, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-27 16:56:00
|
Revision: 299 http://fclient.svn.sourceforge.net/fclient/?rev=299&view=rev Author: jurner Date: 2008-02-27 08:56:03 -0800 (Wed, 27 Feb 2008) Log Message: ----------- added some tests for ClientPut et al Modified Paths: -------------- trunk/sandbox/fcp2/test_fcp/test_client.py Modified: trunk/sandbox/fcp2/test_fcp/test_client.py =================================================================== --- trunk/sandbox/fcp2/test_fcp/test_client.py 2008-02-27 16:55:41 UTC (rev 298) +++ trunk/sandbox/fcp2/test_fcp/test_client.py 2008-02-27 16:56:03 UTC (rev 299) @@ -47,6 +47,9 @@ # deepcopy here, we need exact state msg = copy.deepcopy(msg) self.test_messagesSend.append(msg) + + def clearMessagesSend(self): + self.test_messagesSend = [] #*********************************************************************************** # @@ -139,6 +142,15 @@ msg = copy.deepcopy(msg) self.events.append( (event, msg) ) + + def clearClient(self): + """Clears all messages send, requests registered and events triggered so far""" + # clean up the mess we eventaully left behinf + self.events = [] + self.fcpClient.clearMessagesSend() + self.fcpClient._requests = {} + + def connectClient(self): """Connects to the client""" for n, nodeHello in enumerate(self.fcpClient.iterConnect(duration=20, timeout=0.1)): @@ -230,6 +242,16 @@ param3=None, param4=None, param5=None, + param6=None, + param7=None, + param8=None, + param9=None, + param10=None, + param11=None, + param12=None, + param13=None, + param14=None, + param15=None, data=None ): """Tests if we received a certain message from the client @@ -265,7 +287,47 @@ param5, value5 = param5 self.failUnless(param5 in msg.params) self.assertEqual(value5, msg[param5]) - + if param6 is not None: + param6, value6 = param6 + self.failUnless(param6 in msg.params) + self.assertEqual(value6, msg[param6]) + if param7 is not None: + param7, value7 = param7 + self.failUnless(param7 in msg.params) + self.assertEqual(value7, msg[param7]) + if param8 is not None: + param8, value8 = param8 + self.failUnless(param8 in msg.params) + self.assertEqual(value8, msg[param8]) + if param9 is not None: + param9, value9 = param9 + self.failUnless(param9 in msg.params) + self.assertEqual(value9, msg[param9]) + if param10 is not None: + param10, value10 = param10 + self.failUnless(param10 in msg.params) + self.assertEqual(value10, msg[param10]) + if param11 is not None: + param11, value11 = param11 + self.failUnless(param11 in msg.params) + self.assertEqual(value11, msg[param11]) + if param12 is not None: + param12, value12 = param12 + self.failUnless(param12 in msg.params) + self.assertEqual(value12, msg[param12]) + if param13 is not None: + param13, value13 = param13 + self.failUnless(param13 in msg.params) + self.assertEqual(value13, msg[param13]) + if param14 is not None: + param14, value14 = param14 + self.failUnless(param14 in msg.params) + self.assertEqual(value14, msg[param14]) + if param15 is not None: + param15, value15 = param15 + self.failUnless(param15 in msg.params) + self.assertEqual(value15, msg[param15]) + if data is not None: self.assertEqual(data, msg.data) return msg @@ -289,6 +351,7 @@ event -= self._captureEventsFromClient # clean up tmpfiles for fpath in self.tmpfiles: os.remove(fpath) + self.clearClient() #*********************************************************************************** # @@ -956,11 +1019,11 @@ #*********************************************************************************** #TODO: # -# -# +# SSK@, USK@ +# putFile / PutDir TestDDA + class TestClientPut(BaseTestClient): - - + def testPutRedirect_Success(self): # request a arbitrary file myIdentifier = self.fcpClient.putRedirect( @@ -1025,9 +1088,311 @@ self.failIf(requestsAll) + def testCHKPutData_Success(self): + # request a arbitrary file + myIdentifier = self.fcpClient.chkPutData( + 'arbitrary data' + ) + 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='CHK@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 testCHKPutData_Failure(self): + # request a arbitrary file + myIdentifier = self.fcpClient.chkPutData( + 'arbitrary data' + ) + 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) + + def testCHKPutDir_Success(self): + # request a arbitrary file + myIdentifier = self.fcpClient.chkPutDir( + 'myDirectory' + ) + myRequest = self.fcpClient.getRequest(myIdentifier) + requestsAll = self.fcpClient.getRequests() + + self.assertHasNextMessage(consts.Message.ClientPutDiskDir) + self.failUnless(myIdentifier in requestsAll) + + self.sendResponseMessage( + 'PutSuccessful', + Identifier=myIdentifier, + URI='CHK@my-redirect-name' + ) + + self.assertHasNextEvent( + self.fcpClient.events.RequestCompleted, + consts.Message.ClientPutDiskDir, + ('FcRequestStatus', consts.RequestStatus.Success | + consts.RequestStatus.RemovedFromQueue | + consts.RequestStatus.Completed + ), + ) + + self.assertHasNextEvent(None) + self.assertHasNextMessage(None) + self.failIf(requestsAll) + + + def testCHKPutDir_Failure(self): + # request a arbitrary file + myIdentifier = self.fcpClient.chkPutDir( + 'myDirectory' + ) + myRequest = self.fcpClient.getRequest(myIdentifier) + requestsAll = self.fcpClient.getRequests() + + self.assertHasNextMessage(consts.Message.ClientPutDiskDir) + self.failUnless(myIdentifier in requestsAll) + + self.sendResponseMessage( + 'PutFailed', + Identifier=myIdentifier, + Code='5', # rout not found + ) + + self.assertHasNextEvent( + self.fcpClient.events.RequestFailed, + consts.Message.ClientPutDiskDir, + ('FcRequestStatus', consts.RequestStatus.Error | + consts.RequestStatus.RemovedFromQueue | + consts.RequestStatus.Completed + ), + ) + + self.assertHasNextEvent(None) + self.assertHasNextMessage(None) + self.failIf(requestsAll) + + + def testCHKPutFile_Success(self): + # request a arbitrary file + myIdentifier = self.fcpClient.chkPutFile( + 'myFile.txt' + ) + 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='CHK@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 testCHKPutFile_Failure(self): + # request a arbitrary file + myIdentifier = self.fcpClient.chkPutFile( + 'myFile.txt' + ) + 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) + + + + def testCHKPutMultiple_Success(self): + + items = [ + { + 'FcRequestType': consts.RequestType.PutData, + 'Data': '12345', + 'Name': 'myItem0', + }, + { + 'FcRequestType': consts.RequestType.PutFile, + 'Filename': 'myFile.txt', + 'Name': 'myItem1', + }, + { + 'FcRequestType': consts.RequestType.PutRedirect, + 'TargetURI': 'CHK@123456789', + 'Name': 'myItem2', + }, + { + 'FcRequestType': consts.RequestType.PutData, + 'Data': '67890', + 'Name': 'myItem3', + }, + ] + + # request a arbitrary file + myIdentifier = self.fcpClient.chkPutMultiple( + items + ) + myRequest = self.fcpClient.getRequest(myIdentifier) + requestsAll = self.fcpClient.getRequests() + + msg = self.assertHasNextMessage( + consts.Message.ClientPutComplexDir, + ('Files.0.Name', 'myItem0'), + ('Files.0.UploadFrom', 'direct'), + ('Files.0.DataLength', 5), + + ('Files.1.Name', 'myItem1'), + ('Files.1.UploadFrom', 'disk'), + ('Files.1.Filename', 'myFile.txt'), + + ('Files.2.Name', 'myItem2'), + ('Files.2.UploadFrom', 'redirect'), + ('Files.2.TargetURI', 'CHK@123456789'), + + ('Files.3.Name', 'myItem3'), + ('Files.3.UploadFrom', 'direct'), + ('Files.3.DataLength', 5), + + data='1234567890' + ) + + #for k, v in sorted(msg.params.items()): + # print k, v + + self.failUnless(myIdentifier in requestsAll) + + self.sendResponseMessage( + 'PutSuccessful', + Identifier=myIdentifier, + URI='CHK@my-redirect-name' + ) + + self.assertHasNextEvent( + self.fcpClient.events.RequestCompleted, + consts.Message.ClientPutComplexDir, + ('FcRequestStatus', consts.RequestStatus.Success | + consts.RequestStatus.RemovedFromQueue | + consts.RequestStatus.Completed + ), + ) + + self.assertHasNextEvent(None) + self.assertHasNextMessage(None) + self.failIf(requestsAll) + + + def testCHKPutMultiple_ItemErrors(self): + + + # upload directory is not allowed + items = [ + { + 'FcRequestType': consts.RequestType.PutDir, + 'Data': '12345', + 'Name': 'myItem0', + }, + ] + self.assertRaises(ValueError, self.fcpClient.chkPutMultiple, items) + + #TODO: how to test required params? + # ...just some samples below + + # no request type specified + items = [ + { + #'FcRequestType': consts.RequestType.PutData, + 'Data': '12345', + 'Name': 'myItem0', + }, + ] + self.assertRaises(ValueError, self.fcpClient.chkPutMultiple, items) + + # param missing (we enforce all required parameters) + items = [ + { + 'FcRequestType': consts.RequestType.PutData, + #'Data': '12345', + #'Name': 'myItem0', + }, + ] + self.assertRaises(ValueError, self.fcpClient.chkPutMultiple, items) + + + + + #*********************************************************************************** # #*********************************************************************************** This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-27 16:55:34
|
Revision: 298 http://fclient.svn.sourceforge.net/fclient/?rev=298&view=rev Author: jurner Date: 2008-02-27 08:55:41 -0800 (Wed, 27 Feb 2008) Log Message: ----------- Some fixes for uploadMultiple and more docs Modified Paths: -------------- trunk/sandbox/fcp2/client.py Modified: trunk/sandbox/fcp2/client.py =================================================================== --- trunk/sandbox/fcp2/client.py 2008-02-27 14:14:59 UTC (rev 297) +++ trunk/sandbox/fcp2/client.py 2008-02-27 16:55:41 UTC (rev 298) @@ -1486,10 +1486,12 @@ @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, + @event: (L{events.Event.RequestCompleted}) triggered when the request is complete + @event: (L{events.Event.RequestFailed}) triggered when the request failes + @event: (L{events.Event.RequestFetchable}) triggered as soon as the request is fetchable + @event: (L{events.Event.RequestCompressing}) triggered when the request is about to be compressed + @event: (L{events.Event.RequestCompressed}) triggered as soon as compressing of the request is completed + 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 @@ -1623,8 +1625,7 @@ @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: + @note: to upload multiple items at once 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 @@ -1660,39 +1661,71 @@ msg.data = data 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') + uploadTypeMapping = { + consts.RequestType.PutData: consts.UploadFrom.Direct, + consts.RequestType.PutFile: consts.UploadFrom.Disk, + consts.RequestType.PutRedirect: consts.UploadFrom.Redirect, + } + # requestType --> [(allowedParam: boolParamIsRequired), ...] + paramMapping = { + consts.RequestType.PutData: [ + ('Name', True), + ('Data', True), + ('ContentType', False), + ], + consts.RequestType.PutFile: [ + ('Name', True), + ('Filename', True), + ('Metadata.ContentType', False), + ], + consts.RequestType.PutRedirect: [ + ('Name', True), + ('TargetURI', True), + ], + } + 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) + uploadFrom = uploadTypeMapping.get(requestType, None) if uploadFrom is None: - raise valueError('Unsupported request type for item %s: %s' % (n, requestType)) + raise ValueError('Unsupported request type for item %s: %s' % (n, requestType)) contentType = item.get('ContentType', None) - if conetntType is not None: + if contentType is not None: del msgParams['ContentType'] item['Metadata.ContentType'] = contentType + allowedParams = dict(paramMapping[requestType]) 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) + + if param in allowedParams: + del allowedParams[param] + else: + raise ValueError('Unsupported param for item %s: %s' % (n, param)) + + if param == 'Data': + data += value + msg.params['Files.%s.DataLength' % n] = len(value) continue msg.params['Files.%s.%s' % (n, param)] = value + # errorcheck params + if allowedParams: + for paramName, isRequired in allowedParams.items(): + if isRequired: + raise ValueError('Param "%s" is required for item %s' % (paramName, n)) + msg['DefaultName'] = items[0].get('Name', '') if data: msg.data = data @@ -1750,7 +1783,6 @@ contentType=None, dontCompress=None, - filename=None, maxRetries=None, persistence=consts.Persistence.Connection, priorityClass=consts.Priority.Medium, @@ -1759,9 +1791,31 @@ userData=None, persistentUserData='', ): + """Uploads data + @param data: (bytes) data to upload + + @param contentType: (str) content type. If not specified, the node will guess the content type + @param dontCompress: (bool) if True, the node won't try to compress the data + @param maxRetries: (int) maximum number of retries or -1 to retry forver or None to leave it to the node to decide + @param priorityClass: (L{consts.Priority}) priority of the request + @paramtargetFilename: (str) filename to append to the key (may not contain slashes) + + @param userData: any non persistent data to associate to the request + @param persistentUserData: any string to associate to the request as persistent data + + @event: (L{events.Event.RequestCompleted}) triggered when the request is complete + @event: (L{events.Event.RequestFailed}) triggered when the request failes + @event: (L{events.Event.RequestFetchable}) triggered as soon as the request is fetchable + @event: (L{events.Event.RequestCompressing}) triggered when the request is about to be compressed + @event: (L{events.Event.RequestCompressed}) triggered as soon as compressing of the request is completed + + @note: if the upload is successful the node will create a L{consts.KeyType.CHK} key under wich + the data can be retreieved. The key can be accessed as 'URI' member of the request as soon + as the L{events.Event.RequestFetchable} or the L{events.Event.RequestCompleted} event + is triggered. + + @todo: EarlyEncode and GetCHKOnly message params not implemented """ - @param data: () - """ return self.clientPut( consts.RequestType.PutData, consts.KeyType.CHK, @@ -1791,8 +1845,8 @@ directory, allowUnreadableFiles=False, contentType=None, + dontCompress=None, defaultName=None, - dontCompress=None, maxRetries=None, persistence=consts.Persistence.Connection, priorityClass=consts.Priority.Medium, @@ -1802,9 +1856,36 @@ persistentUserData='', ): + """Uploads the contents of a directory + + @param directory: (str) directory to upload + + @param contentType: (str) content type. If not specified, the node will guess the content type + @param defaultName: (str) the default item to display when the key is requested + @param dontCompress: (bool) if True, the node won't try to compress the data + @param maxRetries: (int) maximum number of retries or -1 to retry forver or None to leave it to the node to decide + @param priorityClass: (L{consts.Priority}) priority of the request + @paramtargetFilename: (str) filename to append to the key (may not contain slashes) + + @param userData: any non persistent data to associate to the request + @param persistentUserData: any string to associate to the request as persistent data + + @event: (L{events.Event.RequestCompleted}) triggered when the request is complete + @event: (L{events.Event.RequestFailed}) triggered when the request failes + @event: (L{events.Event.RequestFetchable}) triggered as soon as the request is fetchable + @event: (L{events.Event.RequestCompressing}) triggered when the request is about to be compressed + @event: (L{events.Event.RequestCompressed}) triggered as soon as compressing of the request is completed + + @note: if the upload is successful the node will create a L{consts.KeyType.CHK} key under wich + the data can be retreieved. The key can be accessed as 'URI' member of the request as soon + as the L{events.Event.RequestFetchable} or the L{events.Event.RequestCompleted} event + is triggered. + + @note: when uploaded items of the directory can be accessed under Key/MyItemName/MyItemSubname + + @todo: EarlyEncode and GetCHKOnly message params not implemented + @todo: 2MiB allowed? Have to test this """ - @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, @@ -1845,10 +1926,31 @@ persistentUserData='', ): + """Uploads a file + @param filename: (bytes) data to upload + + @param contentType: (str) content type. If not specified, the node will guess the content type + @param dontCompress: (bool) if True, the node won't try to compress the data + @param maxRetries: (int) maximum number of retries or -1 to retry forver or None to leave it to the node to decide + @param priorityClass: (L{consts.Priority}) priority of the request + @paramtargetFilename: (str) filename to append to the key (may not contain slashes) + + @param userData: any non persistent data to associate to the request + @param persistentUserData: any string to associate to the request as persistent data + + @event: (L{events.Event.RequestCompleted}) triggered when the request is complete + @event: (L{events.Event.RequestFailed}) triggered when the request failes + @event: (L{events.Event.RequestFetchable}) triggered as soon as the request is fetchable + @event: (L{events.Event.RequestCompressing}) triggered when the request is about to be compressed + @event: (L{events.Event.RequestCompressed}) triggered as soon as compressing of the request is completed + + @note: if the upload is successful the node will create a L{consts.KeyType.CHK} key under wich + the data can be retreieved. The key can be accessed as 'URI' member of the request as soon + as the L{events.Event.RequestFetchable} or the L{events.Event.RequestCompleted} event + is triggered. + + @todo: EarlyEncode and GetCHKOnly message params not implemented """ - @param targetFilename: (str) filename to append to the CHK key or None (may not contain slashes) - """ - return self.clientPut( consts.RequestType.PutFile, consts.KeyType.CHK, @@ -1890,14 +1992,44 @@ persistentUserData='', ): - """Uploads multiple items at once + """Uploads multiple items at once to be retrievable under one key - @param items: + @param items: (list) list of items to upload - @param targetFilename: (str) filename to append to the CHK key or None (may not contain slashes) + @param contentType: (str) content type. If not specified, the node will guess the content type + @param dontCompress: (bool) if True, the node won't try to compress the data + @param maxRetries: (int) maximum number of retries or -1 to retry forver or None to leave it to the node to decide + @param priorityClass: (L{consts.Priority}) priority of the request + @paramtargetFilename: (str) filename to append to the key (may not contain slashes) + @param userData: any non persistent data to associate to the request + @param persistentUserData: any string to associate to the request as persistent data + @event: (L{events.Event.RequestCompleted}) triggered when the request is complete + @event: (L{events.Event.RequestFailed}) triggered when the request failes + @event: (L{events.Event.RequestFetchable}) triggered as soon as the request is fetchable + @event: (L{events.Event.RequestCompressing}) triggered when the request is about to be compressed + @event: (L{events.Event.RequestCompressed}) triggered as soon as compressing of the request is completed + @note: if the upload is successful the node will create a L{consts.KeyType.CHK} key under wich + the data can be retreieved. The key can be accessed as 'URI' member of the request as soon + as the L{events.Event.RequestFetchable} or the L{events.Event.RequestCompleted} event + is triggered. + + @note: to upload multiple items at once 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. + + + @todo: EarlyEncode and GetCHKOnly message params not implemented """ return self.clientPut( consts.RequestType.PutMultiple, @@ -1909,7 +2041,6 @@ items=items, # fcp params - Filename=directory, AllowUnreadableFiles=allowUnreadableFiles, ContentType=contentType, DefaultName=defaultName, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-27 14:15:05
|
Revision: 297 http://fclient.svn.sourceforge.net/fclient/?rev=297&view=rev Author: jurner Date: 2008-02-27 06:14:59 -0800 (Wed, 27 Feb 2008) Log Message: ----------- ups... Modified Paths: -------------- trunk/sandbox/fcp2/client.py Modified: trunk/sandbox/fcp2/client.py =================================================================== --- trunk/sandbox/fcp2/client.py 2008-02-27 14:14:01 UTC (rev 296) +++ trunk/sandbox/fcp2/client.py 2008-02-27 14:14:59 UTC (rev 297) @@ -241,7 +241,7 @@ DefaultFcpHost = os.environ.get('FCP_HOST', '127.0.0.1') DefaultFcpPort = int(os.environ.get('FCP_PORT', '9481')) MaxSizeKeyInfo = 32768 - MinimumRunTime = 1s # FIX: 0001931 + MinimumRunTime = 1 # FIX: 0001931 SocketTimeout = 0.1 consts = consts This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-27 14:14:01
|
Revision: 296 http://fclient.svn.sourceforge.net/fclient/?rev=296&view=rev Author: jurner Date: 2008-02-27 06:14:01 -0800 (Wed, 27 Feb 2008) Log Message: ----------- set client debug level to quiet Modified Paths: -------------- trunk/sandbox/fcp2/test_fcp/test_client.py Modified: trunk/sandbox/fcp2/test_fcp/test_client.py =================================================================== --- trunk/sandbox/fcp2/test_fcp/test_client.py 2008-02-27 14:13:38 UTC (rev 295) +++ trunk/sandbox/fcp2/test_fcp/test_client.py 2008-02-27 14:14:01 UTC (rev 296) @@ -118,7 +118,8 @@ if TestAgainstNode: DummySocketModule.socket = MySocketFactory() fcpClient = MyFcpClient( - #debugVerbosity=FcpClient.consts.DebugVerbosity.Debug + #debugVerbosity=Client.consts.DebugVerbosity.Debug + debugVerbosity=Client.consts.DebugVerbosity.Quiet ) # inject our customized socket module This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-27 14:13:35
|
Revision: 295 http://fclient.svn.sourceforge.net/fclient/?rev=295&view=rev Author: jurner Date: 2008-02-27 06:13:38 -0800 (Wed, 27 Feb 2008) Log Message: ----------- added debug level quiet ++ some more docs Modified Paths: -------------- trunk/sandbox/fcp2/client.py Modified: trunk/sandbox/fcp2/client.py =================================================================== --- trunk/sandbox/fcp2/client.py 2008-02-27 14:13:28 UTC (rev 294) +++ trunk/sandbox/fcp2/client.py 2008-02-27 14:13:38 UTC (rev 295) @@ -212,11 +212,21 @@ #<-- rel import hack logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) +logging.addLevelName(consts.DebugVerbosity.Quiet, '') #************************************************************************************************* # #************************************************************************************************* class Client(object): """ + @cvar ExpectedFcpVersion: (float) minimum expected Freenet client protocol version + @cvar ExpectedNodeBuild: (int) minimum expected node build + @cvar DefaultFcpHost: (str) default Fcp host + @cvar DefaultFcpPort: (int) default Fcp port + @cvar MaxSizeKeyInfo: (bytes) maximum request size for key info requests + @cvar inimumRunTime: (seconds) minimum runtime when the L{run} method is called. + Required to make shure persistent requests can be taken up from the node. + @cvar SocketTimeout: (seconds) default socket timeout + @ivar events: events the client supports @@ -231,7 +241,7 @@ DefaultFcpHost = os.environ.get('FCP_HOST', '127.0.0.1') DefaultFcpPort = int(os.environ.get('FCP_PORT', '9481')) MaxSizeKeyInfo = 32768 - MinimumRunTime = 1 # minimum time (seconds) the client will run when run() is called (FIX: 0001931) + MinimumRunTime = 1s # FIX: 0001931 SocketTimeout = 0.1 consts = consts This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-27 14:13:23
|
Revision: 294 http://fclient.svn.sourceforge.net/fclient/?rev=294&view=rev Author: jurner Date: 2008-02-27 06:13:28 -0800 (Wed, 27 Feb 2008) Log Message: ----------- added debug level quiet Modified Paths: -------------- trunk/sandbox/fcp2/consts.py Modified: trunk/sandbox/fcp2/consts.py =================================================================== --- trunk/sandbox/fcp2/consts.py 2008-02-27 13:52:12 UTC (rev 293) +++ trunk/sandbox/fcp2/consts.py 2008-02-27 14:13:28 UTC (rev 294) @@ -209,6 +209,8 @@ Warning = logging.WARNING Error = logging.ERROR Critical = logging.CRITICAL + Quiet = 1000000 + class DisconnectReason(BaseBitFlags): """Reasons for client disconnect This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-27 13:52:07
|
Revision: 293 http://fclient.svn.sourceforge.net/fclient/?rev=293&view=rev Author: jurner Date: 2008-02-27 05:52:12 -0800 (Wed, 27 Feb 2008) Log Message: ----------- removed a leftover print statement Modified Paths: -------------- trunk/sandbox/fcp2/fcparams.py Modified: trunk/sandbox/fcp2/fcparams.py =================================================================== --- trunk/sandbox/fcp2/fcparams.py 2008-02-27 13:51:52 UTC (rev 292) +++ trunk/sandbox/fcp2/fcparams.py 2008-02-27 13:52:12 UTC (rev 293) @@ -92,7 +92,6 @@ for i, (paramName, paramValidator) in enumerate(FcParams): result = paramValidator(params[i]) - print paramName, paramValidator, result if result is None: return None params[i] = result This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-27 13:51:53
|
Revision: 292 http://fclient.svn.sourceforge.net/fclient/?rev=292&view=rev Author: jurner Date: 2008-02-27 05:51:52 -0800 (Wed, 27 Feb 2008) Log Message: ----------- fix: Client.Config is now Client.config.Config Modified Paths: -------------- trunk/sandbox/fcp2/test_fcp/test_config.py Modified: trunk/sandbox/fcp2/test_fcp/test_config.py =================================================================== --- trunk/sandbox/fcp2/test_fcp/test_config.py 2008-02-27 12:07:31 UTC (rev 291) +++ trunk/sandbox/fcp2/test_fcp/test_config.py 2008-02-27 13:51:52 UTC (rev 292) @@ -38,7 +38,7 @@ 'default.console.enabled': 'false', } - cfg = Client.Config(Msg) + cfg = Client.config.Config(Msg) # check if all items and values have been set as expected consoleItem = cfg.children.get('console', None) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-27 12:07:25
|
Revision: 291 http://fclient.svn.sourceforge.net/fclient/?rev=291&view=rev Author: jurner Date: 2008-02-27 04:07:31 -0800 (Wed, 27 Feb 2008) Log Message: ----------- minor change Modified Paths: -------------- trunk/sandbox/fcp2/fcparams.py Modified: trunk/sandbox/fcp2/fcparams.py =================================================================== --- trunk/sandbox/fcp2/fcparams.py 2008-02-27 12:06:59 UTC (rev 290) +++ trunk/sandbox/fcp2/fcparams.py 2008-02-27 12:07:31 UTC (rev 291) @@ -38,7 +38,6 @@ except ValueError: return None -#TODO: validate FcPersistentUserData... only ASCII (???) chars allowed def validateString(value): try: return str(value) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-27 12:06:58
|
Revision: 290 http://fclient.svn.sourceforge.net/fclient/?rev=290&view=rev Author: jurner Date: 2008-02-27 04:06:59 -0800 (Wed, 27 Feb 2008) Log Message: ----------- combed over docs Modified Paths: -------------- trunk/sandbox/fcp2/types.py Modified: trunk/sandbox/fcp2/types.py =================================================================== --- trunk/sandbox/fcp2/types.py 2008-02-27 12:06:38 UTC (rev 289) +++ trunk/sandbox/fcp2/types.py 2008-02-27 12:06:59 UTC (rev 290) @@ -1,4 +1,4 @@ -"""Fcp types vs. Python types +"""Fcp types vs Python types This module handles type conversions from Fcp to Python and vice versa """ @@ -21,7 +21,6 @@ del hack #<-- rel import hack - #************************************************************************************* # #************************************************************************************* @@ -128,8 +127,10 @@ def fcpToPython(clss, value): return int(value) / 1000 -#TODO: how to handle time deltas? Convert them to seconds? -class FcpTypeTimeDelta(FcpType): pass +class FcpTypeTimeDelta(FcpType): + """ + @todo: how to handle time deltas? No idea... + """ class FcpTypeIP(FcpType): pass class FcpTypeIPList(FcpType): pass @@ -137,10 +138,10 @@ class FcpTypeStringList(FcpType): pass class FcpTypeDirname(FcpType): pass class FcpTypeFilename(FcpType): pass - -#TODO: how to handle byte amounts? Convert them to (int) bytes? class FcpTypeNumBytes(FcpType): - """Type conversion """ + """ + @todo: how to handle byte ammounts? No idea... + """ NamesBinary = ('', 'K', 'M', 'G', 'T', 'P', 'E') NamesCommon = ('', 'k', 'm', 'g', 't', 'p', 'e') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-27 12:06:35
|
Revision: 289 http://fclient.svn.sourceforge.net/fclient/?rev=289&view=rev Author: jurner Date: 2008-02-27 04:06:38 -0800 (Wed, 27 Feb 2008) Log Message: ----------- combed over docs Modified Paths: -------------- trunk/sandbox/fcp2/events.py Modified: trunk/sandbox/fcp2/events.py =================================================================== --- trunk/sandbox/fcp2/events.py 2008-02-27 12:06:22 UTC (rev 288) +++ trunk/sandbox/fcp2/events.py 2008-02-27 12:06:38 UTC (rev 289) @@ -13,6 +13,7 @@ def __del__(self): sys.path.pop(0) hack = _RelImportHack(2) +from fcp2 import consts from fcp2 import types from fcp2.fcp_lib import events @@ -98,11 +99,25 @@ """A request failed""" class RequestFetchable(events.Event): - """An upload is fetchable""" + """An upload is fetchable + The upload is not yet completed but it should be alreay fetchable + """ + class RequestModified(events.Event): - """A request has been modified""" + """A request has been modified + The 'FcModified' member of the request will contain + a dict indicating wich aspect of the request was modified. + + The dict is a mapping of one or more [L{consts.RequestModified}] flag to the modified value. + Modified value will always be None, except when the aspect is [L{consts.RequestModified.Identifier}] + or [L{consts.RequestModified.Filename}] + + @note: due to internal reasons the [L{consts.RequestModified.PersistentUserData}] member will + always be present + """ + class RequestProgress(events.Event): """A request has made some progress""" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ju...@us...> - 2008-02-27 12:06:19
|
Revision: 288 http://fclient.svn.sourceforge.net/fclient/?rev=288&view=rev Author: jurner Date: 2008-02-27 04:06:22 -0800 (Wed, 27 Feb 2008) Log Message: ----------- combed over docs Modified Paths: -------------- trunk/sandbox/fcp2/consts.py Modified: trunk/sandbox/fcp2/consts.py =================================================================== --- trunk/sandbox/fcp2/consts.py 2008-02-27 12:05:55 UTC (rev 287) +++ trunk/sandbox/fcp2/consts.py 2008-02-27 12:06:22 UTC (rev 288) @@ -441,25 +441,6 @@ MaskPut = PutData | PutFile | PutDir | PutMultiple | PutRedirect -#TODO: no idea how fcp handles strings as in <Peer volatile.status=CONNECTED> -# all I could find in the sources where these constants as in PEER_NODE_STATUS_CONNECTED -# in --> freenet/node/PeerManager.java -class PeerNodeStatus: - Connected = 1 - RoutingBackedOff = 2 - TooNew = 3 - TooOld = 4 - Disconnected = 5 - NeverConnected = 6 - Disabled = 7 - Bursting = 8 - Listening = 9 - ListenOnly = 10 - ClockProblem = 11 - ConnError = 12 - Disconnecting = 13 - - class PeerNoteType: """All known peer note types""" Private = '1' @@ -480,10 +461,10 @@ class RequestModified(BaseBitFlags): - """Flags indicating what of a request has been modified + """Flags indicating what aspect of a request has been modified @cvar Filename: the filename has been modified @cvar Identifier: the identifier has been moodified - @cvar PersistentUserData: thepersistent user data has been modified + @cvar PersistentUserData: persistent user data has been modified @cvar PriorityClass: the priority class has been modified @note: the FcModified member of the params dict of a request may contain This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |