def subscribe(self, handler, topic=None, options=None):
        """
        Implements :func:`autobahn.wamp.interfaces.ISubscriber.subscribe`
        """
        if six.PY2 and type(topic) == str:
            topic = six.u(topic)
        assert (topic is None or type(topic) == six.text_type)
        assert ((callable(handler) and topic is not None)
                or hasattr(handler, '__class__'))
        assert (options is None or isinstance(options, dict))

        if not self._transport:
            raise exception.TransportLost()

        if callable(handler):
            # subscribe a single handler
            return self._subscribe(None, handler, topic, options)
        else:
            # subscribe all methods on an object decorated with "wamp.subscribe"
            on_replies = []
            for k in inspect.getmembers(handler.__class__,
                                        is_method_or_function):
                proc = k[1]
                wampuris = filter(lambda x: x.is_handler(),
                                  proc.__dict__.get("_wampuris")) or ()
                for pat in wampuris:
                    subopts = pat.options or options or types.SubscribeOptions(
                        match=u"wildcard" if pat.uri_type == uri.Pattern.
                        URI_TYPE_WILDCARD else u"exact").message_attr()
                    on_replies.append(
                        self._subscribe(handler, proc, pat.uri(), subopts))
            return txaio.gather(on_replies, consume_exceptions=True)
   def test_subscribe(self):
      handler = ApplicationSession()
      transport = MockTransport(handler)

      def on_event(*args, **kwargs):
         print("got event", args, kwargs)

      subscription = yield handler.subscribe(on_event, 'com.myapp.topic1')
      self.assertTrue(type(subscription.id) in (int, long))

      subscription = yield handler.subscribe(on_event, 'com.myapp.topic1', options = types.SubscribeOptions(match = 'wildcard'))
      self.assertTrue(type(subscription.id) in (int, long))
Esempio n. 3
0
    def forward_subscriber(self, func_path, topic, options=None):
        def wrapped(*args, **kwargs):
            payload = {
                'func_path': func_path,
                'topic': topic,
                'args': args,
                'kwargs': kwargs,
            }
            channel_name = 'wamp.events'
            Channel(channel_name).send(payload)

        self.log.info("registered subscriber for '{}'".format(topic))
        if options is None:
            options = types.SubscribeOptions()
        return self.subscribe(wrapped, topic, options=options)
Esempio n. 4
0
        def test_double_subscribe_errors(self):
            """
            Test various error-conditions when we try to add a second
            subscription-handler (its signature must match any
            existing handlers).
            """
            handler = ApplicationSession()
            MockTransport(handler)

            event0 = Deferred()
            event1 = Deferred()

            def second(*args, **kw):
                # our EventDetails should have been passed as the
                # "boom" kwarg; see "details_arg=" below
                self.assertTrue('boom' in kw)
                self.assertTrue(isinstance(kw['boom'], types.EventDetails))
                event1.callback(args)

            subscription0 = yield handler.subscribe(
                lambda arg: event0.callback(arg), u'com.myapp.topic1')
            subscription1 = yield handler.subscribe(
                second,
                u'com.myapp.topic1',
                types.SubscribeOptions(details_arg='boom'),
            )
            # same topic, same ID
            self.assertTrue(subscription0.id == subscription1.id)

            # MockTransport gives us the ack reply and then we do our
            # own event message.
            publish = yield handler.publish(
                u'com.myapp.topic1',
                options=types.PublishOptions(acknowledge=True,
                                             exclude_me=False),
            )
            # note that the protocol serializer converts all sequences
            # to lists, so we pass "args" as a list, not a tuple on
            # purpose.
            handler.onMessage(
                message.Event(subscription0.id, publish.id, args=['arg0']))

            # each callback should have gotten called, each with its
            # own args (we check the correct kwarg in second() above)
            self.assertTrue(event0.called)
            self.assertTrue(event1.called)
            self.assertEqual(event0.result, 'arg0')
            self.assertEqual(event1.result, ('arg0', ))
