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