Пример #1
0
        def test_double_subscribe(self):
            handler = ApplicationSession()
            MockTransport(handler)

            event0 = Deferred()
            event1 = Deferred()

            subscription0 = yield handler.subscribe(
                lambda: event0.callback(42), u'com.myapp.topic1')
            subscription1 = yield handler.subscribe(
                lambda: event1.callback('foo'), u'com.myapp.topic1')
            # same topic, same ID
            self.assertTrue(subscription0.id == subscription1.id)

            # do a publish (MockTransport fakes the acknowledgement
            # message) and then do an actual publish event. The IDs
            # are the same, so we just do one Event.
            publish = yield handler.publish(
                u'com.myapp.topic1',
                options=types.PublishOptions(acknowledge=True,
                                             exclude_me=False),
            )
            handler.onMessage(message.Event(subscription0.id, publish.id))

            # ensure we actually got both callbacks
            self.assertTrue(event0.called, "Missing callback")
            self.assertTrue(event1.called, "Missing callback")
Пример #2
0
        def test_publish_callback_exception(self):
            """
            Ensure we handle an exception from the user code.
            """
            handler = ApplicationSession()
            MockTransport(handler)

            error_instance = RuntimeError("we have a problem")
            got_err_d = Deferred()

            def observer(e, msg):
                if error_instance == e.value:
                    got_err_d.callback(True)

            handler.onUserError = observer

            def boom():
                raise error_instance

            sub = yield handler.subscribe(boom, u'com.myapp.topic1')

            # 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),
            )
            msg = message.Event(sub.id, publish.id)
            handler.onMessage(msg)

            # we know it worked if our observer worked and did
            # .callback on our Deferred above.
            self.assertTrue(got_err_d.called)
Пример #3
0
                def _get_retained_event():

                    if subscription.extra.retained_events:
                        retained_events = list(subscription.extra.retained_events)
                        retained_events.reverse()

                        for retained_event in retained_events:
                            authorized = False

                            if not retained_event.publish.exclude and not retained_event.publish.eligible:
                                authorized = True
                            elif session._session_id in retained_event.publish.eligible and session._session_id not in retained_event.publish.exclude:
                                authorized = True

                            if authorized:
                                publication = util.id()

                                if retained_event.publish.payload:
                                    msg = message.Event(subscription.id,
                                                        publication,
                                                        payload=retained_event.publish.payload,
                                                        enc_algo=retained_event.publish.enc_algo,
                                                        enc_key=retained_event.publish.enc_key,
                                                        enc_serializer=retained_event.publish.enc_serializer,
                                                        publisher=retained_event.publisher,
                                                        publisher_authid=retained_event.publisher_authid,
                                                        publisher_authrole=retained_event.publisher_authrole,
                                                        retained=True)
                                else:
                                    msg = message.Event(subscription.id,
                                                        publication,
                                                        args=retained_event.publish.args,
                                                        kwargs=retained_event.publish.kwargs,
                                                        publisher=retained_event.publisher,
                                                        publisher_authid=retained_event.publisher_authid,
                                                        publisher_authrole=retained_event.publisher_authrole,
                                                        retained=True)

                                msg.correlation_id = subscribe.correlation_id
                                msg.correlation_uri = subscribe.topic
                                msg.correlation_is_anchor = False
                                msg.correlation_is_last = False

                                return [msg]
                    return []
Пример #4
0
def generate_test_messages():
   return [
      message.Hello(u"realm1", [role.RoleBrokerFeatures()]),
      message.Goodbye(),
      message.Heartbeat(123, 456),
      message.Yield(123456),
      message.Yield(123456, args = [1, 2, 3], kwargs = {u'foo': 23, u'bar': u'hello'}),
      message.Yield(123456, progress = True),
      message.Interrupt(123456),
      message.Interrupt(123456, mode = message.Interrupt.KILL),
      message.Invocation(123456, 789123),
      message.Invocation(123456, 789123, args = [1, 2, 3], kwargs = {u'foo': 23, u'bar': u'hello'}),
      message.Invocation(123456, 789123, timeout = 10000),
      message.Result(123456),
      message.Result(123456, args = [1, 2, 3], kwargs = {u'foo': 23, u'bar': u'hello'}),
      message.Result(123456, progress = True),
      message.Cancel(123456),
      message.Cancel(123456, mode = message.Cancel.KILL),
      message.Call(123456, u'com.myapp.procedure1'),
      message.Call(123456, u'com.myapp.procedure1', args = [1, 2, 3], kwargs = {u'foo': 23, u'bar': u'hello'}),
      message.Call(123456, u'com.myapp.procedure1', timeout = 10000),
      message.Unregistered(123456),
      message.Unregister(123456, 789123),
      message.Registered(123456, 789123),
      message.Register(123456, u'com.myapp.procedure1'),
      message.Register(123456, u'com.myapp.procedure1', pkeys = [10, 11, 12]),
      message.Event(123456, 789123),
      message.Event(123456, 789123, args = [1, 2, 3], kwargs = {u'foo': 23, u'bar': u'hello'}),
      message.Event(123456, 789123, publisher = 300),
      message.Published(123456, 789123),
      message.Publish(123456, u'com.myapp.topic1'),
      message.Publish(123456, u'com.myapp.topic1', args = [1, 2, 3], kwargs = {u'foo': 23, u'bar': u'hello'}),
      message.Publish(123456, u'com.myapp.topic1', excludeMe = False, exclude = [300], eligible = [100, 200, 300], discloseMe = True),
      message.Unsubscribed(123456),
      message.Unsubscribe(123456, 789123),
      message.Subscribed(123456, 789123),
      message.Subscribe(123456, u'com.myapp.topic1'),
      message.Subscribe(123456, u'com.myapp.topic1', match = message.Subscribe.MATCH_PREFIX),
      message.Error(message.Call.MESSAGE_TYPE, 123456, u'com.myapp.error1'),
      message.Error(message.Call.MESSAGE_TYPE, 123456, u'com.myapp.error1', args = [1, 2, 3], kwargs = {u'foo': 23, u'bar': u'hello'}),
      message.Call(123456, u'com.myapp.\u4f60\u597d\u4e16\u754c', args=[1, 2, 3]),
      message.Result(123456, args=[1, 2, 3], kwargs={u'en': u'Hello World', u'jp': u'\u3053\u3093\u306b\u3061\u306f\u4e16\u754c'})
   ]
