def test_extract_frame_multi(self): """ Test the handling of multiple concatenated messages by the buffer. """ m1 = b'CONNECT\nsession:207567f3-cce7-4a0a-930b-46fc394dd53d\n\n0123456789\x00' m2 = b'SUBSCRIBE\nack:auto\ndestination:/queue/test\n\n\x00SEND\ndestination:/queue/test\n\n\x00' sb = FrameBuffer() sb.append(m1) f1 = sb.extract_frame() self.assertEqual(f1.cmd, frames.CONNECT) self.assertEqual(f1.body, b'0123456789') f = sb.extract_frame() self.assertIsNone(f) sb.append(m2) f2 = sb.extract_frame() f3 = sb.extract_frame() self.assertEqual(f2.cmd, frames.SUBSCRIBE) self.assertEqual(f2.body, '') self.assertEqual(f3.cmd, frames.SEND) self.assertEqual(f3.headers.get('destination'), '/queue/test') self.assertEqual(f3.body, '') self.assertIsNone(sb.extract_frame())
def test_extract_frame(self): """ Test extracting a single frame. """ sb = FrameBuffer() m1 = self.createMessage( 'connect', {'session': uuid.uuid4()}, 'This is the body') sb.append(m1) msg = sb.extract_frame() self.assertIsInstance(msg, Frame) self.assertEqual(m1, msg.pack())
def test_extract_frame_binary(self): """ Test extracting a binary frame. """ sb = FrameBuffer() binmsg = "\x00\x00HELLO\x00\x00DONKEY\x00\x00" m1 = self.createMessage('send', OrderedDict({'content-length': len(binmsg), 'x-other-header': 'value'}), binmsg ) sb.append(m1) msg = sb.extract_frame() self.assertIsInstance(msg, Frame) self.assertEqual(msg.pack(), m1)
def setup(self): if self.server.timeout is not None: self.request.settimeout(self.server.timeout) self.debug = False self.log = logging.getLogger( '%s.%s' % (self.__module__, self.__class__.__name__)) self.buffer = FrameBuffer() self.engine = StompEngine(connection=self, authenticator=self.server.authenticator, queue_manager=self.server.queue_manager, topic_manager=self.server.topic_manager, protocol=self.server.protocol)
def __init__(self, addr, connect=True): """ @param addr: The (host,port) tuple for connection. @type addr: C{tuple} @param connect: Whether to connect socket to specified addr. @type connect: C{bool} """ self.log = logging.getLogger( '%s.%s' % (self.__module__, self.__class__.__name__)) self.sock = None self.addr = addr self.received_frames = Queue() self.read_stopped = threading.Event() self.buffer = FrameBuffer() if connect: self._connect()
def test_iteration(self): """ Test the iteration feature of our buffer.""" sb = FrameBuffer() m1 = self.createMessage( frames.CONNECT, {'session': uuid.uuid4()}, b'This is the body') m2 = self.createMessage( frames.SEND, {'destination': '/queue/sample'}, b'This is the body-2') sb.append(m1) sb.append(m2) self.assertIs(sb, iter(sb)) idx = 0 expected = (m1, m2) for frame in sb: self.assertIsInstance(frame, Frame) self.assertEqual(expected[idx], frame.pack()) idx += 1 self.assertEqual(idx, 2)
def setup(self): if self.server.timeout is not None: self.request.settimeout(self.server.timeout) self.debug = False self.log = logging.getLogger('%s.%s' % (self.__module__, self.__class__.__name__)) self.buffer = FrameBuffer() self.engine = StompEngine(connection=self, authenticator=self.server.authenticator, queue_manager=self.server.queue_manager, topic_manager=self.server.topic_manager, protocol=self.server.protocol)
def __init__(self, addr, connect=True): """ @param addr: The (host,port) tuple for connection. @type addr: C{tuple} @param connect: Whether to connect socket to specified addr. @type connect: C{bool} """ self.log = logging.getLogger('%s.%s' % ( self.__module__, self.__class__.__name__)) self.sock = None self.addr = addr self.received_frames = Queue() self.read_stopped = threading.Event() self.buffer = FrameBuffer() if connect: self._connect()
class TestStompClient(object): """ A stomp client for use in testing. This client spawns a listener thread and pushes anything that comes in onto the read_frames queue. @ivar received_frames: A queue of Frame instances that have been received. @type received_frames: C{Queue.Queue} containing any received C{stompclient.frame.Frame} """ def __init__(self, addr, connect=True): """ @param addr: The (host,port) tuple for connection. @type addr: C{tuple} @param connect: Whether to connect socket to specified addr. @type connect: C{bool} """ self.log = logging.getLogger( '%s.%s' % (self.__module__, self.__class__.__name__)) self.sock = None self.addr = addr self.received_frames = Queue() self.read_stopped = threading.Event() self.buffer = FrameBuffer() if connect: self._connect() def connect(self, headers=None): self.send_frame(Frame(frames.CONNECT, headers=headers)) def send(self, destination, message, set_content_length=True, extra_headers=None): headers = extra_headers or {} headers['destination'] = destination if set_content_length: headers['content-length'] = len(message) self.send_frame(Frame('send', headers=headers, body=message)) def subscribe(self, destination): self.send_frame( Frame('subscribe', headers={'destination': destination})) def send_frame(self, frame): """ Sends a stomp frame. @param frame: The stomp frame to send. @type frame: L{stompclient.frame.Frame} """ if not self.connected: raise RuntimeError("Not connected") self.sock.send(frame.pack()) def _connect(self): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect(self.addr) self.connected = True self.read_stopped.clear() t = threading.Thread(target=self._read_loop, name="client-receiver-%s" % hex(id(self))) t.start() def _read_loop(self): while self.connected: r, w, e = select.select([self.sock], [], [], 0.1) if r: data = self.sock.recv(1024) self.buffer.append(data) for frame in self.buffer: self.log.debug("Processing frame: %s" % frame) self.received_frames.put(frame) self.read_stopped.set() # print "Read loop has been quit! for %s" % id(self) def disconnect(self): self.send_frame(Frame('disconnect')) def close(self): if not self.connected: raise RuntimeError("Not connected") self.connected = False self.read_stopped.wait(timeout=0.5) self.sock.close()
class StompRequestHandler(BaseRequestHandler, StompConnection): """ Class that will be instantiated to handle STOMP connections. This class will be instantiated once per connection to the server. In a multi-threaded context, that means that instances of this class are scoped to a single thread. It should be noted that while the L{coilmq.engine.StompEngine} instance will be thread-local, the storage containers configured into the engine are not thread-local (and hence must be thread-safe). @ivar buffer: A StompBuffer instance which buffers received data (to ensure we deal with complete STOMP messages. @type buffer: C{stompclient.util.FrameBuffer} @ivar engine: The STOMP protocol engine. @type engine: L{coilmq.engine.StompEngine} @ivar debug: Whether to enable extra-verbose debug logging. (Will be logged at debug level.) @type debug: C{bool} """ def setup(self): if self.server.timeout is not None: self.request.settimeout(self.server.timeout) self.debug = False self.log = logging.getLogger( '%s.%s' % (self.__module__, self.__class__.__name__)) self.buffer = FrameBuffer() self.engine = StompEngine(connection=self, authenticator=self.server.authenticator, queue_manager=self.server.queue_manager, topic_manager=self.server.topic_manager, protocol=self.server.protocol) def handle(self): """ Handle a new socket connection. """ # self.request is the TCP socket connected to the client try: while not self.server._shutdown_request_event.is_set(): try: data = self.request.recv(8192) if not data: break if self.debug: self.log.debug("RECV: %r" % data) self.buffer.append(data) for frame in self.buffer: self.server.frames_queue.put(frame) self.log.debug("Processing frame: %s" % frame) self.engine.process_frame(frame) if not self.engine.connected: raise ClientDisconnected() except socket.timeout: # pragma: no cover pass except ClientDisconnected: self.log.debug("Client disconnected, discontinuing read loop.") except Exception as e: # pragma: no cover self.log.error("Error receiving data (unbinding): %s" % e) self.engine.unbind() raise def finish(self): """ Normal (non-error) termination of request. Unbinds the engine. @see: L{coilmq.engine.StompEngine.unbind} """ self.engine.unbind() def send_frame(self, frame): """ Sends a frame to connected socket client. @param frame: The frame to send. @type frame: C{stompclient.frame.Frame} """ packed = frame.pack() if self.debug: # pragma: no cover self.log.debug("SEND: %r" % packed) self.request.sendall(packed)
class TestStompClient(object): """ A stomp client for use in testing. This client spawns a listener thread and pushes anything that comes in onto the read_frames queue. @ivar received_frames: A queue of Frame instances that have been received. @type received_frames: C{Queue.Queue} containing any received C{stompclient.frame.Frame} """ def __init__(self, addr, connect=True): """ @param addr: The (host,port) tuple for connection. @type addr: C{tuple} @param connect: Whether to connect socket to specified addr. @type connect: C{bool} """ self.log = logging.getLogger('%s.%s' % ( self.__module__, self.__class__.__name__)) self.sock = None self.addr = addr self.received_frames = Queue() self.read_stopped = threading.Event() self.buffer = FrameBuffer() if connect: self._connect() def connect(self, headers=None): self.send_frame(Frame(frames.CONNECT, headers=headers)) def send(self, destination, message, set_content_length=True, extra_headers=None): headers = extra_headers or {} headers['destination'] = destination if set_content_length: headers['content-length'] = len(message) self.send_frame(Frame('send', headers=headers, body=message)) def subscribe(self, destination): self.send_frame(Frame('subscribe', headers={ 'destination': destination})) def send_frame(self, frame): """ Sends a stomp frame. @param frame: The stomp frame to send. @type frame: L{stompclient.frame.Frame} """ if not self.connected: raise RuntimeError("Not connected") self.sock.send(frame.pack()) def _connect(self): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect(self.addr) self.connected = True self.read_stopped.clear() t = threading.Thread(target=self._read_loop, name="client-receiver-%s" % hex(id(self))) t.start() def _read_loop(self): while self.connected: r, w, e = select.select([self.sock], [], [], 0.1) if r: data = self.sock.recv(1024) self.buffer.append(data) for frame in self.buffer: self.log.debug("Processing frame: %s" % frame) self.received_frames.put(frame) self.read_stopped.set() # print "Read loop has been quit! for %s" % id(self) def disconnect(self): self.send_frame(Frame('disconnect')) def close(self): if not self.connected: raise RuntimeError("Not connected") self.connected = False self.read_stopped.wait(timeout=0.5) self.sock.close()
class StompRequestHandler(BaseRequestHandler, StompConnection): """ Class that will be instantiated to handle STOMP connections. This class will be instantiated once per connection to the server. In a multi-threaded context, that means that instances of this class are scoped to a single thread. It should be noted that while the L{coilmq.engine.StompEngine} instance will be thread-local, the storage containers configured into the engine are not thread-local (and hence must be thread-safe). @ivar buffer: A StompBuffer instance which buffers received data (to ensure we deal with complete STOMP messages. @type buffer: C{stompclient.util.FrameBuffer} @ivar engine: The STOMP protocol engine. @type engine: L{coilmq.engine.StompEngine} @ivar debug: Whether to enable extra-verbose debug logging. (Will be logged at debug level.) @type debug: C{bool} """ def setup(self): if self.server.timeout is not None: self.request.settimeout(self.server.timeout) self.debug = False self.log = logging.getLogger('%s.%s' % (self.__module__, self.__class__.__name__)) self.buffer = FrameBuffer() self.engine = StompEngine(connection=self, authenticator=self.server.authenticator, queue_manager=self.server.queue_manager, topic_manager=self.server.topic_manager, protocol=self.server.protocol) def handle(self): """ Handle a new socket connection. """ # self.request is the TCP socket connected to the client try: while not self.server._shutdown_request_event.is_set(): try: data = self.request.recv(8192) if not data: break if self.debug: self.log.debug("RECV: %r" % data) self.buffer.append(data) for frame in self.buffer: self.log.debug("Processing frame: %s" % frame) self.engine.process_frame(frame) if not self.engine.connected: raise ClientDisconnected() except socket.timeout: # pragma: no cover pass except ClientDisconnected: self.log.debug("Client disconnected, discontinuing read loop.") except Exception as e: # pragma: no cover self.log.error("Error receiving data (unbinding): %s" % e) self.engine.unbind() raise def finish(self): """ Normal (non-error) termination of request. Unbinds the engine. @see: L{coilmq.engine.StompEngine.unbind} """ self.engine.unbind() def send_frame(self, frame): """ Sends a frame to connected socket client. @param frame: The frame to send. @type frame: C{stompclient.frame.Frame} """ packed = frame.pack() if self.debug: # pragma: no cover self.log.debug("SEND: %r" % packed) self.request.sendall(packed)