« Return to Thread: Potential new Stomp.py

Potential new Stomp.py

by Jeff Ward :: Rate this Message:

Reply to Author | View in Thread

Hey everyone,

I've recently re-written the Stomp python client and I wanted some opinions on the new version (whether it's better than what's currently in svn, how it can be improved, etc).  Help from seasoned Python developers swould be appreciated.

Thanks guys!

--
Jeff

[stomp.py]

"""
This is a STOMP protocol module that is designed to be as
simple as possible.

@author Jeff Ward
"""
import socket

""" Private class for doing properties through decorators"""
def Property(function):
    return property(doc=function.__doc__, **function())    

class StompFrame(object):
    def __init__(self,  command,  headers=None):
        if headers is None:
            headers = {}
        self.__command = command
        self.__headers = headers
        self.__body = ""
   
    @Property
    def command():
        def fget(self):
            return self.__command
        def fset(self,  value):
            self.__command = value
        return locals()
   
    @Property
    def headers():
        def fget(self):
            return self.__headers
        return locals()
   
    @Property
    def body():
        def fget(self):
            return self.__body
        def fset(self, value):
            self.__body = value
        return locals()

class Connection(object):
   
    @Property
    def connected():
        def fget(self):
            return self.__connected
        return locals()
   
    def __init__(self,  hostName,  port=61613,  login=None,  passcode=None):
        self.__socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.__connected = False
        self.__hostName = hostName
        self.__port = port
        self.__login = login
        self.__passcode = passcode
        self.__receiveBuffer = ''
       
    def connect(self):
        self.__socket.connect ((self.__hostName, self.__port))
       
        frame = StompFrame("CONNECT")
        if(self.__login != None):
            frame.headers["login"] = self.__login
        if(self.__passcode != None):
            frame.headers["passcode"] = self.__passcode
           
        self.send (frame)
        frame = self.receive()
        if(frame == None or frame.command != "CONNECTED"):
            # TODO: Throw an exception
            pass
        else:
            self.__connected = True
           
    def close(self):
        frame = StompFrame("DISCONNECT")
        self.send(frame)
        self.__receiveBuffer = ''
        self.__socket.shutdown(socket.SHUT_RDWR)
        self.__socket.close()
        self.__connected = False
       
    def send(self,  frame):
        # Before sending, we need to check to see if
        # this message is unicode, and add headers if need be.
        if isinstance(frame.body, unicode):
            actualBody = frame.body.encode('UTF-8')
            frame.headers["content-encoding"] = "UTF-8"
            frame.headers["content-length"] = len(actualBody)
            frame.body = actualBody
           
        self.__socket.sendall("%s\n" % (frame.command))
        for k,v in frame.headers.items():
            self.__socket.sendall ("%s:%s\n" % (k,v))
        self.__socket.sendall ("\n")
        self.__socket.sendall (frame.body)
        self.__socket.sendall ("\x00\n")
           
    def receive(self, timeout=None):
        if timeout != None:
            oldTimeout = self.__socket.gettimeout()
            self.__socket.settimeout(timeout)
           
        command = self.__readBufferLine()
        frame = StompFrame(command)
       
        header = self.__readBufferLine()
        while(header != ''):
            colon = header.index(':')
            frame.headers[header[:colon]] =  header[colon+1:]
            header = self.__readBufferLine()
       
        body = ''
        # First, check to see if we have a content-length header
        if frame.headers.has_key('content-length'):
            # If we do, it means we can read to then end, accounting for
            # the extra "null" bit at the end (which is added to all Stomp messages)
            length = int(frame.headers['content-length'])
            while len(self.__receiveBuffer) < length + 1: # +1 is for the final \x00
                self.__readToBuffer()
            encodedBody, self.__receiveBuffer = self.__receiveBuffer[:length], self.__receiveBuffer[length + 1:]
            # Check if this was encoded some how and decode it if it was
            if frame.headers.has_key('content-encoding'):
                body = encodedBody.decode(frame.headers['content-encoding'])
            else:
                body = encodedBody
        else:
            # If there's no content length, we have an ascii string, and we can just read until
            # we get a "null" character.
            eofIndex = self.__receiveBuffer.find('\x00')
            while eofIndex < 0:
                self.__readToBuffer()
                eofIndex = self.__receiveBuffer.find('\x00')
           
            body,  self.__receiveBuffer = self.__receiveBuffer[:eofIndex],  self.__receiveBuffer[eofIndex + 1:]
               
        frame.body = body
       
        # Remove the trailing newline
        self.__readBufferLine()
       
        if timeout != None:
            self.__socket.settimeout(oldTimeout)
           
        return frame
   
    def __readToBuffer(self):
        data = self.__socket.recv(2048)
        self.__receiveBuffer = self.__receiveBuffer + data
   
    def __readBufferLine(self):
        nlIndex = self.__receiveBuffer.find('\n')
        while nlIndex < 0:
            self.__readToBuffer()
            nlIndex = self.__receiveBuffer.find('\n')
       
        line,  self.__receiveBuffer = self.__receiveBuffer[:nlIndex],  self.__receiveBuffer[nlIndex + 1:]
        return line

class Message:
        headers={}
        body=""
        command=""
       
        def init(self,cmd,hds,bdy):
                self.headers=hds
                self.body=bdy
                self.command=cmd


---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

 « Return to Thread: Potential new Stomp.py