Пример #5
0
def generate_test_messages_binary():
    """
    Generate WAMP test messages which contain binary app payloads.

    With the JSON serializer, this currently only works on Python 3 (both CPython3 and PyPy3),
    because even on Python 3, we need to patch the stdlib JSON, and on Python 2, the patching
    would be even hackier.
    """
    msgs = []
    for binary in [b'',
                   b'\x00',
                   b'\30',
                   os.urandom(4),
                   os.urandom(16),
                   os.urandom(128),
                   os.urandom(256),
                   os.urandom(512),
                   os.urandom(1024)]:
        msgs.append(message.Event(123456, 789123, args=[binary]))
        msgs.append(message.Event(123456, 789123, args=[binary], kwargs={'foo': binary}))
    return [(True, msg) for msg in msgs]
Пример #6
0
        def test_double_subscribe_double_unsubscribe(self):
            '''
            If we subscribe twice, and unsubscribe twice, we should then get
            an Unsubscribed message.
            '''
            handler = ApplicationSession()
            MockTransport(handler)

            # monkey-patch ApplicationSession to ensure we get our message
            unsubscribed_d = Deferred()

            def onMessage(msg):
                if isinstance(msg, message.Unsubscribed):
                    unsubscribed_d.callback(msg)
                return ApplicationSession.onMessage(handler, msg)

            handler.onMessage = onMessage

            event0 = Deferred()
            event1 = Deferred()

            subscription0 = yield handler.subscribe(
                lambda: event0.callback(42), u'com.myapp.topic1')
            subscription1 = yield handler.subscribe(
                lambda: event1.callback('foo'), u'com.myapp.topic1')

            self.assertTrue(subscription0.id == subscription1.id)
            yield subscription0.unsubscribe()
            yield subscription1.unsubscribe()

            # after the second unsubscribe, we should have gotten an
            # Unsubscribed message
            assert unsubscribed_d.called

            # do a publish (MockTransport fakes the acknowledgement
            # message) and then do an actual publish event. Sending
            # the Event should be an error, as we have no
            # subscriptions left.
            publish = yield handler.publish(
                u'com.myapp.topic1',
                options=types.PublishOptions(acknowledge=True,
                                             exclude_me=False),
            )
            try:
                handler.onMessage(message.Event(subscription0.id, publish.id))
                self.fail("Expected ProtocolError")
            except ProtocolError:
                pass

            # since we unsubscribed the second event handler, we
            # should NOT have called its callback
            self.assertTrue(not event0.called, "First callback fired.")
            self.assertTrue(not event1.called, "Second callback fired.")
Пример #7
0
                def _get_retained_event():

                    if subscription.extra.retained_events:
                        retained_events = list(
                            subscription.extra.retained_events)
                        retained_events.reverse()

                        for publish in retained_events:
                            authorised = False

                            if not publish.exclude and not publish.eligible:
                                authorised = True
                            elif session._session_id in publish.eligible and session._session_id not in publish.exclude:
                                authorised = True

                            if authorised:
                                publication = util.id()

                                if publish.payload:
                                    msg = message.Event(
                                        subscription.id,
                                        publication,
                                        payload=publish.payload,
                                        retained=True,
                                        enc_algo=publish.enc_algo,
                                        enc_key=publish.enc_key,
                                        enc_serializer=publish.enc_serializer)
                                else:
                                    msg = message.Event(subscription.id,
                                                        publication,
                                                        args=publish.args,
                                                        kwargs=publish.kwargs,
                                                        retained=True)

                                return [msg]
                    return []
Пример #8
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', ))
Пример #9
0
        def test_publish_callback_exception(self):
            """
            Ensure we handle an exception from the user code.
            """
            handler = ApplicationSession()
            MockTransport(handler)

            error_instance = RuntimeError("we have a problem")
            got_err_d = Deferred()

            def observer(kw):
                if kw['isError'] and 'failure' in kw:
                    fail = kw['failure']
                    fail.trap(RuntimeError)
                    if error_instance == fail.value:
                        got_err_d.callback(True)

            log.addObserver(observer)

            def boom():
                raise error_instance

            try:
                sub = yield handler.subscribe(boom, u'com.myapp.topic1')

                # 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),
                )
                msg = message.Event(sub.id, publish.id)
                handler.onMessage(msg)

                # we know it worked if our observer worked and did
                # .callback on our Deferred above.
                self.assertTrue(got_err_d.called)
                # ...otherwise trial will fail the test anyway
                self.flushLoggedErrors()

            finally:
                log.removeObserver(observer)
Пример #10
0
        def test_double_subscribe_single_unsubscribe(self):
            '''
            Make sure we correctly deal with unsubscribing one of our handlers
            from the same topic.
            '''
            handler = ApplicationSession()
            MockTransport(handler)

            # monkey-patch ApplicationSession to ensure we DO NOT get
            # an Unsubscribed message -- since we only unsubscribe
            # from ONE of our handlers for com.myapp.topic1
            def onMessage(msg):
                assert not isinstance(msg, message.Unsubscribed)
                return ApplicationSession.onMessage(handler, msg)

            handler.onMessage = onMessage

            event0 = Deferred()
            event1 = Deferred()

            subscription0 = yield handler.subscribe(
                lambda: event0.callback(42), u'com.myapp.topic1')
            subscription1 = yield handler.subscribe(
                lambda: event1.callback('foo'), u'com.myapp.topic1')

            self.assertTrue(subscription0.id == subscription1.id)
            yield subscription1.unsubscribe()

            # do a publish (MockTransport fakes the acknowledgement
            # message) and then do an actual publish event. Note the
            # IDs are the same, so there's only one Event.
            publish = yield handler.publish(
                u'com.myapp.topic1',
                options=types.PublishOptions(acknowledge=True,
                                             exclude_me=False),
            )
            handler.onMessage(message.Event(subscription0.id, publish.id))

            # since we unsubscribed the second event handler, we
            # should NOT have called its callback
            self.assertTrue(event0.called, "Missing callback")
            self.assertTrue(not event1.called, "Second callback fired.")
    def test_basic(self):
        messages = [
            message.Event(123456,
                          789123,
                          args=[1, 2, 3],
                          kwargs={
                              'foo': 23,
                              'bar': 'hello'
                          },
                          publisher=666,
                          retained=True),
            message.Publish(123456,
                            'com.example.topic1',
                            args=[1, 2, 3],
                            kwargs={
                                'foo': 23,
                                'bar': 'hello'
                            },
                            retain=True)
        ]

        ser = serializer.FlatBuffersSerializer()

        # from pprint import pprint

        for msg in messages:

            # serialize message
            payload, binary = ser.serialize(msg)

            # unserialize message again
            msg2 = ser.unserialize(payload, binary)[0]

            # pprint(msg.marshal())
            # pprint(msg2.marshal())

            # must be equal: message roundtrips via the serializer
            self.assertEqual(msg, msg2)
