Ejemplo n.º 1
0
Archivo: app.py Proyecto: hjalves/sjw
class WAMPApplication:
    def __init__(self, app, config):
        self.app = app
        self.wamp_session = None
        self.wamp_comp = Component(transports=config['router'],
                                   realm=config['realm'])
        self.wamp_comp.on('join', self.initialize)
        self.wamp_comp.on('leave', self.uninitialize)

    @to_deferred
    async def initialize(self, session, details):
        logger.info("Connected to WAMP router")
        self.wamp_session = session
        await session.register(self.app.list_units, 'sjw.list_units')
        await session.register(self.app.query, 'sjw.query')
        await session.register(self.app.start, 'sjw.start')
        await session.register(self.app.stop, 'sjw.stop')
        await session.register(self.app.enable, 'sjw.enable')
        await session.register(self.app.disable, 'sjw.disable')

    def uninitialize(self, session, reason):
        logger.info("%s %s", session, reason)
        logger.info("Lost WAMP connection")
        self.wamp_session = None

    def on_unit_changed(self, unit, props):
        if not self.wamp_session:
            return
        self.wamp_session.publish('sjw.unit.' + unit, props)

    @to_deferred
    async def start(self, reactor=None):
        logger.info("Starting component")
        return (await self.wamp_comp.start(reactor))
        def test_successful_connect(self, fake_sleep):
            endpoint = Mock()
            joins = []

            def joined(session, details):
                joins.append((session, details))
                return session.leave()

            directlyProvides(endpoint, IStreamClientEndpoint)
            component = Component(
                transports={
                    "type": "websocket",
                    "url": "ws://127.0.0.1/ws",
                    "endpoint": endpoint,
                })
            component.on('join', joined)

            def connect(factory, **kw):
                proto = factory.buildProtocol('ws://localhost/')
                transport = FakeTransport()
                proto.makeConnection(transport)

                from autobahn.websocket.protocol import WebSocketProtocol
                from base64 import b64encode
                from hashlib import sha1
                key = proto.websocket_key + WebSocketProtocol._WS_MAGIC
                proto.data = (b"HTTP/1.1 101 Switching Protocols\x0d\x0a"
                              b"Upgrade: websocket\x0d\x0a"
                              b"Connection: upgrade\x0d\x0a"
                              b"Sec-Websocket-Protocol: wamp.2.json\x0d\x0a"
                              b"Sec-Websocket-Accept: " +
                              b64encode(sha1(key).digest()) +
                              b"\x0d\x0a\x0d\x0a")
                proto.processHandshake()

                from autobahn.wamp import role
                features = role.RoleBrokerFeatures(
                    publisher_identification=True,
                    pattern_based_subscription=True,
                    session_meta_api=True,
                    subscription_meta_api=True,
                    subscriber_blackwhite_listing=True,
                    publisher_exclusion=True,
                    subscription_revocation=True,
                    payload_transparency=True,
                    payload_encryption_cryptobox=True,
                )

                msg = Welcome(123456, dict(broker=features), realm='realm')
                serializer = JsonSerializer()
                data, is_binary = serializer.serialize(msg)
                proto.onMessage(data, is_binary)

                msg = Goodbye()
                proto.onMessage(*serializer.serialize(msg))
                proto.onClose(True, 100, "some old reason")

                return succeed(proto)

            endpoint.connect = connect

            # XXX it would actually be nicer if we *could* support
            # passing a reactor in here, but the _batched_timer =
            # make_batched_timer() stuff (slash txaio in general)
            # makes this "hard".
            reactor = Clock()
            with replace_loop(reactor):
                yield component.start(reactor=reactor)
                self.assertTrue(len(joins), 1)
                # make sure we fire all our time-outs
                reactor.advance(3600)
