def start_wamp_session(url, session_factory, loop, serializer=None): parsed_url = urlparse(url) transport_factory = None if parsed_url.scheme == 'tcp': is_unix = False if not parsed_url.hostname or not parsed_url.port: raise ValueError('Host and port is required in URL') transport_factory = WampRawSocketClientFactory(session_factory, serializer=serializer) elif parsed_url.scheme == 'unix' or parsed_url.scheme == '': is_unix = True if not parsed_url.path: raise ValueError('Path to unix socket must be in URL') transport_factory = WampRawSocketClientFactory(session_factory, serializer=serializer) else: raise ValueError('Invalid URL scheme') if is_unix: coro = loop.create_unix_connection(transport_factory, parsed_url.path) else: coro = loop.create_connection(transport_factory, parsed_url.hostname, parsed_url.port) return coro
def _create_transport_factory(loop, transport, session_factory): """ Create a WAMP-over-XXX transport factory. """ if transport.type == u'websocket': serializers = _create_transport_serializers(transport) factory = WampWebSocketClientFactory(session_factory, url=transport.url, serializers=serializers) elif transport.type == u'rawsocket': serializer = _create_transport_serializer(transport.serializers[0]) factory = WampRawSocketClientFactory(session_factory, serializer=serializer) else: assert (False), 'should not arrive here' # set the options one at a time so we can give user better feedback for k, v in transport.options.items(): try: factory.setProtocolOptions(**{k: v}) except (TypeError, KeyError): # this allows us to document options as snake_case # until everything internally is upgraded from # camelCase try: factory.setProtocolOptions( **{_camel_case_from_snake_case(k): v}) except (TypeError, KeyError): raise ValueError("Unknown {} transport option: {}={}".format( transport.type, k, v)) return factory
def _test_wamp_client(event_loop): transport = Mock(spec_set=('abort', 'close', 'write', 'get_extra_info')) transport.write = Mock(side_effect=lambda m: messages.append(m)) client = Mock(spec=['onOpen', 'onMessage']) def fact_client(): return client messages = [] proto = WampRawSocketClientFactory(fact_client)() proto.connection_made(transport) assert proto._serializer s = proto._serializer.RAWSOCKET_SERIALIZER_ID proto.data_received(bytes(bytearray([0x7F, 0xF0 | s, 0, 0]))) client.onOpen.assert_called_once_with(proto) proto.sendMessage(message.Abort('close')) for d in messages[1:]: proto.data_received(d) assert client.onMessage.called assert isinstance(client.onMessage.call_args[0][0], message.Abort)
def run(self, make, start_loop=True, log_level='info'): """ Run the application component. Under the hood, this runs the event loop (unless `start_loop=False` is passed) so won't return until the program is done. :param make: A factory that produces instances of :class:`autobahn.asyncio.wamp.ApplicationSession` when called with an instance of :class:`autobahn.wamp.types.ComponentConfig`. :type make: callable :param start_loop: When ``True`` (the default) this method start a new asyncio loop. :type start_loop: bool :returns: None is returned, unless you specify `start_loop=False` in which case the coroutine from calling `loop.create_connection()` is returned. This will yield the (transport, protocol) pair. """ if callable(make): def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception as e: self.log.error( 'ApplicationSession could not be instantiated: {}'. format(e)) loop = asyncio.get_event_loop() if loop.is_running(): loop.stop() raise else: return session else: create = make if self.url.startswith(u'rs'): # try to parse RawSocket URL .. isSecure, host, port = parse_rs_url(self.url) # use the first configured serializer if any (which means, auto-choose "best") serializer = self.serializers[0] if self.serializers else None # create a WAMP-over-RawSocket transport client factory transport_factory = WampRawSocketClientFactory( create, serializer=serializer) else: # try to parse WebSocket URL .. isSecure, host, port, resource, path, params = parse_ws_url( self.url) # create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory( create, url=self.url, serializers=self.serializers, proxy=self.proxy, headers=self.headers) # client WebSocket settings - similar to: # - http://crossbar.io/docs/WebSocket-Compression/#production-settings # - http://crossbar.io/docs/WebSocket-Options/#production-settings # The permessage-deflate extensions offered to the server .. offers = [PerMessageDeflateOffer()] # Function to accept permessage_delate responses from the server .. def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response) # set WebSocket options for all client connections transport_factory.setProtocolOptions( maxFramePayloadSize=1048576, maxMessagePayloadSize=1048576, autoFragmentSize=65536, failByDrop=False, openHandshakeTimeout=2.5, closeHandshakeTimeout=1., tcpNoDelay=True, autoPingInterval=10., autoPingTimeout=5., autoPingSize=4, perMessageCompressionOffers=offers, perMessageCompressionAccept=accept) # SSL context for client connection if self.ssl is None: ssl = isSecure else: if self.ssl and not isSecure: raise RuntimeError( 'ssl argument value passed to %s conflicts with the "ws:" ' 'prefix of the url argument. Did you mean to use "wss:"?' % self.__class__.__name__) ssl = self.ssl # start the client connection loop = asyncio.get_event_loop() txaio.use_asyncio() txaio.config.loop = loop coro = loop.create_connection(transport_factory, host, port, ssl=ssl) # start a asyncio loop if not start_loop: return coro else: (transport, protocol) = loop.run_until_complete(coro) # start logging txaio.start_logging(level=log_level) try: loop.add_signal_handler(signal.SIGTERM, loop.stop) except NotImplementedError: # signals are not available on Windows pass # 4) now enter the asyncio event loop try: loop.run_forever() except KeyboardInterrupt: # wait until we send Goodbye if user hit ctrl-c # (done outside this except so SIGTERM gets the same handling) pass # give Goodbye message a chance to go through, if we still # have an active session if protocol._session: loop.run_until_complete(protocol._session.leave()) loop.close()
elif args.transport in ['rawsocket-json', 'rawsocket-msgpack']: ## create a WAMP-over-RawSocket transport client factory ## if args.transport == 'rawsocket-msgpack': from autobahn.wamp.serializer import MsgPackSerializer serializer = MsgPackSerializer() elif args.transport == 'rawsocket-json': from autobahn.wamp.serializer import JsonSerializer serializer = JsonSerializer() else: raise Exception("should not arrive here") from autobahn.asyncio.rawsocket import WampRawSocketClientFactory transport_factory = WampRawSocketClientFactory(session_factory, serializer, debug=args.debug) else: raise Exception("logic error") ## start the client loop = asyncio.get_event_loop() coro = loop.create_connection(transport_factory, args.host, args.port) loop.run_until_complete(coro) ## now enter the asyncio event loop loop.run_forever() loop.close()
def run(self, make, start_loop=True, log_level='info'): """ Run the application component. Under the hood, this runs the event loop (unless `start_loop=False` is passed) so won't return until the program is done. :param make: A factory that produces instances of :class:`autobahn.asyncio.wamp.ApplicationSession` when called with an instance of :class:`autobahn.wamp.types.ComponentConfig`. :type make: callable :param start_loop: When ``True`` (the default) this method start a new asyncio loop. :type start_loop: bool :returns: None is returned, unless you specify `start_loop=False` in which case the coroutine from calling `loop.create_connection()` is returned. This will yield the (transport, protocol) pair. """ if callable(make): def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception as e: self.log.error('ApplicationSession could not be instantiated: {}'.format(e)) loop = asyncio.get_event_loop() if loop.is_running(): loop.stop() raise else: return session else: create = make if self.url.startswith(u'rs'): # try to parse RawSocket URL .. isSecure, host, port = parse_rs_url(self.url) # use the first configured serializer if any (which means, auto-choose "best") serializer = self.serializers[0] if self.serializers else None # create a WAMP-over-RawSocket transport client factory transport_factory = WampRawSocketClientFactory(create, serializer=serializer) else: # try to parse WebSocket URL .. isSecure, host, port, resource, path, params = parse_ws_url(self.url) # create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory(create, url=self.url, serializers=self.serializers, proxy=self.proxy, headers=self.headers) # client WebSocket settings - similar to: # - http://crossbar.io/docs/WebSocket-Compression/#production-settings # - http://crossbar.io/docs/WebSocket-Options/#production-settings # The permessage-deflate extensions offered to the server .. offers = [PerMessageDeflateOffer()] # Function to accept permessage_delate responses from the server .. def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response) # set WebSocket options for all client connections transport_factory.setProtocolOptions(maxFramePayloadSize=1048576, maxMessagePayloadSize=1048576, autoFragmentSize=65536, failByDrop=False, openHandshakeTimeout=2.5, closeHandshakeTimeout=1., tcpNoDelay=True, autoPingInterval=10., autoPingTimeout=5., autoPingSize=4, perMessageCompressionOffers=offers, perMessageCompressionAccept=accept) # SSL context for client connection if self.ssl is None: ssl = isSecure else: if self.ssl and not isSecure: raise RuntimeError( 'ssl argument value passed to %s conflicts with the "ws:" ' 'prefix of the url argument. Did you mean to use "wss:"?' % self.__class__.__name__) ssl = self.ssl # start the client connection loop = asyncio.get_event_loop() if loop.is_closed() and start_loop: asyncio.set_event_loop(asyncio.new_event_loop()) loop = asyncio.get_event_loop() txaio.use_asyncio() txaio.config.loop = loop coro = loop.create_connection(transport_factory, host, port, ssl=ssl) # start a asyncio loop if not start_loop: return coro else: (transport, protocol) = loop.run_until_complete(coro) # start logging txaio.start_logging(level=log_level) try: loop.add_signal_handler(signal.SIGTERM, loop.stop) except NotImplementedError: # signals are not available on Windows pass # 4) now enter the asyncio event loop try: loop.run_forever() except KeyboardInterrupt: # wait until we send Goodbye if user hit ctrl-c # (done outside this except so SIGTERM gets the same handling) pass # give Goodbye message a chance to go through, if we still # have an active session if protocol._session: loop.run_until_complete(protocol._session.leave()) loop.close()
def test_wamp(self): transport = Mock(spec_set=('abort', 'close', 'write', 'get_extra_info')) transport.write = Mock(side_effect=lambda m: messages.append(m)) client = Mock(spec=['onOpen', 'onMessage']) def fact(): return client messages = [] proto = WampRawSocketClientFactory(fact)() proto.connection_made(transport) self.assertTrue(proto._serializer) s = proto._serializer.RAWSOCKET_SERIALIZER_ID proto.data_received(bytes(bytearray([0x7F, 0xF0 | s, 0, 0]))) client.onOpen.assert_called_once_with(proto) proto.send(message.Abort(u'close')) for d in messages[1:]: proto.data_received(d) self.assertTrue(client.onMessage.called) self.assertTrue( isinstance(client.onMessage.call_args[0][0], message.Abort)) # server transport = Mock(spec_set=('abort', 'close', 'write', 'get_extra_info')) transport.write = Mock(side_effect=lambda m: messages.append(m)) client = None server = Mock(spec=['onOpen', 'onMessage']) def fact_server(): return server messages = [] proto = WampRawSocketServerFactory(fact_server)() proto.connection_made(transport) self.assertTrue(proto.factory._serializers) s = proto.factory._serializers[1].RAWSOCKET_SERIALIZER_ID proto.data_received(bytes(bytearray([0x7F, 0xF0 | s, 0, 0]))) self.assertTrue(proto._serializer) server.onOpen.assert_called_once_with(proto) proto.send(message.Abort(u'close')) for d in messages[1:]: proto.data_received(d) self.assertTrue(server.onMessage.called) self.assertTrue( isinstance(server.onMessage.call_args[0][0], message.Abort))
def run(self, make, logging_level='info'): """ Run the application component. :param make: A factory that produces instances of :class:`autobahn.asyncio.wamp.ApplicationSession` when called with an instance of :class:`autobahn.wamp.types.ComponentConfig`. :type make: callable """ def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception: self.log.failure("App session could not be created! ") asyncio.get_event_loop().stop() else: return session parsed_url = urlparse(self.url) if parsed_url.scheme == 'tcp': is_unix = False if not parsed_url.hostname or not parsed_url.port: raise ValueError('Host and port is required in URL') elif parsed_url.scheme == 'unix' or parsed_url.scheme == '': is_unix = True if not parsed_url.path: raise ValueError('Path to unix socket must be in URL') transport_factory = WampRawSocketClientFactory( create, serializer=self.serializer) loop = asyncio.get_event_loop() if logging_level == 'debug': loop.set_debug(True) txaio.use_asyncio() txaio.config.loop = loop try: loop.add_signal_handler(signal.SIGTERM, loop.stop) except NotImplementedError: # signals are not available on Windows pass def handle_error(loop, context): self.log.error('Application Error: {err}', err=context) loop.stop() loop.set_exception_handler(handle_error) if is_unix: coro = loop.create_unix_connection(transport_factory, parsed_url.path) else: coro = loop.create_connection(transport_factory, parsed_url.hostname, parsed_url.port) (_transport, protocol) = loop.run_until_complete(coro) txaio.start_logging(level=logging_level) # @UndefinedVariable try: loop.run_forever() except KeyboardInterrupt: pass self.log.debug('Left main loop waiting for completion') # give Goodbye message a chance to go through, if we still # have an active session # it's not working now - because protocol is_closed must return Future if protocol._session: loop.run_until_complete(protocol._session.leave()) loop.close()
def test_wamp(self): transport = Mock(spec_set=('abort', 'close', 'write', 'get_extra_info')) transport.write = Mock(side_effect=lambda m: messages.append(m)) client = Mock(spec=['onOpen', 'onMessage']) def fact(): return client messages = [] proto = WampRawSocketClientFactory(fact)() proto.connection_made(transport) self.assertTrue(proto._serializer) s = proto._serializer.RAWSOCKET_SERIALIZER_ID proto.data_received(bytes(bytearray([0x7F, 0xF0 | s, 0, 0]))) client.onOpen.assert_called_once_with(proto) proto.send(message.Abort(u'close')) for d in messages[1:]: proto.data_received(d) self.assertTrue(client.onMessage.called) self.assertTrue(isinstance(client.onMessage.call_args[0][0], message.Abort)) # server transport = Mock(spec_set=('abort', 'close', 'write', 'get_extra_info')) transport.write = Mock(side_effect=lambda m: messages.append(m)) client = None server = Mock(spec=['onOpen', 'onMessage']) def fact_server(): return server messages = [] proto = WampRawSocketServerFactory(fact_server)() proto.connection_made(transport) self.assertTrue(proto.factory._serializers) s = proto.factory._serializers[1].RAWSOCKET_SERIALIZER_ID proto.data_received(bytes(bytearray([0x7F, 0xF0 | s, 0, 0]))) self.assertTrue(proto._serializer) server.onOpen.assert_called_once_with(proto) proto.send(message.Abort(u'close')) for d in messages[1:]: proto.data_received(d) self.assertTrue(server.onMessage.called) self.assertTrue(isinstance(server.onMessage.call_args[0][0], message.Abort))