Пример #12
0
            def on_authorize_success(authorized):

                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorized:

                    if publish.acknowledge:
                        reply = message.Error(
                            message.Publish.MESSAGE_TYPE, publish.request,
                            ApplicationError.NOT_AUTHORIZED, [
                                u"session not authorized to publish to topic '{0}'"
                                .format(publish.topic)
                            ])
                        session._transport.send(reply)

                else:

                    # new ID for the publication
                    #
                    publication = util.id()

                    # persist event
                    #
                    if store_event:
                        self._event_store.store_event(session._session_id,
                                                      publication,
                                                      publish.topic,
                                                      publish.args,
                                                      publish.kwargs)

                    # send publish acknowledge immediately when requested
                    #
                    if publish.acknowledge:
                        msg = message.Published(publish.request, publication)
                        session._transport.send(msg)

                    # publisher disclosure
                    #
                    if publish.disclose_me:
                        publisher = session._session_id
                    else:
                        publisher = None

                    # skip publisher
                    #
                    if publish.exclude_me is None or publish.exclude_me:
                        me_also = False
                    else:
                        me_also = True

                    # iterate over all subscriptions ..
                    #
                    for subscription in subscriptions:

                        # persist event history
                        #
                        if store_event:
                            self._event_store.store_event_history(
                                publication, subscription.id)

                        # initial list of receivers are all subscribers on a subscription ..
                        #
                        receivers = subscription.observers

                        # filter by "eligible" receivers
                        #
                        if publish.eligible:

                            # map eligible session IDs to eligible sessions
                            eligible = []
                            for session_id in publish.eligible:
                                if session_id in self._router._session_id_to_session:
                                    eligible.append(
                                        self._router.
                                        _session_id_to_session[session_id])

                            # filter receivers for eligible sessions
                            receivers = set(eligible) & receivers

                        # remove "excluded" receivers
                        #
                        if publish.exclude:

                            # map excluded session IDs to excluded sessions
                            exclude = []
                            for s in publish.exclude:
                                if s in self._router._session_id_to_session:
                                    exclude.append(
                                        self._router._session_id_to_session[s])

                            # filter receivers for excluded sessions
                            if exclude:
                                receivers = receivers - set(exclude)

                        # if receivers is non-empty, dispatch event ..
                        #
                        receivers_cnt = len(receivers) - (1 if self
                                                          in receivers else 0)
                        if receivers_cnt:

                            # for pattern-based subscriptions, the EVENT must contain
                            # the actual topic being published to
                            #
                            if subscription.match != message.Subscribe.MATCH_EXACT:
                                topic = publish.topic
                            else:
                                topic = None

                            msg = message.Event(subscription.id,
                                                publication,
                                                args=publish.args,
                                                kwargs=publish.kwargs,
                                                publisher=publisher,
                                                topic=topic)
                            for receiver in receivers:
                                if (me_also or receiver != session
                                    ) and receiver != self._event_store:
                                    # the receiving subscriber session
                                    # might have no transport, or no
                                    # longer be joined
                                    if receiver._session_id and receiver._transport:
                                        receiver._transport.send(msg)
Пример #13
0
    def processPublish(self, session, publish):
        """
      Implements :func:`autobahn.wamp.interfaces.IBroker.processPublish`
      """
        assert (session in self._session_to_subscriptions)

        ## check topic URI
        ##
        if (not self._option_uri_strict and not  _URI_PAT_LOOSE_NON_EMPTY.match(publish.topic)) or \
           (    self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(publish.topic)):

            if publish.acknowledge:
                reply = message.Error(
                    message.Publish.MESSAGE_TYPE, publish.request,
                    ApplicationError.INVALID_URI, [
                        "publish with invalid topic URI '{}'".format(
                            publish.topic)
                    ])
                session._transport.send(reply)

            return

        if publish.topic in self._topic_to_sessions and self._topic_to_sessions[
                publish.topic]:

            ## initial list of receivers are all subscribers ..
            ##
            subscription, receivers = self._topic_to_sessions[publish.topic]

            ## filter by "eligible" receivers
            ##
            if publish.eligible:
                eligible = []
                for s in publish.eligible:
                    if s in self._session_id_to_session:
                        eligible.append(self._session_id_to_session[s])
                if eligible:
                    receivers = set(eligible) & receivers

            ## remove "excluded" receivers
            ##
            if publish.exclude:
                exclude = []
                for s in publish.exclude:
                    if s in self._session_id_to_session:
                        exclude.append(self._session_id_to_session[s])
                if exclude:
                    receivers = receivers - set(exclude)

            ## remove publisher
            ##
            if publish.excludeMe is None or publish.excludeMe:
                #   receivers.discard(session) # bad: this would modify our actual subscriber list
                me_also = False
            else:
                me_also = True

        else:
            subscription, receivers, me_also = None, [], False

        publication = util.id()

        ## send publish acknowledge when requested
        ##
        if publish.acknowledge:
            msg = message.Published(publish.request, publication)
            session._transport.send(msg)

        ## if receivers is non-empty, dispatch event ..
        ##
        if receivers:
            if publish.discloseMe:
                publisher = session._session_id
            else:
                publisher = None
            msg = message.Event(subscription,
                                publication,
                                args=publish.args,
                                kwargs=publish.kwargs,
                                publisher=publisher)
            for receiver in receivers:
                if me_also or receiver != session:
                    ## the subscribing session might have been lost in the meantime ..
                    if receiver._transport:
                        receiver._transport.send(msg)
