예제 #1
0
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
예제 #2
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 _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)
예제 #4
0
    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()
예제 #5
0
    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()
예제 #6
0
    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()
예제 #7
0
    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))
예제 #8
0
    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))