def run(self): try: asyncio.set_event_loop(self._loop) txaio.use_asyncio() txaio.config.loop = self._loop # Info is too verbose, use error by default # TODO: Make logging level for autobahn configurable txaio.start_logging(level='error') # create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory( lambda: self._akcomponent_factory(self._decoupler, self. _callback_executor, self. _allow_exception), url=self._url) # Basic settings with most features disabled transport_factory.setProtocolOptions(failByDrop=False, openHandshakeTimeout=5., closeHandshakeTimeout=1.) isSecure, host, port, _, _, _ = parse_ws_url(self._url) transport, protocol = self._loop.run_until_complete( self._loop.create_connection(transport_factory, host, port, ssl=isSecure)) try: self._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: self._loop.run_until_complete(protocol._session.leave()) self._loop.close() except Exception as e: errorStr = pformat(e) stderr.write(errorStr + "\n") # Wake the caller, this thread will terminate right after so the # error can be detected by checking if the thread is alive self._decoupler.set_joined() self._decoupler.unblock_caller()
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 """ def _create_app_session(): cfg = ComponentConfig(self._realm, self._extra) try: session = make(cfg) except Exception as e: # the app component could not be created .. fatal asyncio.get_event_loop().stop() raise e else: session.debug_app = self._debug_app return session self._transport_factory = WampWebSocketClientFactory( _create_app_session, url=self._url, serializers=self._serializers) if self._auto_ping_interval is not None and self._auto_ping_timeout is not None: self._transport_factory.setProtocolOptions( openHandshakeTimeout=self._open_handshake_timeout, autoPingInterval=self._auto_ping_interval, autoPingTimeout=self._auto_ping_timeout) txaio.use_asyncio() txaio.config.loop = self._loop asyncio. async (self._connect(), loop=self._loop) try: self._loop.add_signal_handler(signal.SIGTERM, self.stop) except NotImplementedError: # Ignore if not implemented. Means this program is running in windows. pass try: self._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 self._closing = True if self._active_protocol and self._active_protocol._session: self._loop.run_until_complete( self._active_protocol._session.leave()) self._loop.close()
def _transport_factory(self): "create and return the transport factory" try: factory = WampWebSocketClientFactory( self._component, url=self.wmp_url, serializers=self.wmp_serializers, loop=self._loop) except Exception as exc: raise Exception("could not build transport factory: %s" % exc) else: factory._session_joined = asyncio.Future(loop=self._loop) self._logger.info("WAMP connecting to %s, realm '%s'" % (self.wmp_url, self.wmp_realm)) return factory
async def run_client(loop): def fact(): self.session = ClientSession(realm='realm1', user=user, token=token, task_cb=self.task_callback) return self.session transport_factory = WampWebSocketClientFactory(fact, url=wamp_url) parsed_url = urlparse(wamp_url) ssl = False if parsed_url.scheme == 'wss': #TODO: This is not good solution, rather consider either providing additional #CA certs - or for internal communication using plain TCP socket ssl = ssllib._create_unverified_context() hp = parsed_url.netloc.split(':') if len(hp) == 1: host, port = hp[0], 8080 elif len(hp) == 2: host, port = hp[0], int(hp[1]) else: raise ValueError('Invalid URL %s' % wamp_url) conn = loop.create_connection(transport_factory, host, port, ssl=ssl) (transport, protocol) = await conn self.protocol = protocol self.transport = transport self._ready.set()
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, ssl = isSecure) loop.run_until_complete(coro) ## 4) now enter the asyncio event loop loop.run_forever() loop.close()
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 start_session(url, realm, extra): from autobahn.wamp.types import ComponentConfig from autobahn.websocket.util import parse_url from autobahn.asyncio.websocket import WampWebSocketClientFactory loop = asyncio.get_event_loop() ready = asyncio.Event() @asyncio.coroutine def connected(session): ready.set() if not extra: extra = {} extra['loop'] = loop extra['connected'] = connected session = [None] def create(): cfg = ComponentConfig(realm, extra) session[0] = ClientSession(cfg) return session[0] transport_factory = WampWebSocketClientFactory(create, url=url) _, host, port, _, _, _ = parse_url(url) coro = loop.create_connection(transport_factory, host, port) (transport, protocol) = loop.run_until_complete(coro) loop.run_until_complete(ready.wait()) return session[0]
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 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 loop.run_until_complete(protocol._session.leave()) loop.close()
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 run(self, make, app_cfg=None): """ 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 """ self.loop = self.loop or asyncio.get_event_loop() txaio.use_asyncio() txaio.config.loop = self.loop # 1) factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra) session = make(cfg, app_cfg=app_cfg, loop=self.loop) 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, loop=self.loop) # 3) start the client coro = self.loop.create_connection(transport_factory, host, port, ssl=ssl) (self.transport, self.protocol) = self.loop.run_until_complete(coro)
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 """ def _create_app_session(): cfg = ComponentConfig(self._realm, self._extra) try: session = make(cfg) except Exception as e: # the app component could not be created .. fatal asyncio.get_event_loop().stop() raise e else: session.debug_app = self._debug_app return session self._transport_factory = WampWebSocketClientFactory(_create_app_session, url=self._url, serializers=self._serializers) if self._auto_ping_interval is not None and self._auto_ping_timeout is not None: self._transport_factory.setProtocolOptions(autoPingInterval=self._auto_ping_interval, autoPingTimeout=self._auto_ping_timeout) txaio.use_asyncio() txaio.config.loop = self._loop asyncio.async(self._connect(), loop=self._loop) self._loop.add_signal_handler(signal.SIGTERM, self.stop) try: self._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 self._closing = True if self._active_protocol and self._active_protocol._session: self._loop.run_until_complete(self._active_protocol._session.leave()) self._loop.close()
def run(self, make): # 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 = parse_url(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) # transport_factory.setProtocolOptions(failByDrop=False, openHandshakeTimeout=90, closeHandshakeTimeout=5) # 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
def _start(self): if self.session: return import asyncio import txaio txaio.use_asyncio() txaio.config.loop = self.loop = asyncio.get_event_loop() from autobahn.wamp import protocol from autobahn.wamp.types import ComponentConfig from autobahn.websocket.util import parse_url from autobahn.asyncio.websocket import WampWebSocketClientFactory from ..remote.client import ClientSession @asyncio.coroutine def _connected(session): self.ready.set() def create(): cfg = ComponentConfig(self.realm, { 'loop': self.loop, 'func': _connected, }) self.session = ClientSession(cfg) return self.session transport_factory = WampWebSocketClientFactory(create, url=self.url) _, host, port, _, _, _ = parse_url(self.url) self.ready = asyncio.Event() coro = self.loop.create_connection(transport_factory, host, port) (transport, protocol) = self.loop.run_until_complete(coro) print(transport, protocol) self.loop.run_until_complete(self.ready.wait())
import importlib c = args.component.split('.') mod, klass = '.'.join(c[:-1]), c[-1] app = importlib.import_module(mod) ## .. and set the session class on the factory ## session_factory.session = getattr(app, klass) if args.transport == "websocket": ## create a WAMP-over-WebSocket transport client factory ## from autobahn.asyncio.websocket import WampWebSocketClientFactory transport_factory = WampWebSocketClientFactory(session_factory, url=args.url, debug_wamp=args.debug) transport_factory.setProtocolOptions(failByDrop=False) 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")
class ApplicationRunner(object): """ This class is a slightly modified version of autobahn.asyncio.wamp.ApplicationRunner with auto reconnection feature to with customizable strategies. """ 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 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 """ def _create_app_session(): cfg = ComponentConfig(self._realm, self._extra) try: session = make(cfg) except Exception as e: # the app component could not be created .. fatal asyncio.get_event_loop().stop() raise e else: session.debug_app = self._debug_app return session self._transport_factory = WampWebSocketClientFactory(_create_app_session, url=self._url, serializers=self._serializers) if self._auto_ping_interval is not None and self._auto_ping_timeout is not None: self._transport_factory.setProtocolOptions(autoPingInterval=self._auto_ping_interval, autoPingTimeout=self._auto_ping_timeout) txaio.use_asyncio() txaio.config.loop = self._loop asyncio.async(self._connect(), loop=self._loop) self._loop.add_signal_handler(signal.SIGTERM, self.stop) try: self._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 self._closing = True if self._active_protocol and self._active_protocol._session: self._loop.run_until_complete(self._active_protocol._session.leave()) self._loop.close() @asyncio.coroutine def _connect(self): self._active_protocol = None self._retry_strategy.reset_retry_interval() while True: try: _, protocol = yield from self._loop.create_connection(self._transport_factory, self._host, self._port, ssl=self._ssl) protocol.is_closed.add_done_callback(self._reconnect) self._active_protocol = protocol return except OSError: print('Connection failed') if self._retry_strategy.retry(): retry_interval = self._retry_strategy.get_retry_interval() print('Retry in {} seconds'.format(retry_interval)) yield from asyncio.sleep(retry_interval) else: print('Exceeded retry count') self._loop.stop() raise ExceededRetryCount() self._retry_strategy.increase_retry_interval() def _reconnect(self, f): # Reconnect print('Connection lost') if not self._closing: print('Reconnecting') asyncio.async(self._connect(), loop=self._loop) def stop(self, *args): self._loop.stop()
async def do_connect() -> None: def create_session() -> AsphaltSession: session = AsphaltSession(self.realm, self.auth_method, self.auth_id, self.auth_secret) session.on('disconnect', on_disconnect) session.on('join', on_join) session.on('leave', on_leave) return session def on_disconnect(session: AsphaltSession, was_clean: bool): if not was_clean: join_future.set_exception(ConnectionError('connection closed unexpectedly')) def on_join(session: AsphaltSession, details: SessionDetails): session.off('disconnect') join_future.set_result((session, details)) def on_leave(session: AsphaltSession, details): self._session = None self._session_details = None self._connect_task = None self._subscriptions.clear() self._registrations.clear() self.realm_left.dispatch(details) if not session._goodbye_sent: if not join_future.done(): join_future.set_exception(ConnectionError(details.message)) elif join_future.done(): logger.error('Connection lost; reconnecting') self.connect() proto = 'wss' if self.tls else 'ws' url = '{proto}://{self.host}:{self.port}{self.path}'.format(proto=proto, self=self) logger.info('Connecting to %s', url) serializers = [wrap_serializer(self.serializer)] attempts = 0 while self._session is None: transport = None attempts += 1 try: join_future = self._loop.create_future() transport_factory = WampWebSocketClientFactory( create_session, url=url, serializers=serializers, loop=self._loop) transport_factory.setProtocolOptions(**self.protocol_options) with timeout(self.connection_timeout): transport, protocol = await self._loop.create_connection( transport_factory, self.host, self.port, ssl=(cast(Optional[SSLContext], self.tls_context) or True if self.tls else False)) # Connection established; wait for the session to join the realm logger.info('Connected to %s; attempting to join realm %s', self.host, self.realm) self._session, self._session_details = await join_future # Register exception mappings with the session logger.info( 'Realm %r joined; registering %d procedure(s), %d subscription(s) and %d ' 'exception(s)', self._session_details.realm, len(self._registry.procedures), len(self._registry.subscriptions), len(self._registry.exceptions)) for error, exc_type in self._registry.exceptions.items(): self._session.define(exc_type, error) # Register procedures with the session for procedure in self._registry.procedures.values(): with timeout(10): await self._register(procedure) # Register subscribers with the session for subscriber in self._registry.subscriptions: with timeout(10): await self._subscribe(subscriber) except Exception as e: if self._session: await self.stop() elif transport: transport.close() if isinstance(e, CancelledError): logger.info('Connection attempt cancelled') raise if (self.max_reconnection_attempts is not None and attempts > self.max_reconnection_attempts): raise logger.warning('Connection failed (attempt %d): %s(%s); reconnecting in %s ' 'seconds', attempts, e.__class__.__name__, e, self.reconnect_delay) await sleep(self.reconnect_delay) # Notify listeners that we've joined the realm self.realm_joined.dispatch(self._session_details) logger.info('Joined realm %r', self.realm)
async def do_connect() -> None: proto = 'wss' if self.ssl else 'ws' url = '{proto}://{self.host}:{self.port}{self.path}'.format( proto=proto, self=self) logger.debug('Connecting to %s:%d (ssl=%s)', self.host, self.port, bool(self.ssl)) serializers = [wrap_serializer(self.serializer)] loop = txaio.config.loop = get_event_loop() transport = None attempts = 0 while self._session is None: attempts += 1 try: join_future = Future() session_factory = partial(AsphaltSession, self.realm, self.auth_method, self.auth_id, self.auth_secret, join_future) transport_factory = WampWebSocketClientFactory( session_factory, url=url, serializers=serializers, loop=loop) transport, protocol = await loop.create_connection( transport_factory, self.host, self.port, ssl=self.ssl) # Connection established; wait for the session to join the realm logger.debug('Connected; attempting to join realm %s', self.realm) self._session_details, self._session = await wait_for( join_future, timeout=5, loop=loop) # Register exception mappings with the session logger.debug( 'Realm joined; registering exceptions, subscriptions and procedures' ) for error, exc_type in self.registry.exceptions.items(): self._session.define(exc_type, error) # Register procedures and subscribers with the session tasks = [ loop.create_task(self._subscribe(subscriber)) for subscriber in self.registry.subscriptions ] tasks += [ loop.create_task(self._register(procedure)) for procedure in self.registry.procedures.values() ] if tasks: done, not_done = await wait( tasks, loop=loop, timeout=10, return_when=FIRST_EXCEPTION) for task in done: if task.exception(): raise task.exception() except CancelledError: raise except Exception as e: if transport: transport.close() self._session = self._session_details = transport = None if (self.max_reconnection_attempts is not None and attempts > self.max_reconnection_attempts): raise logger.info( 'Connection failed (attempt %d): %s(%s); reconnecting in %d ' 'seconds', attempts, e.__class__.__name__, e, self.reconnect_delay) await sleep(self.reconnect_delay) self._session.on('leave', _leave_callback) # Notify listeners that we've joined the realm self.realm_joined.dispatch(self._session_details) logger.debug('Registration complete')
class ApplicationRunner(object): """ This class is a slightly modified version of autobahn.asyncio.wamp.ApplicationRunner with auto reconnection feature to with customizable strategies. """ def __init__(self, url, realm, extra=None, serializers=None, debug_app=False, ssl=None, loop=None, retry_strategy=BackoffStrategy(), open_handshake_timeout=30, 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 open_handshake_timeout: How long to wait for the opening handshake to complete (in seconds). :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._open_handshake_timeout = open_handshake_timeout 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 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 """ def _create_app_session(): cfg = ComponentConfig(self._realm, self._extra) try: session = make(cfg) except Exception as e: # the app component could not be created .. fatal asyncio.get_event_loop().stop() raise e else: session.debug_app = self._debug_app return session self._transport_factory = WampWebSocketClientFactory( _create_app_session, url=self._url, serializers=self._serializers) if self._auto_ping_interval is not None and self._auto_ping_timeout is not None: self._transport_factory.setProtocolOptions( openHandshakeTimeout=self._open_handshake_timeout, autoPingInterval=self._auto_ping_interval, autoPingTimeout=self._auto_ping_timeout) txaio.use_asyncio() txaio.config.loop = self._loop asyncio. async (self._connect(), loop=self._loop) try: self._loop.add_signal_handler(signal.SIGTERM, self.stop) except NotImplementedError: # Ignore if not implemented. Means this program is running in windows. pass try: self._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 self._closing = True if self._active_protocol and self._active_protocol._session: self._loop.run_until_complete( self._active_protocol._session.leave()) self._loop.close() @asyncio.coroutine def _connect(self): self._active_protocol = None self._retry_strategy.reset_retry_interval() while True: try: _, protocol = yield from self._loop.create_connection( self._transport_factory, self._host, self._port, ssl=self._ssl) protocol.is_closed.add_done_callback(self._reconnect) self._active_protocol = protocol return except OSError: print('Connection failed') if self._retry_strategy.retry(): retry_interval = self._retry_strategy.get_retry_interval() print('Retry in {} seconds'.format(retry_interval)) yield from asyncio.sleep(retry_interval) else: print('Exceeded retry count') self._loop.stop() raise ExceededRetryCount() self._retry_strategy.increase_retry_interval() def _reconnect(self, f): # Reconnect print('Connection lost') if not self._closing: print('Reconnecting') asyncio. async (self._connect(), loop=self._loop) def stop(self, *args): self._loop.stop()
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: 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 isSecure, host, port, resource, path, params = parse_url(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) # 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) # start logging txaio.start_logging(level='info') 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 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()
import importlib c = args.component.split('.') mod, klass = '.'.join(c[:-1]), c[-1] app = importlib.import_module(mod) ## .. and set the session class on the factory ## session_factory.session = getattr(app, klass) if args.transport == "websocket": ## create a WAMP-over-WebSocket transport client factory ## from autobahn.asyncio.websocket import WampWebSocketClientFactory transport_factory = WampWebSocketClientFactory(session_factory, url = args.url, debug_wamp = args.debug) transport_factory.setProtocolOptions(failByDrop = False) 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")