Пример #14
0
def generate_test_messages():
    """
    List of WAMP test message used for serializers. Expand this if you add more
    options or messages.

    This list of WAMP message does not contain any binary app payloads!
    """
    some_bytes = os.urandom(32)
    some_unicode = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c'

    some_uri = 'com.myapp.foobar'
    some_unicode_uri = 'com.myapp.\u4f60\u597d\u4e16\u754c.baz'

    some_args = [1, 2, 3, 'hello', some_bytes, some_unicode, {'foo': 23, 'bar': 'hello', 'baz': some_bytes, 'moo': some_unicode}]
    some_kwargs = {'foo': 23, 'bar': 'hello', 'baz': some_bytes, 'moo': some_unicode, 'arr': some_args}

    msgs = [
        message.Hello("realm1", {'subscriber': role.RoleSubscriberFeatures()}),
        message.Hello("realm1", {'publisher': role.RolePublisherFeatures()}),
        message.Hello("realm1", {'caller': role.RoleCallerFeatures()}),
        message.Hello("realm1", {'callee': role.RoleCalleeFeatures()}),
        message.Hello("realm1", {
            'subscriber': role.RoleSubscriberFeatures(),
            'publisher': role.RolePublisherFeatures(),
            'caller': role.RoleCallerFeatures(),
            'callee': role.RoleCalleeFeatures(),
        }),
        message.Goodbye(),
        message.Yield(123456),
        message.Yield(123456, args=some_args),
        message.Yield(123456, args=[], kwargs=some_kwargs),
        message.Yield(123456, args=some_args, kwargs=some_kwargs),
        message.Yield(123456, progress=True),
        message.Interrupt(123456),
        message.Interrupt(123456, mode=message.Interrupt.KILL),
        message.Invocation(123456, 789123),
        message.Invocation(123456, 789123, args=some_args),
        message.Invocation(123456, 789123, args=[], kwargs=some_kwargs),
        message.Invocation(123456, 789123, args=some_args, kwargs=some_kwargs),
        message.Invocation(123456, 789123, timeout=10000),
        message.Result(123456),
        message.Result(123456, args=some_args),
        message.Result(123456, args=[], kwargs=some_kwargs),
        message.Result(123456, args=some_args, kwargs=some_kwargs),
        message.Result(123456, progress=True),
        message.Cancel(123456),
        message.Cancel(123456, mode=message.Cancel.KILL),
        message.Call(123456, some_uri),
        message.Call(123456, some_uri, args=some_args),
        message.Call(123456, some_uri, args=[], kwargs=some_kwargs),
        message.Call(123456, some_uri, args=some_args, kwargs=some_kwargs),
        message.Call(123456, some_uri, timeout=10000),
        message.Call(123456, some_unicode_uri),
        message.Call(123456, some_unicode_uri, args=some_args),
        message.Call(123456, some_unicode_uri, args=[], kwargs=some_kwargs),
        message.Call(123456, some_unicode_uri, args=some_args, kwargs=some_kwargs),
        message.Call(123456, some_unicode_uri, timeout=10000),
        message.Unregistered(123456),
        message.Unregister(123456, 789123),
        message.Registered(123456, 789123),
        message.Register(123456, some_uri),
        message.Register(123456, some_uri, match='prefix'),
        message.Register(123456, some_uri, invoke='roundrobin'),
        message.Register(123456, some_unicode_uri),
        message.Register(123456, some_unicode_uri, match='prefix'),
        message.Register(123456, some_unicode_uri, invoke='roundrobin'),
        message.Event(123456, 789123),
        message.Event(123456, 789123, args=some_args),
        message.Event(123456, 789123, args=[], kwargs=some_kwargs),
        message.Event(123456, 789123, args=some_args, kwargs=some_kwargs),
        message.Event(123456, 789123, publisher=300),
        message.Published(123456, 789123),
        message.Publish(123456, some_uri),
        message.Publish(123456, some_uri, args=some_args),
        message.Publish(123456, some_uri, args=[], kwargs=some_kwargs),
        message.Publish(123456, some_uri, args=some_args, kwargs=some_kwargs),
        message.Publish(123456, some_uri, exclude_me=False, exclude=[300], eligible=[100, 200, 300]),
        message.Publish(123456, some_unicode_uri),
        message.Publish(123456, some_unicode_uri, args=some_args),
        message.Publish(123456, some_unicode_uri, args=[], kwargs=some_kwargs),
        message.Publish(123456, some_unicode_uri, args=some_args, kwargs=some_kwargs),
        message.Publish(123456, some_unicode_uri, exclude_me=False, exclude=[300], eligible=[100, 200, 300]),
        message.Unsubscribed(123456),
        message.Unsubscribe(123456, 789123),
        message.Subscribed(123456, 789123),
        message.Subscribe(123456, some_uri),
        message.Subscribe(123456, some_uri, match=message.Subscribe.MATCH_PREFIX),
        message.Subscribe(123456, some_unicode_uri),
        message.Subscribe(123456, some_unicode_uri, match=message.Subscribe.MATCH_PREFIX),
        message.Error(message.Call.MESSAGE_TYPE, 123456, some_uri),
        message.Error(message.Call.MESSAGE_TYPE, 123456, some_uri, args=some_args),
        message.Error(message.Call.MESSAGE_TYPE, 123456, some_uri, args=[], kwargs=some_kwargs),
        message.Error(message.Call.MESSAGE_TYPE, 123456, some_uri, args=some_args, kwargs=some_kwargs),
        message.Error(message.Call.MESSAGE_TYPE, 123456, some_unicode_uri),
        message.Error(message.Call.MESSAGE_TYPE, 123456, some_unicode_uri, args=some_args),
        message.Error(message.Call.MESSAGE_TYPE, 123456, some_unicode_uri, args=[], kwargs=some_kwargs),
        message.Error(message.Call.MESSAGE_TYPE, 123456, some_unicode_uri, args=some_args, kwargs=some_kwargs),
        message.Result(123456),
        message.Result(123456, args=some_args),
        message.Result(123456, args=some_args, kwargs=some_kwargs),
    ]
    return [(False, msg) for msg in msgs]
