def test_ctor(self): e = message.Published(123456, 789123) msg = e.marshal() self.assertEqual(len(msg), 3) self.assertEqual(msg[0], message.Published.MESSAGE_TYPE) self.assertEqual(msg[1], 123456) self.assertEqual(msg[2], 789123)
def send(self, msg): if self._log: payload, isbinary = self._serializer.serialize(msg) print("Send: {}".format(payload)) reply = None if isinstance(msg, message.Publish): if msg.topic.startswith(u'com.myapp'): if msg.acknowledge: reply = message.Published(msg.request, util.id()) 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.Call): if msg.procedure == u'com.myapp.procedure1': reply = message.Result(msg.request, args = [100]) elif msg.procedure == u'com.myapp.procedure2': reply = message.Result(msg.request, args = [1, 2, 3]) elif msg.procedure == u'com.myapp.procedure3': reply = message.Result(msg.request, args = [1, 2, 3], kwargs = {u'foo': u'bar', u'baz': 23}) elif msg.procedure.startswith(u'com.myapp.myproc'): registration = self._registrations[msg.procedure] request = util.id() self._invocations[request] = msg.request reply = message.Invocation(request, registration, args = msg.args, kwargs = msg.kwargs) else: reply = message.Error(message.Call.MESSAGE_TYPE, msg.request, u'wamp.error.no_such_procedure') elif isinstance(msg, message.Yield): if self._invocations.has_key(msg.request): request = self._invocations[msg.request] reply = message.Result(request, args = msg.args, kwargs = msg.kwargs) elif isinstance(msg, message.Subscribe): reply = message.Subscribed(msg.request, util.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: if self._log: payload, isbinary = self._serializer.serialize(reply) print("Receive: {}".format(payload)) self._handler.onMessage(reply)
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]
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'}) ]
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)
def send(self, msg): if self._log: payload, isbinary = self._serializer.serialize(msg) print("Send: {0}".format(payload)) reply = None if isinstance(msg, message.Publish): if msg.topic.startswith(u'com.myapp'): if msg.acknowledge: reply = message.Published( msg.request, self._fake_router_session._request_id_gen.next()) 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.Call): if msg.procedure == u'com.myapp.procedure1': reply = message.Result(msg.request, args=[100]) elif msg.procedure == u'com.myapp.procedure2': reply = message.Result(msg.request, args=[1, 2, 3]) elif msg.procedure == u'com.myapp.procedure3': reply = message.Result(msg.request, args=[1, 2, 3], kwargs={ u'foo': u'bar', u'baz': 23 }) elif msg.procedure.startswith(u'com.myapp.myproc'): registration = self._registrations[msg.procedure] request = self._fake_router_session._request_id_gen.next() if request in self._invocations: raise ProtocolError("duplicate invocation") self._invocations[request] = msg.request reply = message.Invocation( request, registration, args=msg.args, kwargs=msg.kwargs, receive_progress=msg.receive_progress, ) 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, progress=msg.progress) elif isinstance(msg, message.Subscribe): topic = msg.topic if topic in self._subscription_topics: reply_id = self._subscription_topics[topic] else: reply_id = self._fake_router_session._request_id_gen.next() 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 = self._fake_router_session._request_id_gen.next() self._registrations[msg.procedure] = registration reply = message.Registered(msg.request, registration) elif isinstance(msg, message.Unregister): reply = message.Unregistered(msg.request) elif isinstance(msg, message.Error): # since I'm basically a Dealer, I forward on the # error, but reply to my own request/invocation request = self._invocations[msg.request] reply = message.Error( message.Call.MESSAGE_TYPE, request, msg.error, args=msg.args, kwargs=msg.kwargs, ) if reply: if self._log: payload, isbinary = self._serializer.serialize(reply) print("Receive: {0}".format(payload)) self._handler.onMessage(reply)
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]
def published(): self._s(message.Published(msg.request, pubID))
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)
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)
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)
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)
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)