Ejemplo n.º 3
0
        def test_successful_connect(self, fake_sleep):
            endpoint = Mock()
            joins = []

            def joined(session, details):
                joins.append((session, details))
                return session.leave()
            directlyProvides(endpoint, IStreamClientEndpoint)
            component = Component(
                transports={
                    "type": "websocket",
                    "url": "ws://127.0.0.1/ws",
                    "endpoint": endpoint,
                }
            )
            component.on('join', joined)

            def connect(factory, **kw):
                proto = factory.buildProtocol('boom')
                proto.makeConnection(Mock())

                from autobahn.websocket.protocol import WebSocketProtocol
                from base64 import b64encode
                from hashlib import sha1
                key = proto.websocket_key + WebSocketProtocol._WS_MAGIC
                proto.data = (
                    b"HTTP/1.1 101 Switching Protocols\x0d\x0a"
                    b"Upgrade: websocket\x0d\x0a"
                    b"Connection: upgrade\x0d\x0a"
                    b"Sec-Websocket-Protocol: wamp.2.json\x0d\x0a"
                    b"Sec-Websocket-Accept: " + b64encode(sha1(key).digest()) + b"\x0d\x0a\x0d\x0a"
                )
                proto.processHandshake()

                from autobahn.wamp import role
                features = role.RoleBrokerFeatures(
                    publisher_identification=True,
                    pattern_based_subscription=True,
                    session_meta_api=True,
                    subscription_meta_api=True,
                    subscriber_blackwhite_listing=True,
                    publisher_exclusion=True,
                    subscription_revocation=True,
                    payload_transparency=True,
                    payload_encryption_cryptobox=True,
                )

                msg = Welcome(123456, dict(broker=features), realm=u'realm')
                serializer = JsonSerializer()
                data, is_binary = serializer.serialize(msg)
                proto.onMessage(data, is_binary)

                msg = Goodbye()
                proto.onMessage(*serializer.serialize(msg))
                proto.onClose(True, 100, "some old reason")

                return succeed(proto)
            endpoint.connect = connect

            # XXX it would actually be nicer if we *could* support
            # passing a reactor in here, but the _batched_timer =
            # make_batched_timer() stuff (slash txaio in general)
            # makes this "hard".
            reactor = Clock()
            with replace_loop(reactor):
                yield component.start(reactor=reactor)
                self.assertTrue(len(joins), 1)
                # make sure we fire all our time-outs
                reactor.advance(3600)