Пример #15
0
            def on_authorize_success(authorization):

                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorization[u'allow']:

                    if publish.acknowledge:
                        reply = message.Error(
                            message.Publish.MESSAGE_TYPE, publish.request,
                            ApplicationError.NOT_AUTHORIZED, [
                                u"session not authorized to publish to topic '{0}'"
                                .format(publish.topic)
                            ])
                        reply.correlation_id = publish.correlation_id
                        reply.correlation_uri = publish.topic
                        reply.correlation_is_anchor = False
                        reply.correlation_is_last = True
                        self._router.send(session, reply)

                else:

                    # new ID for the publication
                    #
                    publication = util.id()

                    # publisher disclosure
                    #
                    if authorization[u'disclose']:
                        disclose = True
                    elif (publish.topic.startswith(u"wamp.")
                          or publish.topic.startswith(u"crossbar.")):
                        disclose = True
                    else:
                        disclose = False

                    if disclose:
                        publisher = session._session_id
                        publisher_authid = session._authid
                        publisher_authrole = session._authrole
                    else:
                        publisher = None
                        publisher_authid = None
                        publisher_authrole = None

                    # skip publisher
                    #
                    if publish.exclude_me is None or publish.exclude_me:
                        me_also = False
                    else:
                        me_also = True

                    # persist event (this is done only once, regardless of the number of subscriptions
                    # the event matches on)
                    #
                    if store_event:
                        self._event_store.store_event(session._session_id,
                                                      publication,
                                                      publish.topic,
                                                      publish.args,
                                                      publish.kwargs)

                    # retain event on the topic
                    #
                    if retain_event:
                        retained_event = RetainedEvent(publish, publisher,
                                                       publisher_authid,
                                                       publisher_authrole)

                        observation = self._subscription_map.get_observation(
                            publish.topic)

                        if not observation:
                            # No observation, lets make a new one
                            observation = self._subscription_map.create_observation(
                                publish.topic, extra=SubscriptionExtra())
                        else:
                            # this can happen if event-history is
                            # enabled on the topic: the event-store
                            # creates an observation before any client
                            # could possible hit the code above
                            if observation.extra is None:
                                observation.extra = SubscriptionExtra()
                            elif not isinstance(observation.extra,
                                                SubscriptionExtra):
                                raise Exception(
                                    "incorrect 'extra' for '{}'".format(
                                        publish.topic))

                        if observation.extra.retained_events:
                            if not publish.eligible and not publish.exclude:
                                observation.extra.retained_events = [
                                    retained_event
                                ]
                            else:
                                observation.extra.retained_events.append(
                                    retained_event)
                        else:
                            observation.extra.retained_events = [
                                retained_event
                            ]

                    subscription_to_receivers = {}
                    total_receivers_cnt = 0

                    # iterate over all subscriptions and determine actual receivers of the event
                    # under the respective subscription. also persist events (independent of whether
                    # there is any actual receiver right now on the subscription)
                    #
                    for subscription in subscriptions:

                        # persist event history, but check if it is persisted on the individual subscription!
                        #
                        if store_event and self._event_store in subscription.observers:
                            self._event_store.store_event_history(
                                publication, subscription.id)

                        # initial list of receivers are all subscribers on a subscription ..
                        #
                        receivers = subscription.observers
                        receivers = self._filter_publish_receivers(
                            receivers, publish)

                        # if receivers is non-empty, dispatch event ..
                        #
                        receivers_cnt = len(receivers) - (1 if self
                                                          in receivers else 0)
                        if receivers_cnt:

                            total_receivers_cnt += receivers_cnt
                            subscription_to_receivers[subscription] = receivers

                    # send publish acknowledge before dispatching
                    #
                    if publish.acknowledge:
                        if self._router.is_traced:
                            publish.correlation_is_last = False

                        reply = message.Published(publish.request, publication)
                        reply.correlation_id = publish.correlation_id
                        reply.correlation_uri = publish.topic
                        reply.correlation_is_anchor = False
                        reply.correlation_is_last = total_receivers_cnt == 0
                        self._router.send(session, reply)
                    else:
                        if self._router.is_traced and publish.correlation_is_last is None:
                            if total_receivers_cnt == 0:
                                publish.correlation_is_last = True
                            else:
                                publish.correlation_is_last = False

                    # now actually dispatch the events!
                    # for chunked dispatching, this will be filled with deferreds for each chunk
                    # processed. when the complete list of deferreds is done, that means the
                    # event has been sent out to all applicable receivers
                    all_dl = []

                    if total_receivers_cnt:

                        # list of receivers that should have received the event, but we could not
                        # send the event, since the receiver has disappeared in the meantime
                        vanished_receivers = []

                        for subscription, receivers in subscription_to_receivers.items(
                        ):

                            self.log.debug(
                                'dispatching for subscription={subscription}',
                                subscription=subscription)

                            # for pattern-based subscriptions, the EVENT must contain
                            # the actual topic being published to
                            #
                            if subscription.match != message.Subscribe.MATCH_EXACT:
                                topic = publish.topic
                            else:
                                topic = None

                            if publish.payload:
                                msg = message.Event(
                                    subscription.id,
                                    publication,
                                    payload=publish.payload,
                                    publisher=publisher,
                                    publisher_authid=publisher_authid,
                                    publisher_authrole=publisher_authrole,
                                    topic=topic,
                                    enc_algo=publish.enc_algo,
                                    enc_key=publish.enc_key,
                                    enc_serializer=publish.enc_serializer)
                            else:
                                msg = message.Event(
                                    subscription.id,
                                    publication,
                                    args=publish.args,
                                    kwargs=publish.kwargs,
                                    publisher=publisher,
                                    publisher_authid=publisher_authid,
                                    publisher_authrole=publisher_authrole,
                                    topic=topic)

                            # if the publish message had a correlation ID, this will also be the
                            # correlation ID of the event message sent out
                            msg.correlation_id = publish.correlation_id
                            msg.correlation_uri = publish.topic
                            msg.correlation_is_anchor = False
                            msg.correlation_is_last = False

                            chunk_size = self._options.event_dispatching_chunk_size

                            if chunk_size and len(receivers) > chunk_size:
                                self.log.debug(
                                    'chunked dispatching to {receivers_size} with chunk_size={chunk_size}',
                                    receivers_size=len(receivers),
                                    chunk_size=chunk_size)
                            else:
                                self.log.debug(
                                    'unchunked dispatching to {receivers_size} receivers',
                                    receivers_size=len(receivers))

                            # note that we're using one code-path for both chunked and unchunked
                            # dispatches; the *first* chunk is always done "synchronously" (before
                            # the first call-later) so "un-chunked mode" really just means we know
                            # we'll be done right now and NOT do a call_later...

                            # a Deferred that fires when all chunks are done
                            all_d = txaio.create_future()
                            all_dl.append(all_d)

                            # all the event messages are the same except for the last one, which
                            # needs to have the "is_last" flag set if we're doing a trace
                            if self._router.is_traced:
                                last_msg = copy.deepcopy(msg)
                                last_msg.correlation_id = msg.correlation_id
                                last_msg.correlation_uri = msg.correlation_uri
                                last_msg.correlation_is_anchor = False
                                last_msg.correlation_is_last = True

                            def _notify_some(receivers):

                                # we do a first pass over the proposed chunk of receivers
                                # because not all of them will have a transport, and if this
                                # will be the last chunk of receivers we need to figure out
                                # which event is last...
                                receivers_this_chunk = []
                                for receiver in receivers[:chunk_size]:
                                    if (me_also or receiver != session
                                        ) and receiver != self._event_store:
                                        # the receiving subscriber session might have no transport,
                                        # or no longer be joined
                                        if receiver._session_id and receiver._transport:
                                            receivers_this_chunk.append(
                                                receiver)
                                        else:
                                            vanished_receivers.append(receiver)

                                receivers = receivers[chunk_size:]

                                # XXX note there's still going to be some edge-cases here .. if
                                # we are NOT the last chunk, but all the next chunk's receivers
                                # (could be only 1 in that chunk!) vanish before we run our next
                                # batch, then a "last" event will never go out ...

                                # we now actually do the deliveries, but now we know which
                                # receiver is the last one
                                if receivers or not self._router.is_traced:
                                    # NOT the last chunk (or we're not traced so don't care)
                                    for receiver in receivers_this_chunk:
                                        self._router.send(receiver, msg)
                                else:
                                    # last chunk, so last receiver gets the different message
                                    for receiver in receivers_this_chunk[:-1]:
                                        self._router.send(receiver, msg)
                                    # we might have zero valid receivers
                                    if receivers_this_chunk:
                                        self._router.send(
                                            receivers_this_chunk[-1], last_msg)

                                if receivers:
                                    # still more to do ..
                                    return txaio.call_later(
                                        0, _notify_some, receivers)
                                else:
                                    # all done! resolve all_d, which represents all receivers
                                    # to a single subscription matching the event
                                    txaio.resolve(all_d, None)

                            _notify_some(list(receivers))

                    return txaio.gather(all_dl)
