def send(self, msg): if self._log: bytes, isbinary = self._serializer.serialize(msg) print("Send: {}".format(bytes)) 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_topic') 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: bytes, isbinary = self._serializer.serialize(reply) print("Receive: {}".format(bytes)) self._handler.onMessage(reply)
def __init__(self, uri, ordered=False, extra=None): """ :param uri: The URI (or URI pattern) for this observation. :type uri: unicode """ # URI (or URI pattern) this observation is created for self.uri = uri # flag indicating whether observers should be maintained # in an ordered set or a regular, unordered set self.ordered = ordered # arbitrary, opaque extra data attached to the observation self.extra = extra # generate a new ID for the observation self.id = util.id() # UTC timestamp this observation was created self.created = util.utcnow() # set of observers if self.ordered: self.observers = OrderedSet() else: self.observers = set() # arbitrary, opaque extra data attached to the observers of this observation self.observers_extra = {}
def _unsubscribe(self, subscription): """ Called from :meth:`autobahn.wamp.protocol.Subscription.unsubscribe` """ assert (isinstance(subscription, Subscription)) assert subscription.active assert (subscription.id in self._subscriptions) assert (subscription in self._subscriptions[subscription.id]) if not self._transport: raise exception.TransportLost() # remove handler subscription and mark as inactive self._subscriptions[subscription.id].remove(subscription) subscription.active = False # number of handler subscriptions left .. scount = len(self._subscriptions[subscription.id]) if scount == 0: # if the last handler was removed, unsubscribe from broker .. request_id = util.id() on_reply = txaio.create_future() self._unsubscribe_reqs[request_id] = UnsubscribeRequest( request_id, on_reply, subscription.id) msg = message.Unsubscribe(request_id, subscription.id) self._transport.send(msg) return on_reply else: # there are still handlers active on the subscription! return txaio.create_future_success(scount)
def call(self, procedure, *args, **kwargs): """ Implements :func:`autobahn.wamp.interfaces.ICaller.call` """ if six.PY2 and type(procedure) == str: procedure = six.u(procedure) assert(isinstance(procedure, six.text_type)) if not self._transport: raise exception.TransportLost() request = util.id() if 'options' in kwargs and isinstance(kwargs['options'], types.CallOptions): opts = kwargs.pop('options') msg = message.Call(request, procedure, args = args, kwargs = kwargs, **opts.options) else: opts = None msg = message.Call(request, procedure, args = args, kwargs = kwargs) ## FIXME #def canceller(_d): # cancel_msg = message.Cancel(request) # self._transport.send(cancel_msg) #d = Deferred(canceller) d = self._create_future() self._call_reqs[request] = d, opts self._transport.send(msg) return d
def process_will(res): akw = mqtt_payload_transform( self._wamp_session._router._mqtt_payload_format, packet.will_message) if not akw: # Drop it I guess :( return res args, kwargs = akw msg = message.Call( request=util.id(), procedure=u"wamp.session.add_testament", args=[ u".".join(tokenise_mqtt_topic(packet.will_topic)), args, kwargs, { "retain": bool(packet.flags.will_retain) } ]) self._wamp_session.onMessage(msg) return res
def publish(self, topic, *args, **kwargs): """ Implements :func:`autobahn.wamp.interfaces.IPublisher.publish` """ if six.PY2 and type(topic) == str: topic = six.u(topic) assert(type(topic) == six.text_type) if not self._transport: raise exception.TransportLost() request = util.id() if 'options' in kwargs and isinstance(kwargs['options'], types.PublishOptions): opts = kwargs.pop('options') msg = message.Publish(request, topic, args = args, kwargs = kwargs, **opts.options) else: opts = None msg = message.Publish(request, topic, args = args, kwargs = kwargs) if opts and opts.options['acknowledge'] == True: d = self._create_future() self._publish_reqs[request] = d, opts self._transport.send(msg) return d else: self._transport.send(msg) return
def processRegister(self, session, register): """ Implements :func:`autobahn.wamp.interfaces.IDealer.processRegister` """ assert(session in self._session_to_registrations) ## check topic URI ## if self._option_uri_strict and not _URI_PAT_STRICT.match(register.procedure): reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.INVALID_URI) else: if not register.procedure in self._procs_to_regs: registration_id = util.id() self._procs_to_regs[register.procedure] = (registration_id, session) self._regs_to_procs[registration_id] = register.procedure self._session_to_registrations[session].add(registration_id) reply = message.Registered(register.request, registration_id) else: reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.PROCEDURE_ALREADY_EXISTS) session._transport.send(reply)
def processCall(self, session, call): """ Implements :func:`autobahn.wamp.interfaces.IDealer.processCall` """ assert(session in self._session_to_registrations) if call.procedure in self._procs_to_regs: registration_id, endpoint_session = self._procs_to_regs[call.procedure] request_id = util.id() if call.discloseMe: caller = session._session_id else: caller = None invocation = message.Invocation(request_id, registration_id, args = call.args, kwargs = call.kwargs, timeout = call.timeout, receive_progress = call.receive_progress, caller = caller) self._invocations[request_id] = (call, session) endpoint_session._transport.send(invocation) else: reply = message.Error(message.Call.MESSAGE_TYPE, call.request, 'wamp.error.no_such_procedure') session._transport.send(reply)
def on_authorize_success(authorized): if not authorized: reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.NOT_AUTHORIZED, ["session is not authorized to subscribe to topic '{0}'".format(subscribe.topic)]) else: if not subscribe.topic in self._topic_to_sessions: subscription = util.id() self._topic_to_sessions[subscribe.topic] = (subscription, set()) subscription, subscribers = self._topic_to_sessions[subscribe.topic] if not session in subscribers: subscribers.add(session) if not subscription in self._subscription_to_sessions: self._subscription_to_sessions[subscription] = (subscribe.topic, set()) _, subscribers = self._subscription_to_sessions[subscription] if not session in subscribers: subscribers.add(session) if not subscription in self._session_to_subscriptions[session]: self._session_to_subscriptions[session].add(subscription) reply = message.Subscribed(subscribe.request, subscription) session._transport.send(reply)
def _unsubscribe(self, subscription): """ Called from :meth:`autobahn.wamp.protocol.Subscription.unsubscribe` """ assert(isinstance(subscription, Subscription)) assert subscription.active assert(subscription.id in self._subscriptions) assert(subscription in self._subscriptions[subscription.id]) if not self._transport: raise exception.TransportLost() # remove handler subscription and mark as inactive self._subscriptions[subscription.id].remove(subscription) subscription.active = False # number of handler subscriptions left .. scount = len(self._subscriptions[subscription.id]) if scount == 0: # if the last handler was removed, unsubscribe from broker .. request_id = util.id() on_reply = txaio.create_future() self._unsubscribe_reqs[request_id] = UnsubscribeRequest(request_id, on_reply, subscription.id) msg = message.Unsubscribe(request_id, subscription.id) self._transport.send(msg) return on_reply else: # there are still handlers active on the subscription! return txaio.create_future_success(scount)
def __init__(self, uri, ordered=False, extra=None): """ :param uri: The URI (or URI pattern) for this observation. :type uri: unicode """ # URI (or URI pattern) this observation is created for self.uri = uri # flag indicating whether observers should be maintained # in an ordered set or a regular, unordered set self.ordered = ordered # arbitrary, opaque extra data attached to the observation self.extra = extra # generate a new ID for the observation self.id = util.id() # UTC timestamp this observation was created self.created = util.utcnow() # set of observers if self.ordered: self.observers = OrderedSet() else: self.observers = set()
def on_authorize(authorized): if authorized: registration_id, endpoint_session, discloseCaller = self._procs_to_regs[call.procedure] request_id = util.id() if discloseCaller or call.discloseMe: caller = session._session_id authid = session._authid authrole = session._authrole authmethod = session._authmethod else: caller = None authid = None authrole = None authmethod = None invocation = message.Invocation(request_id, registration_id, args = call.args, kwargs = call.kwargs, timeout = call.timeout, receive_progress = call.receive_progress, caller = caller, authid = authid, authrole = authrole, authmethod = authmethod) self._invocations[request_id] = (call, session) endpoint_session._transport.send(invocation) else: reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.NOT_AUTHORIZED, ["session is not authorized to call procedure '{}'".format(call.procedure)]) session._transport.send(reply)
def call(self, procedure, *args, **kwargs): """ Implements :func:`autobahn.wamp.interfaces.ICaller.call` """ assert(type(procedure) in (str, unicode)) if not self._transport: raise exception.TransportLost() request = util.id() if 'options' in kwargs and isinstance(kwargs['options'], types.CallOptions): opts = kwargs.pop('options') msg = message.Call(request, procedure, args = args, kwargs = kwargs, **opts.options) else: opts = None msg = message.Call(request, procedure, args = args, kwargs = kwargs) def canceller(_d): cancel_msg = message.Cancel(request) self._transport.send(cancel_msg) d = Deferred(canceller) self._call_reqs[request] = d, opts self._transport.send(msg) return d
def _publish(self, event, acknowledge=None): """ Given a MQTT event, create a WAMP Publish message and forward that on the forwarding WAMP session. """ try: payload_format, mapped_topic, options = yield self.factory.transform_mqtt(event.topic_name, event.payload) except: self.log.failure() return request = util.id() msg = message.Publish( request=request, topic=mapped_topic, exclude_me=False, acknowledge=acknowledge, retain=event.retain, **options) self._wamp_session.onMessage(msg) if event.qos_level > 0: self._request_to_packetid[request] = event.packet_identifier returnValue(0)
def process_will(res): self.log.info() payload_format, mapped_topic, options = yield self.factory.transform_mqtt(packet.will_topic, packet.will_message) request = util.id() msg = message.Call( request=request, procedure=u"wamp.session.add_testament", args=[ mapped_topic, options.get('args', None), options.get('kwargs', None), { # specifiy "retain" for when the testament (last will) # will be auto-published by the broker later u'retain': bool(packet.flags.will_retain) } ]) self._wamp_session.onMessage(msg) returnValue(res)
def processSubscribe(self, session, subscribe): """ Implements :func:`autobahn.wamp.interfaces.IBroker.processSubscribe` """ assert(session in self._session_to_subscriptions) if True: if not subscribe.topic in self._topic_to_sessions: subscription = util.id() self._topic_to_sessions[subscribe.topic] = (subscription, set()) subscription, subscribers = self._topic_to_sessions[subscribe.topic] if not session in subscribers: subscribers.add(session) if not subscription in self._subscription_to_sessions: self._subscription_to_sessions[subscription] = (subscribe.topic, set()) _, subscribers = self._subscription_to_sessions[subscription] if not session in subscribers: subscribers.add(session) if not subscription in self._session_to_subscriptions[session]: self._session_to_subscriptions[session].add(subscription) reply = message.Subscribed(subscribe.request, subscription) else: reply = message.Error(message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.INVALID_TOPIC) session._transport.send(reply)
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 []
def processRegister(self, session, register): """ Implements :func:`autobahn.wamp.interfaces.IDealer.processRegister` """ assert(session in self._session_to_registrations) ## check procedure URI ## if (not self._option_uri_strict and not _URI_PAT_LOOSE_NON_EMPTY.match(register.procedure)) or \ ( self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(register.procedure)): reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.INVALID_URI, ["register for invalid procedure URI '{}'".format(register.procedure)]) else: if not register.procedure in self._procs_to_regs: registration_id = util.id() self._procs_to_regs[register.procedure] = (registration_id, session, register.discloseCaller) self._regs_to_procs[registration_id] = register.procedure self._session_to_registrations[session].add(registration_id) reply = message.Registered(register.request, registration_id) else: reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.PROCEDURE_ALREADY_EXISTS, ["register for already registered procedure URI '{}'".format(register.procedure)]) session._transport.send(reply)
def onMessage(self, msg): """ Implements :func:`autobahn.wamp.interfaces.ITransportHandler.onMessage` """ if self._session_id is None: ## the first message MUST be HELLO if isinstance(msg, message.Hello): self._session_id = util.id() self._goodbye_sent = False self._router = self._router_factory.get(msg.realm) if not self._router: raise Exception("no such realm") roles = [] self._router.attach(self) roles.append(role.RoleBrokerFeatures()) roles.append(role.RoleDealerFeatures()) msg = message.Welcome(self._session_id, roles) self._transport.send(msg) self.onJoin(SessionDetails(self._session_id)) else: raise ProtocolError("Received {} message, and session is not yet established".format(msg.__class__)) else: if isinstance(msg, message.Hello): raise ProtocolError("HELLO message received, while session is already established") elif isinstance(msg, message.Goodbye): if not self._goodbye_sent: ## the peer wants to close: send GOODBYE reply reply = message.Goodbye() self._transport.send(reply) ## fire callback and close the transport self.onLeave(types.CloseDetails(msg.reason, msg.message)) self._router.detach(self) self._session_id = None #self._transport.close() elif isinstance(msg, message.Heartbeat): pass ## FIXME else: self._router.process(self, msg)
def processCall(self, session, call): """ Implements :func:`autobahn.wamp.interfaces.IDealer.processCall` """ assert (session in self._session_to_registrations) ## check procedure URI ## if (not self._option_uri_strict and not _URI_PAT_LOOSE_NON_EMPTY.match(call.procedure)) or \ ( self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(call.procedure)): reply = message.Error( message.Register.MESSAGE_TYPE, call.request, ApplicationError.INVALID_URI, [ "call with invalid procedure URI '{}'".format( call.procedure) ]) session._transport.send(reply) else: if call.procedure in self._procs_to_regs: registration_id, endpoint_session, discloseCaller = self._procs_to_regs[ call.procedure] request_id = util.id() if discloseCaller or call.discloseMe: caller = session._session_id authid = session._authid authrole = session._authrole authmethod = session._authmethod else: caller = None authid = None authrole = None authmethod = None invocation = message.Invocation( request_id, registration_id, args=call.args, kwargs=call.kwargs, timeout=call.timeout, receive_progress=call.receive_progress, caller=caller, authid=authid, authrole=authrole, authmethod=authmethod) self._invocations[request_id] = (call, session) endpoint_session._transport.send(invocation) else: reply = message.Error( message.Call.MESSAGE_TYPE, call.request, ApplicationError.NO_SUCH_PROCEDURE, ["no procedure '{}' registered".format(call.procedure)]) session._transport.send(reply)
def send(self, msg): """ Implements :func:`autobahn.wamp.interfaces.ITransport.send` """ if isinstance(msg, message.Hello): self._router = self._routerFactory.get(msg.realm) ## fake session ID assignment (normally done in WAMP opening handshake) self._session._session_id = util.id() ## add app session to router self._router.attach(self._session) ## fake app session open ## self._session.onJoin(SessionDetails(self._session._session_id)) ## app-to-router ## elif isinstance(msg, message.Publish) or \ isinstance(msg, message.Subscribe) or \ isinstance(msg, message.Unsubscribe) or \ isinstance(msg, message.Call) or \ isinstance(msg, message.Yield) or \ isinstance(msg, message.Register) or \ isinstance(msg, message.Unregister) or \ isinstance(msg, message.Cancel) or \ (isinstance(msg, message.Error) and msg.request_type == message.Invocation.MESSAGE_TYPE): ## deliver message to router ## self._router.process(self._session, msg) ## router-to-app ## elif isinstance(msg, message.Event) or \ isinstance(msg, message.Invocation) or \ isinstance(msg, message.Result) or \ isinstance(msg, message.Published) or \ isinstance(msg, message.Subscribed) or \ isinstance(msg, message.Unsubscribed) or \ isinstance(msg, message.Registered) or \ isinstance(msg, message.Unregistered) or \ (isinstance(msg, message.Error) and msg.request_type == message.Call.MESSAGE_TYPE): ## deliver message to app session ## self._session.onMessage(msg) else: ## should not arrive here ## raise Exception("WampRouterAppSession.send: unhandled message {}".format(msg))
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 []
def welcome(realm, authid = None): self._session_id = util.id() self._goodbye_sent = False self._router = self._router_factory.get(realm) if not self._router: raise Exception("no such realm") roles = self._router.attach(self) msg = message.Welcome(self._session_id, roles, authid) self._transport.send(msg) self.onJoin(SessionDetails(self._session_id))
def _register(obj, endpoint, procedure, options): request = util.id() d = self._create_future() self._register_reqs[request] = (d, obj, endpoint, procedure, options) if options is not None: msg = message.Register(request, procedure, **options.options) else: msg = message.Register(request, procedure) self._transport.send(msg) return d
def _subscribe(obj, fn, topic, options): request_id = util.id() on_reply = txaio.create_future() handler_obj = Handler(fn, obj, options.details_arg if options else None) self._subscribe_reqs[request_id] = SubscribeRequest(request_id, on_reply, handler_obj) if options: msg = message.Subscribe(request_id, topic, **options.message_attr()) else: msg = message.Subscribe(request_id, topic) self._transport.send(msg) return on_reply
def _subscribe(obj, handler, topic, options): request = util.id() d = self._create_future() self._subscribe_reqs[request] = (d, obj, handler, topic, options) if options is not None: msg = message.Subscribe(request, topic, **options.options) else: msg = message.Subscribe(request, topic) self._transport.send(msg) return d
def _register(obj, fn, procedure, options): request_id = util.id() on_reply = txaio.create_future() endpoint_obj = Endpoint(fn, obj, options.details_arg if options else None) self._register_reqs[request_id] = RegisterRequest(request_id, on_reply, procedure, endpoint_obj) if options: msg = message.Register(request_id, procedure, **options.message_attr()) else: msg = message.Register(request_id, procedure) self._transport.send(msg) return on_reply
def on_authorize_success(authorized): if authorized: registration_id = util.id() self._procs_to_regs[register.procedure] = (registration_id, session, register.discloseCaller, register.discloseCallerTransport) self._regs_to_procs[registration_id] = register.procedure self._session_to_registrations[session].add(registration_id) reply = message.Registered(register.request, registration_id) else: reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.NOT_AUTHORIZED, ["session is not authorized to register procedure '{0}'".format(register.procedure)]) session._transport.send(reply)
def on_authorize(authorized): if authorized: registration_id = util.id() self._procs_to_regs[register.procedure] = (registration_id, session, register.discloseCaller) self._regs_to_procs[registration_id] = register.procedure self._session_to_registrations[session].add(registration_id) reply = message.Registered(register.request, registration_id) else: reply = message.Error(message.Register.MESSAGE_TYPE, register.request, ApplicationError.NOT_AUTHORIZED, ["session is not authorized to register procedure URI '{}'".format(register.procedure)]) session._transport.send(reply)
def session_add_testament(self, topic, args, kwargs, publish_options=None, scope=u"destroyed", details=None): """ Add a testament to the current session. :param topic: The topic to publish the testament to. :type topic: str :param args: A list of arguments for the publish. :type args: list or tuple :param kwargs: A dict of keyword arguments for the publish. :type kwargs: dict :param publish_options: The publish options for the publish. :type publish_options: None or dict :param scope: The scope of the testament, either "detached" or "destroyed". :type scope: str :returns: The publication ID. :rtype: int """ session = self._router._session_id_to_session[details.caller] if scope not in [u"destroyed", u"detached"]: raise ApplicationError(u"wamp.error.testament_error", u"scope must be destroyed or detached") pub_id = util.id() # Get the publish options, remove some explicit keys publish_options = publish_options or {} publish_options.pop("acknowledge", None) publish_options.pop("exclude_me", None) pub = message.Publish(request=pub_id, topic=topic, args=args, kwargs=kwargs, **publish_options) session._testaments[scope].append(pub) return pub_id
def call(self, procedure, *args, **kwargs): """ Implements :func:`autobahn.wamp.interfaces.ICaller.call` """ if six.PY2 and type(procedure) == str: procedure = six.u(procedure) assert (isinstance(procedure, six.text_type)) if not self._transport: raise exception.TransportLost() request_id = util.id() if 'options' in kwargs and isinstance(kwargs['options'], types.CallOptions): options = kwargs.pop('options') msg = message.Call(request_id, procedure, args=args, kwargs=kwargs, **options.message_attr()) else: options = None msg = message.Call(request_id, procedure, args=args, kwargs=kwargs) # FIXME # def canceller(_d): # cancel_msg = message.Cancel(request) # self._transport.send(cancel_msg) # d = Deferred(canceller) on_reply = self._create_future() self._call_reqs[request_id] = CallRequest(request_id, on_reply, options) try: # Notes: # # * this might raise autobahn.wamp.exception.SerializationError # when the user payload cannot be serialized # * we have to setup a PublishRequest() in _publish_reqs _before_ # calling transpor.send(), because a mock- or side-by-side transport # will immediately lead on an incoming WAMP message in onMessage() # self._transport.send(msg) except Exception as e: if request_id in self._call_reqs: del self._call_reqs[request_id] raise e return on_reply
def publish(self, topic, *args, **kwargs): """ Implements :func:`autobahn.wamp.interfaces.IPublisher.publish` """ if six.PY2 and type(topic) == str: topic = six.u(topic) assert (type(topic) == six.text_type) if not self._transport: raise exception.TransportLost() request_id = util.id() if 'options' in kwargs and isinstance(kwargs['options'], types.PublishOptions): options = kwargs.pop('options') msg = message.Publish(request_id, topic, args=args, kwargs=kwargs, **options.message_attr()) else: options = None msg = message.Publish(request_id, topic, args=args, kwargs=kwargs) if options and options.acknowledge: # only acknowledged publications expect a reply .. on_reply = self._create_future() self._publish_reqs[request_id] = PublishRequest( request_id, on_reply) else: on_reply = None try: # Notes: # # * this might raise autobahn.wamp.exception.SerializationError # when the user payload cannot be serialized # * we have to setup a PublishRequest() in _publish_reqs _before_ # calling transpor.send(), because a mock- or side-by-side transport # will immediately lead on an incoming WAMP message in onMessage() # self._transport.send(msg) except Exception as e: if request_id in self._publish_reqs: del self._publish_reqs[request_id] raise e return on_reply
def __init__(self, handler): self._log = False self._handler = handler self._serializer = serializer.JsonSerializer() self._registrations = {} self._invocations = {} self._subscription_topics = {} self._my_session_id = util.id() self._handler.onOpen(self) roles = {u'broker': role.RoleBrokerFeatures(), u'dealer': role.RoleDealerFeatures()} msg = message.Welcome(self._my_session_id, roles) self._handler.onMessage(msg)
def processCall(self, session, call): """ Implements :func:`autobahn.wamp.interfaces.IDealer.processCall` """ assert(session in self._session_to_registrations) ## check procedure URI ## if (not self._option_uri_strict and not _URI_PAT_LOOSE_NON_EMPTY.match(call.procedure)) or \ ( self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(call.procedure)): reply = message.Error(message.Register.MESSAGE_TYPE, call.request, ApplicationError.INVALID_URI, ["call with invalid procedure URI '{}'".format(call.procedure)]) session._transport.send(reply) else: if call.procedure in self._procs_to_regs: registration_id, endpoint_session, discloseCaller = self._procs_to_regs[call.procedure] request_id = util.id() if discloseCaller or call.discloseMe: caller = session._session_id authid = session._authid authrole = session._authrole authmethod = session._authmethod else: caller = None authid = None authrole = None authmethod = None invocation = message.Invocation(request_id, registration_id, args = call.args, kwargs = call.kwargs, timeout = call.timeout, receive_progress = call.receive_progress, caller = caller, authid = authid, authrole = authrole, authmethod = authmethod) self._invocations[request_id] = (call, session) endpoint_session._transport.send(invocation) else: reply = message.Error(message.Call.MESSAGE_TYPE, call.request, ApplicationError.NO_SUCH_PROCEDURE, ["no procedure '{}' registered".format(call.procedure)]) session._transport.send(reply)
def _publish(self, event, options): request = util.id() msg = message.Publish(request=request, topic=u".".join( tokenise_mqtt_topic(event.topic_name)), payload=event.payload, **options.message_attr()) msg._mqtt_publish = True self._wamp_session.onMessage(msg) if event.qos_level > 0: self._request_to_packetid[request] = event.packet_identifier return succeed(0)
def _subscribe(obj, fn, topic, options): request_id = util.id() on_reply = self._create_future() handler_obj = Handler(fn, obj, options.details_arg if options else None) self._subscribe_reqs[request_id] = SubscribeRequest( request_id, on_reply, handler_obj) if options: msg = message.Subscribe(request_id, topic, **options.message_attr()) else: msg = message.Subscribe(request_id, topic) self._transport.send(msg) return on_reply
def _register(obj, fn, procedure, options): request_id = util.id() on_reply = self._create_future() endpoint_obj = Endpoint(fn, obj, options.details_arg if options else None) self._register_reqs[request_id] = RegisterRequest( request_id, on_reply, procedure, endpoint_obj) if options: msg = message.Register(request_id, procedure, **options.message_attr()) else: msg = message.Register(request_id, procedure) self._transport.send(msg) return on_reply
def on_authorize_success(authorized): if authorized: registration_id, endpoint_session, discloseCaller, discloseCallerTransport = self._procs_to_regs[ call.procedure] request_id = util.id() if discloseCaller or call.discloseMe: caller = session._session_id caller_transport = None authid = session._authid authrole = session._authrole authmethod = session._authmethod if discloseCallerTransport and hasattr( session._transport, '_transport_info'): caller_transport = session._transport._transport_info else: caller = None caller_transport = None authid = None authrole = None authmethod = None invocation = message.Invocation( request_id, registration_id, args=call.args, kwargs=call.kwargs, timeout=call.timeout, receive_progress=call.receive_progress, caller=caller, caller_transport=caller_transport, authid=authid, authrole=authrole, authmethod=authmethod) self._invocations[request_id] = (call, session) endpoint_session._transport.send(invocation) else: reply = message.Error( message.Call.MESSAGE_TYPE, call.request, ApplicationError.NOT_AUTHORIZED, [ "session is not authorized to call procedure '{0}'" .format(call.procedure) ]) session._transport.send(reply)
def test_non_depleting(self): res = {} with open('/dev/urandom', 'rb') as rng: for i in range(1000): for j in range(100): # "reseed" (seems pointless, but ..) random.seed() # random UUIDs v1 = uuid.uuid4() # noqa # stdlib random v2 = random.random() # noqa v3 = random.getrandbits(32) # noqa v4 = random.randint(0, 9007199254740992) # noqa v5 = random.normalvariate(10, 100) # noqa v6 = random.choice(range(100)) # noqa # PyNaCl v7 = utils.random(public.Box.NONCE_SIZE) # noqa # Autobahn utils v8 = util.generate_token(4, 4) # noqa v9 = util.id() # noqa v10 = util.rid() # noqa v11 = util.newid() # noqa # direct procfs access to PRNG d = rng.read(1000) # noqa # check available entropy with open('/proc/sys/kernel/random/entropy_avail', 'r') as ent: ea = int(ent.read()) // 100 if ea not in res: res[ea] = 0 res[ea] += 1 skeys = sorted(res.keys()) print('\nsystem entropy depletion stats:') for k in skeys: print('{}: {}'.format(k, res[k])) self.assertTrue(skeys[0] > 0)
def processSubscribe(self, session, subscribe): """ Implements :func:`autobahn.wamp.interfaces.IBroker.processSubscribe` """ assert (session in self._session_to_subscriptions) ## check topic URI ## if (not self._option_uri_strict and not _URI_PAT_LOOSE_NON_EMPTY.match(subscribe.topic)) or \ ( self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(subscribe.topic)): reply = message.Error( message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.INVALID_URI, [ "subscribe for invalid topic URI '{}'".format( subscribe.topic) ]) else: if not subscribe.topic in self._topic_to_sessions: subscription = util.id() self._topic_to_sessions[subscribe.topic] = (subscription, set()) subscription, subscribers = self._topic_to_sessions[ subscribe.topic] if not session in subscribers: subscribers.add(session) if not subscription in self._subscription_to_sessions: self._subscription_to_sessions[subscription] = ( subscribe.topic, set()) _, subscribers = self._subscription_to_sessions[subscription] if not session in subscribers: subscribers.add(session) if not subscription in self._session_to_subscriptions[session]: self._session_to_subscriptions[session].add(subscription) reply = message.Subscribed(subscribe.request, subscription) session._transport.send(reply)
def call(self, procedure, *args, **kwargs): """ Implements :func:`autobahn.wamp.interfaces.ICaller.call` """ if six.PY2 and type(procedure) == str: procedure = six.u(procedure) assert(isinstance(procedure, six.text_type)) if not self._transport: raise exception.TransportLost() request_id = util.id() if 'options' in kwargs and isinstance(kwargs['options'], types.CallOptions): options = kwargs.pop('options') msg = message.Call(request_id, procedure, args=args, kwargs=kwargs, **options.message_attr()) else: options = None msg = message.Call(request_id, procedure, args=args, kwargs=kwargs) # FIXME # def canceller(_d): # cancel_msg = message.Cancel(request) # self._transport.send(cancel_msg) # d = Deferred(canceller) on_reply = txaio.create_future() self._call_reqs[request_id] = CallRequest(request_id, on_reply, options) try: # Notes: # # * this might raise autobahn.wamp.exception.SerializationError # when the user payload cannot be serialized # * we have to setup a PublishRequest() in _publish_reqs _before_ # calling transpor.send(), because a mock- or side-by-side transport # will immediately lead on an incoming WAMP message in onMessage() # self._transport.send(msg) except Exception as e: if request_id in self._call_reqs: del self._call_reqs[request_id] raise e return on_reply
def session_add_testament(self, topic, args, kwargs, publish_options=None, scope=u"destroyed", details=None): """ Add a testament to the current session. :param topic: The topic to publish the testament to. :type topic: str :param args: A list of arguments for the publish. :type args: list or tuple :param kwargs: A dict of keyword arguments for the publish. :type kwargs: dict :param publish_options: The publish options for the publish. :type publish_options: None or dict :param scope: The scope of the testament, either "detatched" or "destroyed". :type scope: str :returns: The publication ID. :rtype: int """ session = self._router._session_id_to_session[details.caller] if scope not in [u"destroyed", u"detatched"]: raise ApplicationError(u"wamp.error.testament_error", u"scope must be destroyed or detatched") pub_id = util.id() # Get the publish options, remove some explicit keys publish_options = publish_options or {} publish_options.pop("acknowledge", None) publish_options.pop("exclude_me", None) pub = message.Publish( request=pub_id, topic=topic, args=args, kwargs=kwargs, **publish_options) session._testaments[scope].append(pub) return pub_id
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 []
def __init__(self, handler): self._log = False self._handler = handler self._serializer = serializer.JsonSerializer() self._registrations = {} self._invocations = {} #: str -> ID self._subscription_topics = {} self._handler.onOpen(self) self._my_session_id = util.id() roles = {u"broker": role.RoleBrokerFeatures(), u"dealer": role.RoleDealerFeatures()} msg = message.Welcome(self._my_session_id, roles) self._handler.onMessage(msg) self._fake_router_session = ApplicationSession()
def welcome(realm, authid = None, authrole = None, authmethod = None): self._session_id = util.id() self._goodbye_sent = False self._router = self._router_factory.get(realm) if not self._router: raise Exception("no such realm") self._authid = authid self._authrole = authrole self._authmethod = authmethod roles = self._router.attach(self) msg = message.Welcome(self._session_id, roles, authid = authid, authrole = authrole, authmethod = authmethod) self._transport.send(msg) self.onJoin(SessionDetails(self._realm, self._session_id, self._authid, self._authrole, self._authmethod))
def processRegister(self, session, register): """ Implements :func:`autobahn.wamp.interfaces.IDealer.processRegister` """ assert(session in self._session_to_registrations) if not register.procedure in self._procs_to_regs: registration_id = util.id() self._procs_to_regs[register.procedure] = (registration_id, session) self._regs_to_procs[registration_id] = register.procedure self._session_to_registrations[session].add(registration_id) reply = message.Registered(register.request, registration_id) else: reply = message.Error(message.Register.MESSAGE_TYPE, register.request, 'wamp.error.procedure_already_exists') session._transport.send(reply)
def process_subscribe(self, packet): packet_watch = OrderedDict() d = Deferred() @d.addCallback def _(ign): self._mqtt.send_suback( packet.packet_identifier, [x["response"] for x in packet_watch.values()]) del self._inflight_subscriptions[packet.packet_identifier] del self._subrequest_callbacks[packet.packet_identifier] self._subrequest_callbacks[packet.packet_identifier] = d self._inflight_subscriptions[packet.packet_identifier] = packet_watch for n, x in enumerate(packet.topic_requests): topic, match = _mqtt_topicfilter_to_wamp(x.topic_filter) self.log.info('process_subscribe -> topic={topic}, match={match}', topic=topic, match=match) request_id = util.id() msg = message.Subscribe( request=request_id, topic=topic, match=match, get_retained=True, ) try: packet_watch[request_id] = { "response": -1, "topic": x.topic_filter } self._subrequest_to_mqtt_subrequest[ request_id] = packet.packet_identifier self._wamp_session.onMessage(msg) except: self.log.failure() packet_watch[request_id] = {"response": 128}
def __init__(self, handler): self._log = False self._handler = handler self._serializer = serializer.JsonSerializer() self._registrations = {} self._invocations = {} #: str -> ID self._subscription_topics = {} self._handler.onOpen(self) self._my_session_id = util.id() roles = {'broker': role.RoleBrokerFeatures(), 'dealer': role.RoleDealerFeatures()} msg = message.Welcome(self._my_session_id, roles) self._handler.onMessage(msg) self._fake_router_session = ApplicationSession() self._transport_details = TransportDetails()
def _unregister(self, registration): """ Called from :meth:`autobahn.wamp.protocol.Registration.unregister` """ assert(isinstance(registration, Registration)) assert registration.active assert(registration.id in self._registrations) if not self._transport: raise exception.TransportLost() request = util.id() d = self._create_future() self._unregister_reqs[request] = (d, registration) msg = message.Unregister(request, registration.id) self._transport.send(msg) return d
def _unsubscribe(self, subscription): """ Called from :meth:`autobahn.wamp.protocol.Subscription.unsubscribe` """ assert(isinstance(subscription, Subscription)) assert subscription.active assert(subscription.id in self._subscriptions) if not self._transport: raise exception.TransportLost() request = util.id() d = self._create_future() self._unsubscribe_reqs[request] = (d, subscription) msg = message.Unsubscribe(request, subscription.id) self._transport.send(msg) return d
def call(self, procedure, *args, **kwargs): """ Reimplemented to support calls with custom options """ if six.PY2 and type(procedure) == str: procedure = six.u(procedure) assert(isinstance(procedure, six.text_type)) if not self._transport: raise exception.TransportLost() request_id = util.id() on_reply = txaio.create_future() self._call_reqs[request_id] = CallRequest(request_id, procedure, on_reply, {}) try: self._transport.send(AkCall(request_id, procedure, args, kwargs)) except Exception as e: if request_id in self._call_reqs: del self._call_reqs[request_id] raise e return on_reply
def process_will(res): payload_format, mapped_topic, options = yield self.factory.transform_mqtt( packet.will_topic, packet.will_message) request = util.id() msg = message.Call(request=request, procedure=u"wamp.session.add_testament", args=[ mapped_topic, options.get('args', None), options.get('kwargs', None), { 'retain': bool(packet.flags.will_retain) } ]) self._wamp_session.onMessage(msg) returnValue(res)
def on_authorize_success(authorized): if not authorized: reply = message.Error( message.Subscribe.MESSAGE_TYPE, subscribe.request, ApplicationError.NOT_AUTHORIZED, [ "session is not authorized to subscribe to topic '{0}'" .format(subscribe.topic) ]) else: if not subscribe.topic in self._topic_to_sessions: subscription = util.id() self._topic_to_sessions[subscribe.topic] = ( subscription, set()) subscription, subscribers = self._topic_to_sessions[ subscribe.topic] if not session in subscribers: subscribers.add(session) if not subscription in self._subscription_to_sessions: self._subscription_to_sessions[subscription] = ( subscribe.topic, set()) _, subscribers = self._subscription_to_sessions[ subscription] if not session in subscribers: subscribers.add(session) if not subscription in self._session_to_subscriptions[ session]: self._session_to_subscriptions[session].add( subscription) reply = message.Subscribed(subscribe.request, subscription) session._transport.send(reply)
def process_subscribe(self, packet): packet_watch = OrderedDict() d = Deferred() @d.addCallback def _(ign): self._mqtt.send_suback( packet.packet_identifier, [x["response"] for x in packet_watch.values()]) del self._inflight_subscriptions[packet.packet_identifier] del self._subrequest_callbacks[packet.packet_identifier] self._subrequest_callbacks[packet.packet_identifier] = d self._inflight_subscriptions[packet.packet_identifier] = packet_watch for n, x in enumerate(packet.topic_requests): # fixme match_type = u"exact" request_id = util.id() msg = message.Subscribe( request=request_id, topic=u".".join(tokenise_mqtt_topic(x.topic_filter)), match=match_type, get_retained=True, ) try: packet_watch[request_id] = { "response": -1, "topic": x.topic_filter } self._subrequest_to_mqtt_subrequest[ request_id] = packet.packet_identifier self._wamp_session.onMessage(msg) except Exception: self.log.failure() packet_watch[request_id] = {"response": 128}
def processRegister(self, session, register): """ Implements :func:`autobahn.wamp.interfaces.IDealer.processRegister` """ assert (session in self._session_to_registrations) ## check procedure URI ## if (not self._option_uri_strict and not _URI_PAT_LOOSE_NON_EMPTY.match(register.procedure)) or \ ( self._option_uri_strict and not _URI_PAT_STRICT_NON_EMPTY.match(register.procedure)): reply = message.Error( message.Register.MESSAGE_TYPE, register.request, ApplicationError.INVALID_URI, [ "register for invalid procedure URI '{}'".format( register.procedure) ]) else: if not register.procedure in self._procs_to_regs: registration_id = util.id() self._procs_to_regs[register.procedure] = ( registration_id, session, register.discloseCaller) self._regs_to_procs[registration_id] = register.procedure self._session_to_registrations[session].add(registration_id) reply = message.Registered(register.request, registration_id) else: reply = message.Error( message.Register.MESSAGE_TYPE, register.request, ApplicationError.PROCEDURE_ALREADY_EXISTS, [ "register for already registered procedure URI '{}'". format(register.procedure) ]) session._transport.send(reply)