def check_url(config, section): if 'url' in config: url = config['url'] if type(url) != six.text_type: raise TypeError("'url' in {} configuration must be str, " "but got {}".format(section, type(url).__name__)) try: parseWsUrl(url) except Exception as e: raise ValueError("Invalid 'url' in {} configuration: {}".format( section, e)) else: raise ValueError("'url' required in {} configuration" .format(section))
def setupService(self): """ Setup the application component. """ isSecure, host, port, resource, path, params = parseWsUrl(self.url) # factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) session = self.make(cfg) session.debug_app = self.debug_app return session # create a WAMP-over-WebSocket transport client factory transport_factory = self.factory(create, url=self.url, debug=self.debug, debug_wamp=self.debug_wamp) # setup the client from a Twisted endpoint if isSecure: from twisted.application.internet import SSLClient clientClass = SSLClient else: from twisted.application.internet import TCPClient clientClass = TCPClient client = clientClass(host, port, transport_factory) client.setServiceParent(self)
def getMapUpdaterComponentService(self, url, realm, mapUpdater): def create(config): try: session = MapUpdaterComponent(mapUpdater, config) except Exception as e: # the app component could not be created .. fatal print(e) else: session.debug_app = True return session sessionFactory = ApplicationSessionFactory( ComponentConfig(realm, None)) sessionFactory.session = create transportFactory = WampWebSocketClientFactory( sessionFactory, url=url) transportFactory.noisy = False transportFactory.autoPingInterval = 30 transportFactory.autoPingTimeout = 30 isSecure, host, port, resource, path, params = parseWsUrl(url) endpoint = HostnameEndpoint(reactor, host.encode('utf8'), port) if isSecure: contextFactory = optionsForClientTLS(hostname=host) endpoint = wrapClientTLS(contextFactory, endpoint) return ClientService(endpoint, transportFactory)
def start(self, url, loop=None, debug=False, debug_wamp=False): """ Starts a WAMP session based on the arguments above. """ logging.info('wamp_session.start') if loop is None: loop = asyncio.get_event_loop() self.loop = loop isSecure, host, port, resource, path, params = parseWsUrl(url) transport_factory = WampWebSocketClientFactory( lambda: self, url=url, serializers=None, debug=debug, debug_wamp=debug_wamp) connection = loop.create_connection( transport_factory, host, port, ssl=isSecure) asyncio.async(connection) logging.info('start_wamp_session finished.') return loop
def register(self): def create(): cfg = ComponentConfig( self._realm, extra={"dts": self._dts, "loop": self._loop, "log": self._log} ) # Set the asyncio loop for txaio txaio.config.loop = self._loop self._app = WampDtsMockApplication(cfg) self._app.debug_app = True return self._app isSecure, host, port, resource, path, params = parseWsUrl(self._url) transport_factory = WampWebSocketClientFactory( create, url=self._url, serializers=None, debug=True, debug_wamp=True, ) while True: try: create_conn = self._loop.create_connection(transport_factory, host, port) (transport, protocol) = yield from create_conn self._log.debug("Connected to crossbar.io") break except ConnectionRefusedError: self._log.error("ConnectionRefusedError: sleeping for a second and retrying") yield from asyncio.sleep(1, self._loop)
def setupService(self): """ Setup the application component. """ is_secure, host, port, resource, path, params = parseWsUrl(self.url) # factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) session = self.make(cfg) session.debug_app = self.debug_app return session # create a WAMP-over-WebSocket transport client factory transport_factory = self.factory(create, url=self.url, debug=self.debug) # setup the client from a Twisted endpoint if is_secure: from twisted.application.internet import SSLClient ctx = self.context_factory if ctx is None: from twisted.internet.ssl import optionsForClientTLS ctx = optionsForClientTLS(host) client = SSLClient(host, port, transport_factory, contextFactory=ctx) else: if self.context_factory is not None: raise Exception("context_factory specified on non-secure URI") from twisted.application.internet import TCPClient client = TCPClient(host, port, transport_factory) client.setServiceParent(self)
def check_transport_websocket(transport): for k in transport: if k not in ['type', 'endpoint', 'url', 'debug', 'options']: raise Exception("encountered unknown attribute '{}' in WebSocket transport configuration".format(k)) if not 'endpoint' in transport: raise Exception("missing mandatory attribute 'endpoint' in WebSocket transport item\n\n{}".format(pformat(transport))) check_endpoint_listen(transport['endpoint']) if 'options' in transport: check_websocket_options(transport[options]) if 'debug' in transport: debug = transport['debug'] if type(debug) != bool: raise Exception("'debug' in WebSocket transport configuration must be boolean ({} encountered)".format(type(debug))) if 'url' in transport: url = transport['url'] if type(url) not in [str, unicode]: raise Exception("'url' in WebSocket transport configuration must be str ({} encountered)".format(type(url))) try: u = parseWsUrl(url) except Exception as e: raise Exception("invalid 'url' in WebSocket transport configuration : {}".format(e))
def run(self, make): """ 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 """ ## 1) factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception as e: ## the app component could not be created .. fatal print(e) asyncio.get_event_loop().stop() else: session.debug_app = self.debug_app return session isSecure, host, port, resource, path, params = parseWsUrl(self.url) ## 2) create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory(create, url = self.url, debug = self.debug, debug_wamp = self.debug_wamp) ## 3) start the client loop = asyncio.get_event_loop() coro = loop.create_connection(transport_factory, host, port) loop.run_until_complete(coro) ## 4) now enter the asyncio event loop loop.run_forever() loop.close()
def __init__(self, url, username="", password="", proto=GrapheneWebsocketProtocol): """ Open A GrapheneWebsocket connection that can handle notifications though asynchronous calls. :param str url: Url to the websocket server :param str username: Username for login :param str password: Password for login :param GrapheneWebsocketProtocol proto: (optional) Protocol that inherits ``GrapheneWebsocketProtocol`` """ ssl, host, port, resource, path, params = parseWsUrl(url) self.url = url self.username = username self.password = password # Open another RPC connection to execute calls GrapheneWebsocketRPC.__init__(self, url, username, password) # Parameters for another connection for asynchronous notifications self.ssl = ssl self.host = host self.port = port self.proto = proto self.proto.username = username self.proto.password = password self.objectMap = LimitedSizeDict() self.proto.objectMap = self.objectMap # this is a reference self.factory = None
def run(self, make, start_reactor = True): """ 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 """ from twisted.internet import reactor isSecure, host, port, resource, path, params = parseWsUrl(self.url) ## start logging to console if self.debug or self.debug_wamp or self.debug_app: log.startLogging(sys.stdout) ## run an embedded router if ask to start standalone if self.standalone: from autobahn.wamp.router import RouterFactory from autobahn.twisted.websocket import WampWebSocketServerFactory from twisted.internet.endpoints import serverFromString router_factory = RouterFactory() session_factory = RouterSessionFactory(router_factory) transport_factory = WampWebSocketServerFactory(session_factory, debug = self.debug, debug_wamp = self.debug_wamp) transport_factory.setProtocolOptions(failByDrop = False) server = serverFromString(reactor, "tcp:{}".format(port)) server.listen(transport_factory) ## factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception: ## the app component could not be created .. fatal log.err() reactor.stop() else: session.debug_app = self.debug_app return session ## create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory(create, url = self.url, debug = self.debug, debug_wamp = self.debug_wamp) ## start the client from a Twisted endpoint from twisted.internet.endpoints import clientFromString client = clientFromString(reactor, "tcp:{}:{}".format(host, port)) client.connect(transport_factory) ## now enter the Twisted reactor loop if start_reactor: reactor.run()
def run(self, make): """ 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 """ # 1) factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception as e: # the app component could not be created .. fatal print(e) asyncio.get_event_loop().stop() else: session.debug_app = self.debug_app return session isSecure, host, port, resource, path, params = parseWsUrl(self.url) 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 # 2) create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory(create, url=self.url, serializers=self.serializers, debug=self.debug, debug_wamp=self.debug_wamp) # 3) start the client loop = asyncio.get_event_loop() txaio.use_asyncio() txaio.config.loop = loop coro = loop.create_connection(transport_factory, host, port, ssl=ssl) (transport, protocol) = loop.run_until_complete(coro) loop.add_signal_handler(signal.SIGTERM, loop.stop) # 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 connect_ws(self, data): from autobahn.websocket.protocol import parseWsUrl (isSecure, host, port, resource, path, params) = parseWsUrl( data['url']) endpoint = SSL4ClientEndpoint( self.clock, host, port, ssl.ClientContextFactory()) return endpoint.connect( RelayFactory(self, data, debug=self.debug))
def __init__(self, url, realm, extra=None, serializers=None, debug_app=False, ssl=None, loop=None, retry_strategy=BackoffStrategy(), auto_ping_interval=10, auto_ping_timeout=27): """ :param url: The WebSocket URL of the WAMP router to connect to (e.g. `ws://somehost.com:8090/somepath`) :type url: unicode :param realm: The WAMP realm to join the application session to. :type realm: unicode :param extra: Optional extra configuration to forward to the application component. :type extra: dict :param serializers: A list of WAMP serializers to use (or None for default serializers). Serializers must implement :class:`autobahn.wamp.interfaces.ISerializer`. :type serializers: list :param debug_app: Turn on app-level debugging. :type debug_app: bool :param ssl: An (optional) SSL context instance or a bool. See the documentation for the `loop.create_connection` asyncio method, to which this value is passed as the ``ssl=`` kwarg. :type ssl: :class:`ssl.SSLContext` or bool :param auto_ping_interval: How often to send a keep-alive ping to the router (in seconds). A value of None turns off pings. :type auto_ping_interval: int :param auto_ping_timeout: Consider the connection dropped if the router does not respond to our ping for more than X seconds. :type auto_ping_timeout: int """ self._url = url self._realm = realm self._extra = extra or dict() self._debug_app = debug_app self._serializers = serializers self._loop = loop or asyncio.get_event_loop() self._retry_strategy = retry_strategy self._closing = False self._auto_ping_interval = auto_ping_interval self._auto_ping_timeout = auto_ping_timeout self._isSecure, self._host, self._port, _, _, _ = parseWsUrl(url) if ssl is None: self._ssl = self._isSecure else: if ssl and not self._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__) self._ssl = ssl
def __init__(self, url, username, password, proto=GrapheneWebsocketProtocol): ssl, host, port, resource, path, params = parseWsUrl(url) GrapheneWebsocketRPC.__init__(self, url, username, password) self.url = url self.username = username self.password = password self.ssl = ssl self.host = host self.port = port self.proto = proto self.proto.username = username self.proto.password = password self.objectMap = LimitedSizeDict() self.proto.objectMap = self.objectMap # this is a reference self.factory = None
def run(self, make, start_reactor = True): """ 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 """ from twisted.internet import reactor isSecure, host, port, resource, path, params = parseWsUrl(self.url) ## start logging to console if self.debug or self.debug_wamp or self.debug_app: log.startLogging(sys.stdout) ## factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception: ## the app component could not be created .. fatal log.err() reactor.stop() else: session.debug_app = self.debug_app return session ## create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory(create, url = self.url, debug = self.debug, debug_wamp = self.debug_wamp) ## start the client from a Twisted endpoint from twisted.internet.endpoints import clientFromString if isSecure: endpoint_descriptor = "ssl:{0}:{1}".format(host, port) else: endpoint_descriptor = "tcp:{0}:{1}".format(host, port) client = clientFromString(reactor, endpoint_descriptor) client.connect(transport_factory) ## now enter the Twisted reactor loop if start_reactor: reactor.run()
def run(self, make): """ 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 """ # 1) factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception as e: # the app component could not be created .. fatal print(e) asyncio.get_event_loop().stop() else: session.debug_app = self.debug_app return session isSecure, host, port, resource, path, params = parseWsUrl(self.url) 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 # 2) create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory(create, url=self.url, serializers=self.serializers, debug=self.debug, debug_wamp=self.debug_wamp) # 3) start the client loop = asyncio.get_event_loop() txaio.use_asyncio() txaio.config.loop = loop coro = loop.create_connection(transport_factory, host, port, ssl=ssl) loop.run_until_complete(coro) # 4) now enter the asyncio event loop loop.run_forever() loop.close()
def check_transport_web_path_service_websocket(config): if 'options' in config: check_websocket_options(config['options']) if 'debug' in config: debug = config['debug'] if type(debug) != bool: raise Exception("'debug' in WebSocket configuration must be boolean ({} encountered)".format(type(debug))) if 'url' in config: url = config['url'] if type(url) not in [str, unicode]: raise Exception("'url' in WebSocket configuration must be str ({} encountered)".format(type(url))) try: u = parseWsUrl(url) except Exception as e: raise Exception("invalid 'url' in WebSocket configuration : {}".format(e))
def check_connecting_transport_websocket(transport): """ Check a connecting WebSocket-WAMP transport configuration. :param transport: The configuration item to check. :type transport: dict """ for k in transport: if k not in ['id', 'type', 'endpoint', 'url', 'serializers', 'debug', 'options']: raise Exception("encountered unknown attribute '{}' in WebSocket transport configuration".format(k)) if 'id' in transport: check_id(transport['id']) if not 'endpoint' in transport: raise Exception("missing mandatory attribute 'endpoint' in WebSocket transport item\n\n{}".format(pformat(transport))) check_connecting_endpoint(transport['endpoint']) if 'options' in transport: check_websocket_options(transport['options']) if 'serializers' in transport: serializers = transport['serializers'] if type(serializers) != list: raise Exception("'serializers' in WebSocket transport configuration must be list ({} encountered)".format(type(serializers))) if 'debug' in transport: debug = transport['debug'] if type(debug) != bool: raise Exception("'debug' in WebSocket transport configuration must be boolean ({} encountered)".format(type(debug))) if not 'url' in transport: raise Exception("missing mandatory attribute 'url' in WebSocket transport item\n\n{}".format(pformat(transport))) url = transport['url'] if type(url) != six.text_type: raise Exception("'url' in WebSocket transport configuration must be str ({} encountered)".format(type(url))) try: u = parseWsUrl(url) except Exception as e: raise Exception("invalid 'url' in WebSocket transport configuration : {}".format(e))
def run(config_info, build_controller): config_push = config_info["push_server"] Component.init(config_push, build_controller) # 1) create a WAMP application session factory component_config = types.ComponentConfig(realm=config_push["realm"]) session_factory = wamp.ApplicationSessionFactory(config=component_config) session_factory.session = Component # 2) create a WAMP-over-WebSocket transport client factory url = config_push["url"] transport_factory = MyClientFactory(session_factory, url=url, debug=False) # 3) start the client from a Twisted endpoint isSecure, host, port, resource, path, params = parseWsUrl(url) transport_factory.host = host transport_factory.port = port websocket.connectWS(transport_factory) # 4) now enter the Twisted reactor loop reactor.run()
def check_web_path_service_websocket(config): """ Check a "websocket" path service on Web transport. :param config: The path service configuration. :type config: dict """ if 'options' in config: check_websocket_options(config['options']) if 'debug' in config: debug = config['debug'] if type(debug) != bool: raise Exception("'debug' in WebSocket configuration must be boolean ({} encountered)".format(type(debug))) if 'url' in config: url = config['url'] if type(url) != six.text_type: raise Exception("'url' in WebSocket configuration must be str ({} encountered)".format(type(url))) try: u = parseWsUrl(url) except Exception as e: raise Exception("invalid 'url' in WebSocket configuration : {}".format(e))
def run(self, make, start_reactor=True): """ 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 :param start_reactor: if True (the default) this method starts the Twisted reactor and doesn't return until the reactor stops. If there are any problems starting the reactor or connect()-ing, we stop the reactor and raise the exception back to the caller. :returns: None is returned, unless you specify ``start_reactor=False`` in which case the Deferred that connect() returns is returned; this will callback() with an IProtocol instance, which will actually be an instance of :class:`WampWebSocketClientProtocol` """ if start_reactor: # only select framework, set loop and start logging when we are asked # start the reactor - otherwise we are running in a program that likely # already tool care of all this. from twisted.internet import reactor txaio.use_twisted() txaio.config.loop = reactor if self.debug or self.debug_app: txaio.start_logging(level='debug') else: txaio.start_logging(level='info') isSecure, host, port, resource, path, params = parseWsUrl(self.url) # factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception as e: if start_reactor: # the app component could not be created .. fatal self.log.error(str(e)) reactor.stop() else: # if we didn't start the reactor, it's up to the # caller to deal with errors raise else: session.debug_app = self.debug_app return session # create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory(create, url=self.url, serializers=self.serializers, proxy=self.proxy, debug=self.debug) # supress pointless log noise like # "Starting factory <autobahn.twisted.websocket.WampWebSocketClientFactory object at 0x2b737b480e10>"" transport_factory.noisy = False # if user passed ssl= but isn't using isSecure, we'll never # use the ssl argument which makes no sense. context_factory = None if self.ssl is not None: if 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__) context_factory = self.ssl elif isSecure: from twisted.internet.ssl import optionsForClientTLS context_factory = optionsForClientTLS(host) from twisted.internet import reactor if self.proxy is not None: from twisted.internet.endpoints import TCP4ClientEndpoint client = TCP4ClientEndpoint(reactor, self.proxy['host'], self.proxy['port']) transport_factory.contextFactory = context_factory elif isSecure: from twisted.internet.endpoints import SSL4ClientEndpoint assert context_factory is not None client = SSL4ClientEndpoint(reactor, host, port, context_factory) else: from twisted.internet.endpoints import TCP4ClientEndpoint client = TCP4ClientEndpoint(reactor, host, port) d = client.connect(transport_factory) # as the reactor shuts down, we wish to wait until we've sent # out our "Goodbye" message; leave() returns a Deferred that # fires when the transport gets to STATE_CLOSED def cleanup(proto): if hasattr(proto, '_session') and proto._session is not None: if proto._session.is_attached(): return proto._session.leave() elif proto._session.is_connected(): return proto._session.disconnect() # when our proto was created and connected, make sure it's cleaned # up properly later on when the reactor shuts down for whatever reason def init_proto(proto): reactor.addSystemEventTrigger('before', 'shutdown', cleanup, proto) return proto # if we connect successfully, the arg is a WampWebSocketClientProtocol d.addCallback(init_proto) # if the user didn't ask us to start the reactor, then they # get to deal with any connect errors themselves. if start_reactor: # if an error happens in the connect(), we save the underlying # exception so that after the event-loop exits we can re-raise # it to the caller. class ErrorCollector(object): exception = None def __call__(self, failure): self.exception = failure.value reactor.stop() connect_error = ErrorCollector() d.addErrback(connect_error) # now enter the Twisted reactor loop reactor.run() # if we exited due to a connection error, raise that to the # caller if connect_error.exception: raise connect_error.exception else: # let the caller handle any errors return d
def run(self, make, start_reactor=True): """ 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 :param start_reactor: if True (the default) this method starts the Twisted reactor and doesn't return until the reactor stops. If there are any problems starting the reactor or connect()-ing, we stop the reactor and raise the exception back to the caller. :returns: None is returned, unless you specify ``start_reactor=False`` in which case the Deferred that connect() returns is returned; this will callback() with an IProtocol instance, which will actually be an instance of :class:`WampWebSocketClientProtocol` """ from twisted.internet import reactor isSecure, host, port, resource, path, params = parseWsUrl(self.url) # start logging to console if self.debug or self.debug_wamp or self.debug_app: log.startLogging(sys.stdout) # factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception as e: if start_reactor: # the app component could not be created .. fatal log.err(str(e)) reactor.stop() else: # if we didn't start the reactor, it's up to the # caller to deal with errors raise else: session.debug_app = self.debug_app return session # create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory(create, url=self.url, debug=self.debug, debug_wamp=self.debug_wamp) # start the client from a Twisted endpoint from twisted.internet.endpoints import clientFromString if isSecure: endpoint_descriptor = "ssl:{0}:{1}".format(host, port) else: endpoint_descriptor = "tcp:{0}:{1}".format(host, port) client = clientFromString(reactor, endpoint_descriptor) d = client.connect(transport_factory) # if the user didn't ask us to start the reactor, then they # get to deal with any connect errors themselves. if start_reactor: # if an error happens in the connect(), we save the underlying # exception so that after the event-loop exits we can re-raise # it to the caller. class ErrorCollector: exception = None def __call__(self, failure): self.exception = failure.value # print(failure.getErrorMessage()) reactor.stop() connect_error = ErrorCollector() d.addErrback(connect_error) # now enter the Twisted reactor loop reactor.run() # if we exited due to a connection error, raise that to the # caller if connect_error.exception: raise connect_error.exception else: # let the caller handle any errors return d
def test_parse_url06(self): self.assertEqual(parseWsUrl("wss://localhost/ws?foo=bar"), (True, 'localhost', 443, '/ws?foo=bar', '/ws', {'foo': ['bar']}))
def test_parse_url05(self): self.assertEqual(parseWsUrl("wss://localhost/ws"), (True, 'localhost', 443, '/ws', '/ws', {}))
def test_parse_url04(self): self.assertEqual(parseWsUrl("wss://localhost:443"), (True, 'localhost', 443, '/', '/', {}))
def run(self, make, start_reactor=True): """ 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 :param start_reactor: if True (the default) this method starts the Twisted reactor and doesn't return until the reactor stops. If there are any problems starting the reactor or connect()-ing, we stop the reactor and raise the exception back to the caller. :returns: None is returned, unless you specify ``start_reactor=False`` in which case the Deferred that connect() returns is returned; this will callback() with an IProtocol instance, which will actually be an instance of :class:`WampWebSocketClientProtocol` """ from twisted.internet import reactor txaio.use_twisted() txaio.config.loop = reactor isSecure, host, port, resource, path, params = parseWsUrl(self.url) # start logging to console if self.debug or self.debug_wamp or self.debug_app: log.startLogging(sys.stdout) # factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception as e: if start_reactor: # the app component could not be created .. fatal log.err(str(e)) reactor.stop() else: # if we didn't start the reactor, it's up to the # caller to deal with errors raise else: session.debug_app = self.debug_app return session # create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory( create, url=self.url, debug=self.debug, debug_wamp=self.debug_wamp) # start the client from a Twisted endpoint from twisted.internet.endpoints import clientFromString if isSecure: endpoint_descriptor = "ssl:{0}:{1}".format(host, port) else: endpoint_descriptor = "tcp:{0}:{1}".format(host, port) client = clientFromString(reactor, endpoint_descriptor) d = client.connect(transport_factory) # if the user didn't ask us to start the reactor, then they # get to deal with any connect errors themselves. if start_reactor: # if an error happens in the connect(), we save the underlying # exception so that after the event-loop exits we can re-raise # it to the caller. class ErrorCollector(object): exception = None def __call__(self, failure): self.exception = failure.value # print(failure.getErrorMessage()) reactor.stop() connect_error = ErrorCollector() d.addErrback(connect_error) # now enter the Twisted reactor loop reactor.run() # if we exited due to a connection error, raise that to the # caller if connect_error.exception: raise connect_error.exception else: # let the caller handle any errors return d
def test_parse_url08(self): self.assertEqual(parseWsUrl("wss://localhost/ws?foo=bar&moo=23&moo=44"), (True, 'localhost', 443, '/ws?foo=bar&moo=23&moo=44', '/ws', {'moo': ['23', '44'], 'foo': ['bar']}))
# print "reason:", reason ReconnectingClientFactory.clientConnectionFailed( self, connector, reason) def clientConnectionLost(self, connector, reason): print("Connection Lost") # print "reason:", reason ReconnectingClientFactory.clientConnectionLost(self, connector, reason) if __name__ == '__main__': Component.init() # 1) create a WAMP application session factory component_config = types.ComponentConfig(realm=Component.config["realm"]) session_factory = wamp.ApplicationSessionFactory(config=component_config) session_factory.session = Component # 2) create a WAMP-over-WebSocket transport client factory url = Component.config["url"] transport_factory = MyClientFactory(session_factory, url=url, debug=False) # 3) start the client from a Twisted endpoint isSecure, host, port, resource, path, params = parseWsUrl(url) transport_factory.host = host transport_factory.port = port websocket.connectWS(transport_factory) # 4) now enter the Twisted reactor loop reactor.run()
def run(self, make, start_reactor=True): """ 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 :param start_reactor: if True (the default) this method starts the Twisted reactor and doesn't return until the reactor stops. If there are any problems starting the reactor or connect()-ing, we stop the reactor and raise the exception back to the caller. :returns: None is returned, unless you specify ``start_reactor=False`` in which case the Deferred that connect() returns is returned; this will callback() with an IProtocol instance, which will actually be an instance of :class:`WampWebSocketClientProtocol` """ from twisted.internet import reactor txaio.use_twisted() txaio.config.loop = reactor isSecure, host, port, resource, path, params = parseWsUrl(self.url) # start logging to console if self.debug or self.debug_wamp or self.debug_app: log.startLogging(sys.stdout) # factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception as e: if start_reactor: # the app component could not be created .. fatal log.err(str(e)) reactor.stop() else: # if we didn't start the reactor, it's up to the # caller to deal with errors raise else: session.debug_app = self.debug_app return session # create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory(create, url=self.url, debug=self.debug, debug_wamp=self.debug_wamp) # if user passed ssl= but isn't using isSecure, we'll never # use the ssl argument which makes no sense. context_factory = None if self.ssl is not None: if 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__) context_factory = self.ssl elif isSecure: from twisted.internet.ssl import optionsForClientTLS context_factory = optionsForClientTLS(six.u(host)) if isSecure: from twisted.internet.endpoints import SSL4ClientEndpoint assert context_factory is not None client = SSL4ClientEndpoint(reactor, host, port, context_factory) else: from twisted.internet.endpoints import TCP4ClientEndpoint client = TCP4ClientEndpoint(reactor, host, port) d = client.connect(transport_factory) # as the reactor shuts down, we wish to wait until we've sent # out our "Goodbye" message; leave() returns a Deferred that # fires when the transport gets to STATE_CLOSED def cleanup(proto): if hasattr(proto, '_session') and proto._session is not None: return proto._session.leave() # if we connect successfully, the arg is a WampWebSocketClientProtocol d.addCallback(lambda proto: reactor.addSystemEventTrigger( 'before', 'shutdown', cleanup, proto)) # if the user didn't ask us to start the reactor, then they # get to deal with any connect errors themselves. if start_reactor: # if an error happens in the connect(), we save the underlying # exception so that after the event-loop exits we can re-raise # it to the caller. class ErrorCollector(object): exception = None def __call__(self, failure): self.exception = failure.value # print(failure.getErrorMessage()) reactor.stop() connect_error = ErrorCollector() d.addErrback(connect_error) # now enter the Twisted reactor loop reactor.run() # if we exited due to a connection error, raise that to the # caller if connect_error.exception: raise connect_error.exception else: # let the caller handle any errors return d
def run(self, make, start_reactor=True): """ 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 :param start_reactor: if True (the default) this method starts the Twisted reactor and doesn't return until the reactor stops. If there are any problems starting the reactor or connect()-ing, we stop the reactor and raise the exception back to the caller. :returns: None is returned, unless you specify ``start_reactor=False`` in which case the Deferred that connect() returns is returned; this will callback() with an IProtocol instance, which will actually be an instance of :class:`WampWebSocketClientProtocol` """ from twisted.internet import reactor txaio.use_twisted() txaio.config.loop = reactor isSecure, host, port, resource, path, params = parseWsUrl(self.url) # start logging to console if self.debug or self.debug_wamp or self.debug_app: log.startLogging(sys.stdout) # factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception as e: if start_reactor: # the app component could not be created .. fatal log.err(str(e)) reactor.stop() else: # if we didn't start the reactor, it's up to the # caller to deal with errors raise else: session.debug_app = self.debug_app return session # create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory( create, url=self.url, serializers=self.serializers, debug=self.debug, debug_wamp=self.debug_wamp) # if user passed ssl= but isn't using isSecure, we'll never # use the ssl argument which makes no sense. context_factory = None if self.ssl is not None: if 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__) context_factory = self.ssl elif isSecure: from twisted.internet.ssl import optionsForClientTLS context_factory = optionsForClientTLS(host) if isSecure: from twisted.internet.endpoints import SSL4ClientEndpoint assert context_factory is not None client = SSL4ClientEndpoint(reactor, host, port, context_factory) else: from twisted.internet.endpoints import TCP4ClientEndpoint client = TCP4ClientEndpoint(reactor, host, port) d = client.connect(transport_factory) # as the reactor shuts down, we wish to wait until we've sent # out our "Goodbye" message; leave() returns a Deferred that # fires when the transport gets to STATE_CLOSED def cleanup(proto): if hasattr(proto, '_session') and proto._session is not None: return proto._session.leave() # when our proto was created and connected, make sure it's cleaned # up properly later on when the reactor shuts down for whatever reason def init_proto(proto): reactor.addSystemEventTrigger('before', 'shutdown', cleanup, proto) return proto # if we connect successfully, the arg is a WampWebSocketClientProtocol d.addCallback(init_proto) # if the user didn't ask us to start the reactor, then they # get to deal with any connect errors themselves. if start_reactor: # if an error happens in the connect(), we save the underlying # exception so that after the event-loop exits we can re-raise # it to the caller. class ErrorCollector(object): exception = None def __call__(self, failure): self.exception = failure.value # print(failure.getErrorMessage()) reactor.stop() connect_error = ErrorCollector() d.addErrback(connect_error) # now enter the Twisted reactor loop reactor.run() # if we exited due to a connection error, raise that to the # caller if connect_error.exception: raise connect_error.exception else: # let the caller handle any errors return d
'--cpuid', dest='cpuid', type=int, default=None, help= 'If given, this is a worker which will use provided CPU core to set its affinity.' ) options = parser.parse_args() if options.profile and not hasStatprof: raise Exception("profiling requested, but statprof not installed") # parse WS URI into components and forward via options # FIXME: add TLS support isSecure, host, wsport, resource, path, params = parseWsUrl(options.wsuri) options.wsport = wsport # if not options.silence: # log.startLogging(sys.stdout) if options.fd is not None: # run worker worker(options) else: if not options.silence: for m in startupMsgs: print m # run master master(options)
parser.add_argument('--silence', dest='silence', action="store_true", default=False, help='Silence log output.') parser.add_argument('--debug', dest='debug', action="store_true", default=False, help='Enable WebSocket debug output.') parser.add_argument('--interval', dest='interval', type=int, default=5, help='Worker stats update interval.') parser.add_argument('--profile', dest='profile', action="store_true", default=False, help='Enable profiling.') parser.add_argument('--fd', dest='fd', type=int, default=None, help='If given, this is a worker which will use provided FD and all other options are ignored.') parser.add_argument('--cpuid', dest='cpuid', type=int, default=None, help='If given, this is a worker which will use provided CPU core to set its affinity.') options = parser.parse_args() if options.profile and not hasStatprof: raise Exception("profiling requested, but statprof not installed") # parse WS URI into components and forward via options # FIXME: add TLS support isSecure, host, wsport, resource, path, params = parseWsUrl(options.wsuri) options.wsport = wsport # if not options.silence: # log.startLogging(sys.stdout) if options.fd is not None: # run worker worker(options) else: if not options.silence: for m in startupMsgs: print m # run master master(options)
def test_parse_url02(self): self.assertEqual(parseWsUrl("ws://localhost:80"), (False, 'localhost', 80, '/', '/', {}))
def __init__(self, main=None, setup=None, transports=None, config=None): """ :param main: A callable that runs user code for the component. The component will be started with a "main-like" procedure. When a transport has been connected and a session has been established and joined a realm, the user code will be run until it finishes which signals that the component has run to completion. :type main: callable :param setup: A callable that runs user code for the component. The component will be started with a "setup-like" procedure. When a transport has been connected and a session has been established and joined a realm, the user code will be run until it finishes which signals that the component is now "ready". The component will continue to run until it explicitly closes the session or the underlying transport closes. :type setup: callable :param transports: Transport configurations for creating transports. :type transports: None or unicode or list :param config: Session configuration. :type config: None or dict """ ObservableMixin.__init__(self) if main is None and setup is None: raise RuntimeError('either a "main" or "setup" procedure must be provided for a component') if main is not None and setup is not None: raise RuntimeError('either a "main" or "setup" procedure must be provided for a component (not both)') if main is not None and not callable(main): raise RuntimeError('"main" must be a callable if given') if setup is not None and not callable(setup): raise RuntimeError('"setup" must be a callable if given') if setup: self._entry = setup self._entry_type = Component.TYPE_SETUP elif main: self._entry = main self._entry_type = Component.TYPE_MAIN else: assert(False), 'logic error' # use WAMP-over-WebSocket to localhost when no transport is specified at all if transports is None: transports = u'ws://127.0.0.1:8080/ws' # allows to provide an URL instead of a list of transports if type(transports) == six.text_type: url = transports is_secure, host, port, resource, path, params = parseWsUrl(url) transport = { 'type': 'websocket', 'url': url, 'endpoint': { 'type': 'tcp', 'host': host, 'port': port } } if is_secure: # FIXME transport['endpoint']['tls'] = {} transports = [transport] # now check and save list of transports self._transports = [] idx = 0 for transport in transports: check_transport(transport) self._transports.append(Transport(idx, transport)) idx += 1 self._realm = u'realm1' self._extra = None
def test_parse_url06(self): self.assertEqual(parseWsUrl("wss://localhost/ws?foo=bar"), (True, 'localhost', 443, '/ws?foo=bar', '/ws', { 'foo': ['bar'] }))
def run(self, make, start_reactor = True): """ 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 """ from twisted.internet import reactor isSecure, host, port, resource, path, params = parseWsUrl(self.url) ## start logging to console if self.debug or self.debug_wamp or self.debug_app: log.startLogging(sys.stdout) ## run an embedded router if ask to start standalone if self.standalone: from twisted.internet.endpoints import serverFromString router_factory = RouterFactory() session_factory = RouterSessionFactory(router_factory) transport_factory = WampWebSocketServerFactory(session_factory, debug = self.debug, debug_wamp = self.debug_wamp) transport_factory.setProtocolOptions(failByDrop = False) server = serverFromString(reactor, "tcp:{0}".format(port)) server.listen(transport_factory) ## factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception: ## the app component could not be created .. fatal log.err() reactor.stop() else: session.debug_app = self.debug_app return session ## create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory(create, url = self.url, serializers = self.serializers, debug = self.debug, debug_wamp = self.debug_wamp) ## start the client from a Twisted endpoint from twisted.internet.endpoints import clientFromString if isSecure: endpoint_descriptor = "ssl:{0}:{1}".format(host, port) else: endpoint_descriptor = "tcp:{0}:{1}".format(host, port) client = clientFromString(reactor, endpoint_descriptor) client.connect(transport_factory) ## now enter the Twisted reactor loop if start_reactor: reactor.run()
def run(self, make): """ 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 """ # 1) factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception as e: # the app component could not be created .. fatal print(e) asyncio.get_event_loop().stop() else: session.debug_app = self.debug_app return session isSecure, host, port, resource, path, params = parseWsUrl(self.url) 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 # 2) create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory( create, url=self.url, serializers=self.serializers, debug=self.debug, debug_wamp=self.debug_wamp) # 3) start the client loop = asyncio.get_event_loop() txaio.use_asyncio() txaio.config.loop = loop coro = loop.create_connection(transport_factory, host, port, ssl=ssl) (transport, protocol) = loop.run_until_complete(coro) 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()