Пример #16
0
    def send(self, msg):

        if self._log:
            print("req")
            print(msg)

        reply = None

        if isinstance(msg, message.Publish):
            if msg.topic in self._subscription_topics.keys():

                pubID = util.id()

                def published():
                    self._s(message.Published(msg.request, pubID))

                reg = self._subscription_topics[msg.topic]
                reply = message.Event(reg, pubID, args=msg.args, kwargs=msg.kwargs)

                if msg.acknowledge:
                    reactor.callLater(0, published)

            elif len(msg.topic) == 0:
                reply = message.Error(message.Publish.MESSAGE_TYPE, msg.request, u'wamp.error.invalid_uri')
            else:
                reply = message.Error(message.Publish.MESSAGE_TYPE, msg.request, u'wamp.error.not_authorized')

        elif isinstance(msg, message.Error):
            # Convert an invocation error into a call error
            if msg.request_type == 68:
                msg.request_type = 48

            reply = msg

        elif isinstance(msg, message.Call):
            if msg.procedure in self._registrations:
                request = util.id()
                registration = self._registrations[msg.procedure]
                self._invocations[msg.request] = msg.request

                def invoke():
                    self._s(message.Invocation(msg.request, registration, args=msg.args, kwargs=msg.kwargs))

                reactor.callLater(0, invoke)

            else:
                reply = message.Error(message.Call.MESSAGE_TYPE, msg.request, u'wamp.error.no_such_procedure')

        elif isinstance(msg, message.Yield):
            if msg.request in self._invocations:
                request = self._invocations[msg.request]
                reply = message.Result(request, args=msg.args, kwargs=msg.kwargs)

        elif isinstance(msg, message.Subscribe):
            topic = msg.topic
            if topic in self._subscription_topics:
                reply_id = self._subscription_topics[topic]
            else:
                reply_id = util.id()
                self._subscription_topics[topic] = reply_id
            reply = message.Subscribed(msg.request, reply_id)

        elif isinstance(msg, message.Unsubscribe):
            reply = message.Unsubscribed(msg.request)

        elif isinstance(msg, message.Register):
            registration = util.id()
            self._registrations[msg.procedure] = registration
            reply = message.Registered(msg.request, registration)

        elif isinstance(msg, message.Unregister):
            reply = message.Unregistered(msg.request)

        if reply:
            self._s(reply)
Пример #17
0
            def on_authorize_success(authorized):

                if not authorized:

                    if publish.acknowledge:
                        reply = message.Error(
                            message.Publish.MESSAGE_TYPE, publish.request,
                            ApplicationError.NOT_AUTHORIZED, [
                                "session not authorized to publish to topic '{0}'"
                                .format(publish.topic)
                            ])
                        session._transport.send(reply)

                else:

                    ## continue processing if either a) there are subscribers to the topic or b) the publish is to be acknowledged
                    ##
                    if publish.topic in self._topic_to_sessions and self._topic_to_sessions[
                            publish.topic]:

                        ## initial list of receivers are all subscribers ..
                        ##
                        subscription, receivers = self._topic_to_sessions[
                            publish.topic]

                        ## filter by "eligible" receivers
                        ##
                        if publish.eligible:
                            eligible = []
                            for s in publish.eligible:
                                if s in self._session_id_to_session:
                                    eligible.append(
                                        self._session_id_to_session[s])

                            receivers = set(eligible) & receivers

                        ## remove "excluded" receivers
                        ##
                        if publish.exclude:
                            exclude = []
                            for s in publish.exclude:
                                if s in self._session_id_to_session:
                                    exclude.append(
                                        self._session_id_to_session[s])
                            if exclude:
                                receivers = receivers - set(exclude)

                        ## remove publisher
                        ##
                        if publish.excludeMe is None or publish.excludeMe:
                            #   receivers.discard(session) # bad: this would modify our actual subscriber list
                            me_also = False
                        else:
                            me_also = True

                    else:
                        subscription, receivers, me_also = None, [], False

                    publication = util.id()

                    ## send publish acknowledge when requested
                    ##
                    if publish.acknowledge:
                        msg = message.Published(publish.request, publication)
                        session._transport.send(msg)

                    ## if receivers is non-empty, dispatch event ..
                    ##
                    if receivers:
                        if publish.discloseMe:
                            publisher = session._session_id
                        else:
                            publisher = None
                        msg = message.Event(subscription,
                                            publication,
                                            args=publish.args,
                                            kwargs=publish.kwargs,
                                            publisher=publisher)
                        for receiver in receivers:
                            if me_also or receiver != session:
                                ## the subscribing session might have been lost in the meantime ..
                                if receiver._transport:
                                    receiver._transport.send(msg)