Ejemplo n.º 4
0
def test_roundrobin_proxy(request, reactor, virtualenv):
    """
    Confirm that a proxy with two connections does connections to both
    backends.

    Two nodes each with a router-worker for 'realm1'
    Each node rlink-connects to the other.
    One node has a proxy
    """

    tempdir = _create_temp(request)

    # burn in hard-coded keys so we can refer to the public parts in
    # configs more easily.
    node_keys = [
        (node0_pubkey, node0_privkey),
        (node1_pubkey, node1_privkey),
        (node2_pubkey, node2_privkey),
        (node3_pubkey, node3_privkey),
    ]
    for node_num in range(4):
        node_dir = join(tempdir, "node{}".format(node_num))
        os.mkdir(node_dir)

        pub, priv = node_keys[node_num]
        with open(join(node_dir, "key.pub"), "w") as f:
            f.write(pub)
        with open(join(node_dir, "key.priv"), "w") as f:
            f.write(priv)

    # we start the nodes in parallel because we don't know which one
    # will "win" and connect first
    node_setup = [
        (node0_config, join(tempdir, "node0")),
        (node1_config, join(tempdir, "node1")),
        (node2_config, join(tempdir, "node2")),
        (node3_config, join(tempdir, "node3")),
    ]
    node_starts = []
    for node_config, node_dir in node_setup:
        node_d = start_node(request, reactor, virtualenv, node_config, node_dir)
        node_starts.append(node_d)
    print("-" * 80)
    print(node_starts)
    results = yield DeferredList(node_starts)
    print("-" * 80)
    print(results)
    print("-" * 80)
    nodes = []
    for ok, res in results:
        if not ok:
            raise res
        nodes.append(res)
    protocol0, protocol1, protocol2, protocol3 = nodes

    print("Started rlink'd nodes:")

    print("  0: {}".format(protocol0))
    print("  1: {}".format(protocol1))
    print("  2: {}".format(protocol2))
    print("  3: {}".format(protocol3))

    print("-" * 80)

    # we could wait to see text of each node successfully connecting
    # to the other .. or we just wait a bit.
    yield sleep(5)

    subscribed_d = Deferred()
    rpc_call_d = Deferred()
    print("start alice")
    # run alice first

    alice = Component(
        transports=[
            {"url": "ws://localhost:7070/ws", "type": "websocket"},  # proxy0
        ],
        realm="realm1",
    )

    @alice.on_join
    @inlineCallbacks
    def alice_join(session, details):
        print("\n\nalice joined\n")

        def a_thing(*args, **kw):
            print("received: a_thing: args={} kw={}".format(args, kw))
            reactor.callLater(3, session.leave)
        yield session.subscribe(a_thing, "test.a_thing")

        def rpc(*args, **kw):
            print("call: rpc: args={} kw={}".format(args, kw))
            reactor.callLater(1, rpc_call_d.callback, None)
            return "rpc return"
        yield session.register(rpc, "test.rpc")
        # XXX we don't know when the rlink registration goes all the way through...
        reactor.callLater(2.0, subscribed_d.callback, None)

    alice_done = alice.start(reactor)

    # wait until Alice actually subscribes (and thus is also registered) before starting bob
    yield subscribed_d
    print("alice is subscribed + registered")

    print("start bob")

    bob = Component(
        transports=[{
            "url": "ws://localhost:7070/ws",  # node0 XXX should be node1
            "type": "websocket",
        }],
        realm="realm1",
    )

    @bob.on_join
    @inlineCallbacks
    def bob_join(session, details):
        print("bob joined: PID={x_cb_pid}".format(**details.authextra))
        print("publishing 'test.a_thing'")
        p = yield session.publish("test.a_thing", 3, 2, 1, options=types.PublishOptions(acknowledge=True))
        print("published {}".format(p))
        res = yield session.call("test.rpc", 1, 2, 3)
        print("test.rpc returned: {}".format(res))
        reactor.callLater(2, session.leave)

    bob_done = bob.start(reactor)
    print("bob is starting", bob_done, alice_done)
    yield rpc_call_d
    yield bob_done
    yield alice_done

    # do a bunch of pubs in different sessions to prove we're hitting
    # different proxies and different router processes.

    received = []
    connects = []

    carol = Component(
        transports=[{
            "url": "ws://*****:*****@carol.subscribe("multiverse", types.SubscribeOptions(details=True))
    def _(*args, **kwargs):
        print("SUB: {}".format(kwargs.get('details', None)))
        received.append((args, kwargs))

    carol_ready = Deferred()
    carol.on('ready', carol_ready.callback)
    carol.start()

    yield sleep(3)
    yield carol_ready

    GROUPS = 10
    CONNECTS = 5

    for g in range(GROUPS):
        group = []
        for m in range(CONNECTS):
            client = Component(
                transports=[{
                    "url": "ws://localhost:7070/ws",  # proxy0
                    "type": "websocket",
                }],
                realm="realm1",
            )

            @client.on_join
            @inlineCallbacks
            def _(session, details):
                connects.append(details)
                yield session.publish(
                    u"multiverse", group=g, member=m,
                    options=types.PublishOptions(acknowledge=True)
                )
                yield session.leave()

            group.append(client.start())
        res = yield DeferredList(group)
        for ok, value in res:
            if not ok:
                raise value
    print("-" * 80)
    print("Received {} events".format(len(received)))
    for r in received:
        print(r[1]['details'])

    # some client should get each publish() that we sent

    # FIXME: AssertionError: assert 49 == (10 * 5)
    assert len(received) == GROUPS * CONNECTS
    print("-" * 80)

    # figure out which nodes and proxies we've contacted
    workers = set()
    proxies = set()
    for c in connects:
        workers.add(c.authextra['x_cb_worker'])
        proxies.add(c.authextra['x_cb_proxy_worker'])
        print(c.authextra['x_cb_worker'])
    print("workers: {}".format(workers))
    print("proxies: {}".format(proxies))
    print("-" * 80)
    assert workers == set([
        "node0_worker0",
        "node1_worker0",
        "node2_worker0",
        "node3_worker0",
    ])
    assert proxies == set(["node0_proxy0"])