Esempio n. 5
0
 async def _register_subscribers(self):
     for name, method, options in ScopeInspector.subscribers(self.scope):
         topic = self.scope.get_routing(method.subscribed).format(
             self.scope)
         options = types.SubscribeOptions(**options)
         try:
             subscribed = await self.session.subscribe(
                 method,
                 topic,
                 options=options,
             )
             self.subscriptions.append(subscribed)
             self.session.log.debug("subscriber `{topic}` registered",
                                    topic=topic)
         except Exception as e:
             self.session.log.error(topic)
             self.session.log.error(
                 "could not register subscriber to `{uri}`: {e!r}",
                 uri=topic,
                 e=e)
             self.session.log.error(no_format(traceback.format_exc()))
Esempio n. 6
0
    async def _register_hooks(self):
        for name, method, options in ScopeInspector.hooks(self.scope):
            global_topic = '{}.webhooks.{}'.format(
                settings.ROOT_TOPIC, method.hooked).format(self.scope)

            options = types.SubscribeOptions(**options)
            try:
                subscribed = await self.session.subscribe(
                    method,
                    global_topic,
                    options=options,
                )
                self.subscriptions.append(subscribed)
                self.session.log.debug("hook `{topic}` registered",
                                       topic=global_topic)
            except Exception as e:
                self.session.log.error(global_topic)
                self.session.log.error(
                    "could not register hook to `{topic}`: {e!r}",
                    topic=global_topic,
                    e=e)
                self.session.log.error(no_format(traceback.format_exc()))
Esempio n. 7
0
 async def on_brain_join(session, details):
     brain = Brain(robot_info, planner_name, episode_dir, session)
     logger.info('brain subscribing to {}'.format(robot_name))
     session.subscribe(brain.on_signal, 'gp.robots.{}'.format(robot_name), options=ab_types.SubscribeOptions(match='prefix')),
     asyncio.get_event_loop().create_task(brain.main_brain_loop())
Esempio n. 8
0
 async def on_join(session, details):
     logger.info('wamp component: joining')
     session.subscribe(callback, channel, options=ab_types.SubscribeOptions(match='prefix'))
Esempio n. 9
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"])
Esempio n. 10
0
    def onJoin(self, details):
        self.channel_layer = channel_layers["default"]

        Channel('wamp.join').send({'session': details.session})

        while self.is_connected():
            yield self.publish('com.example.bonjour',
                               2,
                               options=types.PublishOptions(exclude_me=False))
            self.call('com.example.hello', 'hey!')

            channel_name, result = self.channel_layer.receive_many(
                self.channels)
            if channel_name is None:
                yield sleep(SLEEP_TIME)
                continue

            elif channel_name == 'wamp.call':
                uri = result['uri']
                args = result.get('args', [])
                kwargs = result.get('kwargs', {})
                options = result.get('options', {})
                if options:
                    kwargs['options'] = types.CallOptions(**options)
                registration = self.call(uri, *args, **kwargs)

            elif channel_name == 'wamp.publish':
                topic = result['topic']
                args = result.get('args', [])
                kwargs = result.get('kwargs', {})
                options = result.get('options', {})
                if options:
                    kwargs['options'] = types.PublishOptions(**options)
                self.publish(topic, *args, **kwargs)

            elif channel_name == 'wamp.subscribe':
                func_path = result['func_path']
                topic = result['topic']
                options = result.get('options', {}) or {}
                subscribe_options = types.SubscribeOptions(**options)
                subscription = yield self.forward_subscriber(
                    func_path, topic, subscribe_options)
                self.forward_subscription(result['reply_channel'],
                                          subscription)

            elif channel_name == 'wamp.unsubscribe':
                subscription_id = result['subscription_id']
                subscription = self.subscriptions.pop(subscription_id)
                yield subscription.unsubscribe()

            elif channel_name == 'wamp.register':
                func_path = result['func_path']
                uri = result['uri']
                options = result.get('options', {}) or {}
                register_options = types.RegisterOptions(**options)
                registration = yield self.forward_procedure(
                    func_path, uri, register_options)
                self.forward_registration(result['reply_channel'],
                                          registration)

            elif channel_name == 'wamp.unregister':
                registration_id = result['registration_id']
                registration = self.subscriptions.pop(registration_id)
                yield registration.unregister()

            elif channel_name in self.reply_channels:
                self.reply_channels[channel_name].callback(
                    *result['args'], **result['kwargs'])

            yield sleep(SLEEP_TIME)

        self.log.info('disconnected!')
        Channel('wamp.disconnect').send({
            'reason': 'not connected',
        })
        self.disconnect()
        reactor.stop()