Пример #18
0
def generate_test_messages():
    """
    List of WAMP test message used for serializers. Expand this if you add more
    options or messages.

    This list of WAMP message does not contain any binary app payloads!
    """
    msgs = [
        message.Hello(u"realm1",
                      {u'subscriber': role.RoleSubscriberFeatures()}),
        message.Goodbye(),
        message.Yield(123456),
        message.Yield(123456,
                      args=[1, 2, 3],
                      kwargs={
                          u'foo': 23,
                          u'bar': u'hello'
                      }),
        message.Yield(123456, args=[u'hello']),
        message.Yield(123456, progress=True),
        message.Interrupt(123456),
        message.Interrupt(123456, mode=message.Interrupt.KILL),
        message.Invocation(123456, 789123),
        message.Invocation(123456,
                           789123,
                           args=[1, 2, 3],
                           kwargs={
                               u'foo': 23,
                               u'bar': u'hello'
                           }),
        message.Invocation(123456, 789123, timeout=10000),
        message.Result(123456),
        message.Result(123456,
                       args=[1, 2, 3],
                       kwargs={
                           u'foo': 23,
                           u'bar': u'hello'
                       }),
        message.Result(123456, progress=True),
        message.Cancel(123456),
        message.Cancel(123456, mode=message.Cancel.KILL),
        message.Call(123456, u'com.myapp.procedure1'),
        message.Call(123456,
                     u'com.myapp.procedure1',
                     args=[1, 2, 3],
                     kwargs={
                         u'foo': 23,
                         u'bar': u'hello'
                     }),
        message.Call(123456, u'com.myapp.procedure1', timeout=10000),
        message.Unregistered(123456),
        message.Unregister(123456, 789123),
        message.Registered(123456, 789123),
        message.Register(123456, u'com.myapp.procedure1'),
        message.Register(123456, u'com.myapp.procedure1', match=u'prefix'),
        message.Register(123456, u'com.myapp.procedure1',
                         invoke=u'roundrobin'),
        message.Event(123456, 789123),
        message.Event(123456,
                      789123,
                      args=[1, 2, 3],
                      kwargs={
                          u'foo': 23,
                          u'bar': u'hello'
                      }),
        message.Event(123456, 789123, publisher=300),
        message.Published(123456, 789123),
        message.Publish(123456, u'com.myapp.topic1'),
        message.Publish(123456,
                        u'com.myapp.topic1',
                        args=[1, 2, 3],
                        kwargs={
                            u'foo': 23,
                            u'bar': u'hello'
                        }),
        message.Publish(123456,
                        u'com.myapp.topic1',
                        exclude_me=False,
                        exclude=[300],
                        eligible=[100, 200, 300]),
        message.Unsubscribed(123456),
        message.Unsubscribe(123456, 789123),
        message.Subscribed(123456, 789123),
        message.Subscribe(123456, u'com.myapp.topic1'),
        message.Subscribe(123456,
                          u'com.myapp.topic1',
                          match=message.Subscribe.MATCH_PREFIX),
        message.Error(message.Call.MESSAGE_TYPE, 123456, u'com.myapp.error1'),
        message.Error(message.Call.MESSAGE_TYPE,
                      123456,
                      u'com.myapp.error1',
                      args=[1, 2, 3],
                      kwargs={
                          u'foo': 23,
                          u'bar': u'hello'
                      }),
        message.Call(123456,
                     u'com.myapp.\u4f60\u597d\u4e16\u754c',
                     args=[1, 2, 3]),
        message.Result(123456,
                       args=[1, 2, 3],
                       kwargs={
                           u'en': u'Hello World',
                           u'jp': u'\u3053\u3093\u306b\u3061\u306f\u4e16\u754c'
                       })
    ]
    return [(False, msg) for msg in msgs]
Пример #19
0
            def on_authorize_success(authorization):

                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorization[u'allow']:

                    if publish.acknowledge:
                        reply = message.Error(message.Publish.MESSAGE_TYPE, publish.request, ApplicationError.NOT_AUTHORIZED, [u"session not authorized to publish to topic '{0}'".format(publish.topic)])
                        self._router.send(session, reply)

                else:

                    # new ID for the publication
                    #
                    publication = util.id()

                    # persist event (this is done only once, regardless of the number of subscriptions
                    # the event matches on)
                    #
                    if store_event:
                        self._event_store.store_event(session._session_id, publication, publish.topic, publish.args, publish.kwargs)

                    # retain event on the topic
                    #
                    if retain_event:
                        observation = self._subscription_map.get_observation(publish.topic)

                        if not observation:
                            # No observation, lets make a new one
                            observation = self._subscription_map.create_observation(publish.topic, extra=SubscriptionExtra())

                        if observation.extra.retained_events:
                            if not publish.eligible and not publish.exclude:
                                observation.extra.retained_events = [publish]
                            else:
                                observation.extra.retained_events.append(publish)
                        else:
                            observation.extra.retained_events = [publish]

                    # send publish acknowledge immediately when requested
                    #
                    if publish.acknowledge:
                        reply = message.Published(publish.request, publication)
                        self._router.send(session, reply)

                    # publisher disclosure
                    #
                    if authorization[u'disclose']:
                        disclose = True
                    elif (publish.topic.startswith(u"wamp.") or
                          publish.topic.startswith(u"crossbar.")):
                        disclose = True
                    else:
                        disclose = False

                    if disclose:
                        publisher = session._session_id
                        publisher_authid = session._authid
                        publisher_authrole = session._authrole
                    else:
                        publisher = None
                        publisher_authid = None
                        publisher_authrole = None

                    # skip publisher
                    #
                    if publish.exclude_me is None or publish.exclude_me:
                        me_also = False
                    else:
                        me_also = True

                    # iterate over all subscriptions ..
                    #
                    for subscription in subscriptions:

                        # persist event history, but check if it is persisted on the individual subscription!
                        #
                        if store_event and self._event_store in subscription.observers:
                            self._event_store.store_event_history(publication, subscription.id)

                        # initial list of receivers are all subscribers on a subscription ..
                        #
                        receivers = subscription.observers

                        # filter by "eligible" receivers
                        #
                        if publish.eligible:

                            # map eligible session IDs to eligible sessions
                            eligible = []
                            for session_id in publish.eligible:
                                if session_id in self._router._session_id_to_session:
                                    eligible.append(self._router._session_id_to_session[session_id])

                            # filter receivers for eligible sessions
                            receivers = set(eligible) & receivers

                        # remove "excluded" receivers
                        #
                        if publish.exclude:

                            # map excluded session IDs to excluded sessions
                            exclude = []
                            for s in publish.exclude:
                                if s in self._router._session_id_to_session:
                                    exclude.append(self._router._session_id_to_session[s])

                            # filter receivers for excluded sessions
                            if exclude:
                                receivers = receivers - set(exclude)

                        # if receivers is non-empty, dispatch event ..
                        #
                        receivers_cnt = len(receivers) - (1 if self in receivers else 0)
                        if receivers_cnt:

                            # for pattern-based subscriptions, the EVENT must contain
                            # the actual topic being published to
                            #
                            if subscription.match != message.Subscribe.MATCH_EXACT:
                                topic = publish.topic
                            else:
                                topic = None

                            if publish.payload:
                                msg = message.Event(subscription.id,
                                                    publication,
                                                    payload=publish.payload,
                                                    publisher=publisher,
                                                    publisher_authid=publisher_authid,
                                                    publisher_authrole=publisher_authrole,
                                                    topic=topic,
                                                    enc_algo=publish.enc_algo,
                                                    enc_key=publish.enc_key,
                                                    enc_serializer=publish.enc_serializer)
                            else:
                                msg = message.Event(subscription.id,
                                                    publication,
                                                    args=publish.args,
                                                    kwargs=publish.kwargs,
                                                    publisher=publisher,
                                                    publisher_authid=publisher_authid,
                                                    publisher_authrole=publisher_authrole,
                                                    topic=topic)
                            for receiver in receivers:
                                if (me_also or receiver != session) and receiver != self._event_store:
                                    # the receiving subscriber session
                                    # might have no transport, or no
                                    # longer be joined
                                    if receiver._session_id and receiver._transport:
                                        self._router.send(receiver, msg)
Пример #20
0
            def on_authorize_success(authorization):

                # the call to authorize the action _itself_ succeeded. now go on depending on whether
                # the action was actually authorized or not ..
                #
                if not authorization[u'allow']:

                    if publish.acknowledge:
                        reply = message.Error(
                            message.Publish.MESSAGE_TYPE, publish.request,
                            ApplicationError.NOT_AUTHORIZED, [
                                u"session not authorized to publish to topic '{0}'"
                                .format(publish.topic)
                            ])
                        self._router.send(session, reply)

                else:

                    # new ID for the publication
                    #
                    publication = util.id()

                    # send publish acknowledge immediately when requested
                    #
                    if publish.acknowledge:
                        reply = message.Published(publish.request, publication)
                        self._router.send(session, reply)

                    # publisher disclosure
                    #
                    if authorization[u'disclose']:
                        disclose = True
                    elif (publish.topic.startswith(u"wamp.")
                          or publish.topic.startswith(u"crossbar.")):
                        disclose = True
                    else:
                        disclose = False

                    if disclose:
                        publisher = session._session_id
                        publisher_authid = session._authid
                        publisher_authrole = session._authrole
                    else:
                        publisher = None
                        publisher_authid = None
                        publisher_authrole = None

                    # skip publisher
                    #
                    if publish.exclude_me is None or publish.exclude_me:
                        me_also = False
                    else:
                        me_also = True

                    # persist event (this is done only once, regardless of the number of subscriptions
                    # the event matches on)
                    #
                    if store_event:
                        self._event_store.store_event(session._session_id,
                                                      publication,
                                                      publish.topic,
                                                      publish.args,
                                                      publish.kwargs)

                    # retain event on the topic
                    #
                    if retain_event:
                        retained_event = RetainedEvent(publish, publisher,
                                                       publisher_authid,
                                                       publisher_authrole)

                        observation = self._subscription_map.get_observation(
                            publish.topic)

                        if not observation:
                            # No observation, lets make a new one
                            observation = self._subscription_map.create_observation(
                                publish.topic, extra=SubscriptionExtra())
                        else:
                            # this can happen if event-history is
                            # enabled on the topic: the event-store
                            # creates an observation before any client
                            # could possible hit the code above
                            if observation.extra is None:
                                observation.extra = SubscriptionExtra()
                            elif not isinstance(observation.extra,
                                                SubscriptionExtra):
                                raise Exception(
                                    "incorrect 'extra' for '{}'".format(
                                        publish.topic))

                        if observation.extra.retained_events:
                            if not publish.eligible and not publish.exclude:
                                observation.extra.retained_events = [
                                    retained_event
                                ]
                            else:
                                observation.extra.retained_events.append(
                                    retained_event)
                        else:
                            observation.extra.retained_events = [
                                retained_event
                            ]

                    all_dl = []

                    # iterate over all subscriptions ..
                    #
                    for subscription in subscriptions:

                        self.log.debug(
                            'dispatching for subscription={subscription}',
                            subscription=subscription)

                        # persist event history, but check if it is persisted on the individual subscription!
                        #
                        if store_event and self._event_store in subscription.observers:
                            self._event_store.store_event_history(
                                publication, subscription.id)

                        # initial list of receivers are all subscribers on a subscription ..
                        #
                        receivers = subscription.observers
                        receivers = self._filter_publish_receivers(
                            receivers, publish)

                        # if receivers is non-empty, dispatch event ..
                        #
                        receivers_cnt = len(receivers) - (1 if self
                                                          in receivers else 0)
                        if receivers_cnt:

                            # for pattern-based subscriptions, the EVENT must contain
                            # the actual topic being published to
                            #
                            if subscription.match != message.Subscribe.MATCH_EXACT:
                                topic = publish.topic
                            else:
                                topic = None

                            if publish.payload:
                                msg = message.Event(
                                    subscription.id,
                                    publication,
                                    payload=publish.payload,
                                    publisher=publisher,
                                    publisher_authid=publisher_authid,
                                    publisher_authrole=publisher_authrole,
                                    topic=topic,
                                    enc_algo=publish.enc_algo,
                                    enc_key=publish.enc_key,
                                    enc_serializer=publish.enc_serializer)
                            else:
                                msg = message.Event(
                                    subscription.id,
                                    publication,
                                    args=publish.args,
                                    kwargs=publish.kwargs,
                                    publisher=publisher,
                                    publisher_authid=publisher_authid,
                                    publisher_authrole=publisher_authrole,
                                    topic=topic)

                            chunk_size = self._options.event_dispatching_chunk_size

                            if chunk_size:
                                self.log.debug(
                                    'chunked dispatching to {receivers_size} with chunk_size={chunk_size}',
                                    receivers_size=len(receivers),
                                    chunk_size=chunk_size)

                                # a Deferred that fires when all chunks are done
                                all_d = txaio.create_future()
                                all_dl.append(all_d)

                                def _notify_some(receivers):
                                    for receiver in receivers[:chunk_size]:
                                        if (
                                                me_also or receiver != session
                                        ) and receiver != self._event_store:
                                            # the receiving subscriber session
                                            # might have no transport, or no
                                            # longer be joined
                                            if receiver._session_id and receiver._transport:
                                                self._router.send(
                                                    receiver, msg)
                                    receivers = receivers[chunk_size:]
                                    if len(receivers) > 0:
                                        # still more to do ..
                                        return txaio.call_later(
                                            0, _notify_some, receivers)
                                    else:
                                        # all done! resolve all_d, which represents all receivers
                                        # to a single subscription matching the event
                                        txaio.resolve(all_d, None)

                                _notify_some(list(receivers))
                            else:
                                self.log.debug(
                                    'unchunked dispatching to {receivers_size} receivers',
                                    receivers_size=len(receivers))

                                for receiver in receivers:
                                    if (me_also or receiver != session
                                        ) and receiver != self._event_store:
                                        # the receiving subscriber session
                                        # might have no transport, or no
                                        # longer be joined
                                        if receiver._session_id and receiver._transport:
                                            self._router.send(receiver, msg)

                    return txaio.gather(all_dl)