def _when_ready(self): if self._wamp_session: return self._mqtt.transport = self.transport self._wamp_session = RouterSession(self.factory._router_session_factory._routerFactory) self._wamp_transport = WampTransport(self.factory, self.on_message, self.transport) self._wamp_session.onOpen(self._wamp_transport) self._wamp_session._transport_config = self.factory._options
def _when_ready(self): if self._wamp_session: return self._mqtt.transport = self.transport self._wamp_session = RouterSession( self.factory._wamp_session_factory._routerFactory) self._wamp_session._is_mqtt = True self._wamp_transport = WampTransport(self.on_message, self.transport) self._wamp_transport.factory = self.factory self._wamp_session.onOpen(self._wamp_transport)
class WampMQTTServerProtocol(Protocol): log = make_logger() def __init__(self, reactor): self._mqtt = MQTTServerTwistedProtocol(self, reactor) self._request_to_packetid = {} self._waiting_for_connect = None self._inflight_subscriptions = {} self._subrequest_to_mqtt_subrequest = {} self._subrequest_callbacks = {} self._topic_lookup = {} self._wamp_session = None def on_message(self, inc_msg): try: self._on_message(inc_msg) except: self.log.failure() @inlineCallbacks def _on_message(self, inc_msg): self.log.debug('WampMQTTServerProtocol._on_message(inc_msg={inc_msg})', inc_msg=inc_msg) if isinstance(inc_msg, message.Challenge): assert inc_msg.method == "ticket" msg = message.Authenticate(signature=self._pw_challenge) del self._pw_challenge self._wamp_session.onMessage(msg) elif isinstance(inc_msg, message.Welcome): self._waiting_for_connect.callback((0, False)) elif isinstance(inc_msg, message.Abort): self._waiting_for_connect.callback((1, False)) elif isinstance(inc_msg, message.Subscribed): # Successful subscription! mqtt_id = self._subrequest_to_mqtt_subrequest[inc_msg.request] self._inflight_subscriptions[mqtt_id][ inc_msg.request]["response"] = 0 self._topic_lookup[ inc_msg.subscription] = self._inflight_subscriptions[mqtt_id][ inc_msg.request]["topic"] if -1 not in [ x["response"] for x in self._inflight_subscriptions[mqtt_id].values() ]: self._subrequest_callbacks[mqtt_id].callback(None) elif (isinstance(inc_msg, message.Error) and inc_msg.request_type == message.Subscribe.MESSAGE_TYPE): # Failed subscription :( mqtt_id = self._subrequest_to_mqtt_subrequest[inc_msg.request] self._inflight_subscriptions[mqtt_id][ inc_msg.request]["response"] = 128 if -1 not in [ x["response"] for x in self._inflight_subscriptions[mqtt_id].values() ]: self._subrequest_callbacks[mqtt_id].callback(None) elif isinstance(inc_msg, message.Event): topic = inc_msg.topic or self._topic_lookup[inc_msg.subscription] try: payload_format, mapped_topic, payload = yield self.factory.transform_wamp( topic, inc_msg) except: self.log.failure() else: self._mqtt.send_publish(mapped_topic, 0, payload, retained=inc_msg.retained or False) elif isinstance(inc_msg, message.Goodbye): if self._mqtt.transport: self._mqtt.transport.loseConnection() self._mqtt.transport = None else: self.log.warn('cannot process unimplemented message: {inc_msg}', inc_msg=inc_msg) def connectionMade(self, ignore_handshake=False): if ignore_handshake or not ISSLTransport.providedBy(self.transport): self._when_ready() def connectionLost(self, reason): if self._wamp_session: msg = message.Goodbye() self._wamp_session.onMessage(msg) del self._wamp_session def handshakeCompleted(self): self._when_ready() def _when_ready(self): if self._wamp_session: return self._mqtt.transport = self.transport self._wamp_session = RouterSession( self.factory._router_session_factory._routerFactory) self._wamp_transport = WampTransport(self.factory, self.on_message, self.transport) self._wamp_session.onOpen(self._wamp_transport) self._wamp_session._transport_config = self.factory._options def process_connect(self, packet): """ Process the initial Connect message from the MQTT client. This should return a pair `(accept_conn, session_present)`, where `accept_conn` is a return code: 0: connection accepted 1-5: connection refused (see MQTT spec 3.2.2.3) """ # Connect(client_id='paho/4E23D8C09DD9C6CF2C', # flags=ConnectFlags(username=False, # password=False, # will=False, # will_retain=False, # will_qos=0, # clean_session=True, # reserved=False), # keep_alive=60, # will_topic=None, # will_message=None, # username=None, # password=None) self.log.info( 'WampMQTTServerProtocol.process_connect(packet={packet})', packet=packet) # we don't support session resumption: https://github.com/crossbario/crossbar/issues/892 if not packet.flags.clean_session: self.log.warn( 'denying MQTT connect from {peer}, as the clients wants to resume a session (which we do not support)', peer=peer2str(self.transport.getPeer())) return succeed((1, False)) # we won't support QoS 2: https://github.com/crossbario/crossbar/issues/1046 if packet.flags.will and packet.flags.will_qos not in [0, 1]: self.log.warn( 'denying MQTT connect from {peer}, as the clients wants to provide a "last will" event with QoS {will_qos} (and we only support QoS 0/1 here)', peer=peer2str(self.transport.getPeer()), will_qos=packet.flags.will_qos) return succeed((1, False)) # this will be resolved when the MQTT connect handshake is completed self._waiting_for_connect = Deferred() roles = { "subscriber": role.RoleSubscriberFeatures(payload_transparency=True, pattern_based_subscription=True), "publisher": role.RolePublisherFeatures(payload_transparency=True, x_acknowledged_event_delivery=True) } realm = self.factory._options.get('realm', None) authmethods = [] authextra = { 'mqtt': { 'client_id': packet.client_id, 'will': bool(packet.flags.will), 'will_topic': packet.will_topic } } if ISSLTransport.providedBy(self.transport): authmethods.append("tls") if packet.username and packet.password: authmethods.append("ticket") msg = message.Hello(realm=realm, roles=roles, authmethods=authmethods, authid=packet.username, authextra=authextra) self._pw_challenge = packet.password else: authmethods.append("anonymous") msg = message.Hello(realm=realm, roles=roles, authmethods=authmethods, authid=packet.client_id, authextra=authextra) self._wamp_session.onMessage(msg) if packet.flags.will: # it's unclear from the MQTT spec whether a) the publication of the last will # is to happen in-band during "connect", and if it fails, deny the connection, # or b) the last will publication happens _after_ "connect", and the connection # succeeds regardless whether the last will publication succeeds or not. # # we opt for b) here! # @inlineCallbacks @self._waiting_for_connect.addCallback 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="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 'retain': bool(packet.flags.will_retain) } ]) self._wamp_session.onMessage(msg) returnValue(res) return self._waiting_for_connect @inlineCallbacks 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_publish_qos_0(self, event): try: return self._publish(event) except: self.log.failure() def process_publish_qos_1(self, event): try: return self._publish(event, acknowledge=True) except: self.log.failure() def process_puback(self, event): return def process_pubrec(self, event): return def process_pubrel(self, event): return def process_pubcomp(self, event): return 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} @inlineCallbacks def process_unsubscribe(self, packet): for topic in packet.topics: if topic in self._subscriptions: yield self._subscriptions.pop(topic).unsubscribe() return def dataReceived(self, data): self._mqtt.dataReceived(data)
class WampMQTTServerProtocol(Protocol): log = make_logger() def __init__(self, reactor): self._mqtt = MQTTServerTwistedProtocol(self, reactor) self._request_to_packetid = {} self._waiting_for_connect = None self._inflight_subscriptions = {} self._subrequest_to_mqtt_subrequest = {} self._subrequest_callbacks = {} self._topic_lookup = {} self._wamp_session = None def on_message(self, inc_msg): try: self._on_message(inc_msg) except: self.log.failure() def _on_message(self, inc_msg): if isinstance(inc_msg, message.Challenge): assert inc_msg.method == u"ticket" msg = message.Authenticate(signature=self._pw_challenge) del self._pw_challenge self._wamp_session.onMessage(msg) elif isinstance(inc_msg, message.Welcome): self._waiting_for_connect.callback((0, False)) elif isinstance(inc_msg, message.Abort): self._waiting_for_connect.callback((1, False)) elif isinstance(inc_msg, message.Subscribed): # Successful subscription! mqtt_id = self._subrequest_to_mqtt_subrequest[inc_msg.request] self._inflight_subscriptions[mqtt_id][ inc_msg.request]["response"] = 0 self._topic_lookup[ inc_msg.subscription] = self._inflight_subscriptions[mqtt_id][ inc_msg.request]["topic"] if -1 not in [ x["response"] for x in self._inflight_subscriptions[mqtt_id].values() ]: self._subrequest_callbacks[mqtt_id].callback(None) elif (isinstance(inc_msg, message.Error) and inc_msg.request_type == message.Subscribe.MESSAGE_TYPE): # Failed subscription :( mqtt_id = self._subrequest_to_mqtt_subrequest[inc_msg.request] self._inflight_subscriptions[mqtt_id][ inc_msg.request]["response"] = 128 if -1 not in [ x["response"] for x in self._inflight_subscriptions[mqtt_id].values() ]: self._subrequest_callbacks[mqtt_id].callback(None) elif isinstance(inc_msg, message.Event): topic = inc_msg.topic or self._topic_lookup[inc_msg.subscription] body = wamp_payload_transform( self._wamp_session._router._mqtt_payload_format, inc_msg) self._mqtt.send_publish(u"/".join(tokenise_wamp_topic(topic)), 0, body, retained=inc_msg.retained or False) elif isinstance(inc_msg, message.Goodbye): if self._mqtt.transport: self._mqtt.transport.loseConnection() self._mqtt.transport = None else: print("Got something we don't understand yet:") print(inc_msg) def connectionMade(self, ignore_handshake=False): if ignore_handshake or not ISSLTransport.providedBy(self.transport): self._when_ready() def connectionLost(self, reason): if self._wamp_session: msg = message.Goodbye() self._wamp_session.onMessage(msg) del self._wamp_session def handshakeCompleted(self): self._when_ready() def _when_ready(self): if self._wamp_session: return self._mqtt.transport = self.transport self._wamp_session = RouterSession( self.factory._wamp_session_factory._routerFactory) self._wamp_session._is_mqtt = True self._wamp_transport = WampTransport(self.on_message, self.transport) self._wamp_transport.factory = self.factory self._wamp_session.onOpen(self._wamp_transport) def process_connect(self, packet): self._waiting_for_connect = Deferred() roles = { u"subscriber": role.RoleSubscriberFeatures(payload_transparency=True), u"publisher": role.RolePublisherFeatures(payload_transparency=True, x_acknowledged_event_delivery=True) } # Will be autoassigned realm = None methods = [] if ISSLTransport.providedBy(self.transport): methods.append(u"tls") if packet.username and packet.password: methods.append(u"ticket") msg = message.Hello(realm=realm, roles=roles, authmethods=methods, authid=packet.username) self._pw_challenge = packet.password else: methods.append(u"anonymous") msg = message.Hello(realm=realm, roles=roles, authmethods=methods, authid=packet.client_id) self._wamp_session.onMessage(msg) if packet.flags.will: @self._waiting_for_connect.addCallback 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 return self._waiting_for_connect 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 process_publish_qos_0(self, event): return self._publish(event, options=PublishOptions(exclude_me=False, retain=event.retain)) def process_publish_qos_1(self, event): return self._publish(event, options=PublishOptions(acknowledge=True, exclude_me=False, retain=event.retain)) def process_puback(self, event): return def process_pubrec(self, event): return def process_pubrel(self, event): return def process_pubcomp(self, event): return 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} @inlineCallbacks def process_unsubscribe(self, packet): for topic in packet.topics: if topic in self._subscriptions: yield self._subscriptions.pop(topic).unsubscribe() return def dataReceived(self, data): self._mqtt.dataReceived(data)
class WampMQTTServerProtocol(Protocol): log = make_logger() def __init__(self, reactor): self._mqtt = MQTTServerTwistedProtocol(self, reactor) self._request_to_packetid = {} self._waiting_for_connect = None self._inflight_subscriptions = {} self._subrequest_to_mqtt_subrequest = {} self._subrequest_callbacks = {} self._topic_lookup = {} self._wamp_session = None def on_message(self, inc_msg): try: self._on_message(inc_msg) except: self.log.failure() @inlineCallbacks def _on_message(self, inc_msg): self.log.debug('WampMQTTServerProtocol._on_message(inc_msg={inc_msg})', inc_msg=inc_msg) if isinstance(inc_msg, message.Challenge): assert inc_msg.method == u"ticket" msg = message.Authenticate(signature=self._pw_challenge) del self._pw_challenge self._wamp_session.onMessage(msg) elif isinstance(inc_msg, message.Welcome): self._waiting_for_connect.callback((0, False)) elif isinstance(inc_msg, message.Abort): self._waiting_for_connect.callback((1, False)) elif isinstance(inc_msg, message.Subscribed): # Successful subscription! mqtt_id = self._subrequest_to_mqtt_subrequest[inc_msg.request] self._inflight_subscriptions[mqtt_id][inc_msg.request]["response"] = 0 self._topic_lookup[inc_msg.subscription] = self._inflight_subscriptions[mqtt_id][inc_msg.request]["topic"] if -1 not in [x["response"] for x in self._inflight_subscriptions[mqtt_id].values()]: self._subrequest_callbacks[mqtt_id].callback(None) elif (isinstance(inc_msg, message.Error) and inc_msg.request_type == message.Subscribe.MESSAGE_TYPE): # Failed subscription :( mqtt_id = self._subrequest_to_mqtt_subrequest[inc_msg.request] self._inflight_subscriptions[mqtt_id][inc_msg.request]["response"] = 128 if -1 not in [x["response"] for x in self._inflight_subscriptions[mqtt_id].values()]: self._subrequest_callbacks[mqtt_id].callback(None) elif isinstance(inc_msg, message.Event): topic = inc_msg.topic or self._topic_lookup[inc_msg.subscription] try: payload_format, mapped_topic, payload = yield self.factory.transform_wamp(topic, inc_msg) except: self.log.failure() else: self._mqtt.send_publish(mapped_topic, 0, payload, retained=inc_msg.retained or False) elif isinstance(inc_msg, message.Goodbye): if self._mqtt.transport: self._mqtt.transport.loseConnection() self._mqtt.transport = None else: self.log.warn('cannot process unimplemented message: {inc_msg}', inc_msg=inc_msg) def connectionMade(self, ignore_handshake=False): if ignore_handshake or not ISSLTransport.providedBy(self.transport): self._when_ready() def connectionLost(self, reason): if self._wamp_session: msg = message.Goodbye() self._wamp_session.onMessage(msg) del self._wamp_session def handshakeCompleted(self): self._when_ready() def _when_ready(self): if self._wamp_session: return self._mqtt.transport = self.transport self._wamp_session = RouterSession(self.factory._router_session_factory._routerFactory) self._wamp_transport = WampTransport(self.factory, self.on_message, self.transport) self._wamp_session.onOpen(self._wamp_transport) self._wamp_session._transport_config = self.factory._options def process_connect(self, packet): """ Process the initial Connect message from the MQTT client. This should return a pair `(accept_conn, session_present)`, where `accept_conn` is a return code: 0: connection accepted 1-5: connection refused (see MQTT spec 3.2.2.3) """ # Connect(client_id='paho/4E23D8C09DD9C6CF2C', # flags=ConnectFlags(username=False, # password=False, # will=False, # will_retain=False, # will_qos=0, # clean_session=True, # reserved=False), # keep_alive=60, # will_topic=None, # will_message=None, # username=None, # password=None) self.log.info('WampMQTTServerProtocol.process_connect(packet={packet})', packet=packet) # we don't support session resumption: https://github.com/crossbario/crossbar/issues/892 if not packet.flags.clean_session: self.log.warn('denying MQTT connect from {peer}, as the clients wants to resume a session (which we do not support)', peer=peer2str(self.transport.getPeer())) return succeed((1, False)) # we won't support QoS 2: https://github.com/crossbario/crossbar/issues/1046 if packet.flags.will and packet.flags.will_qos not in [0, 1]: self.log.warn('denying MQTT connect from {peer}, as the clients wants to provide a "last will" event with QoS {will_qos} (and we only support QoS 0/1 here)', peer=peer2str(self.transport.getPeer()), will_qos=packet.flags.will_qos) return succeed((1, False)) # this will be resolved when the MQTT connect handshake is completed self._waiting_for_connect = Deferred() roles = { u"subscriber": role.RoleSubscriberFeatures( payload_transparency=True, pattern_based_subscription=True), u"publisher": role.RolePublisherFeatures( payload_transparency=True, x_acknowledged_event_delivery=True) } realm = self.factory._options.get(u'realm', None) authmethods = [] authextra = { u'mqtt': { u'client_id': packet.client_id, u'will': bool(packet.flags.will), u'will_topic': packet.will_topic } } if ISSLTransport.providedBy(self.transport): authmethods.append(u"tls") if packet.username and packet.password: authmethods.append(u"ticket") msg = message.Hello( realm=realm, roles=roles, authmethods=authmethods, authid=packet.username, authextra=authextra) self._pw_challenge = packet.password else: authmethods.append(u"anonymous") msg = message.Hello( realm=realm, roles=roles, authmethods=authmethods, authid=packet.client_id, authextra=authextra) self._wamp_session.onMessage(msg) if packet.flags.will: # it's unclear from the MQTT spec whether a) the publication of the last will # is to happen in-band during "connect", and if it fails, deny the connection, # or b) the last will publication happens _after_ "connect", and the connection # succeeds regardless whether the last will publication succeeds or not. # # we opt for b) here! # @inlineCallbacks @self._waiting_for_connect.addCallback 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) return self._waiting_for_connect @inlineCallbacks 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_publish_qos_0(self, event): try: return self._publish(event) except: self.log.failure() def process_publish_qos_1(self, event): try: return self._publish(event, acknowledge=True) except: self.log.failure() def process_puback(self, event): return def process_pubrec(self, event): return def process_pubrel(self, event): return def process_pubcomp(self, event): return 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} @inlineCallbacks def process_unsubscribe(self, packet): for topic in packet.topics: if topic in self._subscriptions: yield self._subscriptions.pop(topic).unsubscribe() return def dataReceived(self, data): self._mqtt.dataReceived(data)
class WampMQTTServerProtocol(Protocol): log = make_logger() def __init__(self, reactor): self._mqtt = MQTTServerTwistedProtocol(self, reactor) self._request_to_packetid = {} self._waiting_for_connect = None self._inflight_subscriptions = {} self._subrequest_to_mqtt_subrequest = {} self._subrequest_callbacks = {} self._topic_lookup = {} self._wamp_session = None def on_message(self, inc_msg): try: self._on_message(inc_msg) except: self.log.failure() @inlineCallbacks def _on_message(self, inc_msg): self.log.debug('WampMQTTServerProtocol._on_message(inc_msg={inc_msg})', inc_msg=inc_msg) if isinstance(inc_msg, message.Challenge): assert inc_msg.method == u"ticket" msg = message.Authenticate(signature=self._pw_challenge) del self._pw_challenge self._wamp_session.onMessage(msg) elif isinstance(inc_msg, message.Welcome): self._waiting_for_connect.callback((0, False)) elif isinstance(inc_msg, message.Abort): self._waiting_for_connect.callback((1, False)) elif isinstance(inc_msg, message.Subscribed): # Successful subscription! mqtt_id = self._subrequest_to_mqtt_subrequest[inc_msg.request] self._inflight_subscriptions[mqtt_id][ inc_msg.request]["response"] = 0 self._topic_lookup[ inc_msg.subscription] = self._inflight_subscriptions[mqtt_id][ inc_msg.request]["topic"] if -1 not in [ x["response"] for x in self._inflight_subscriptions[mqtt_id].values() ]: self._subrequest_callbacks[mqtt_id].callback(None) elif (isinstance(inc_msg, message.Error) and inc_msg.request_type == message.Subscribe.MESSAGE_TYPE): # Failed subscription :( mqtt_id = self._subrequest_to_mqtt_subrequest[inc_msg.request] self._inflight_subscriptions[mqtt_id][ inc_msg.request]["response"] = 128 if -1 not in [ x["response"] for x in self._inflight_subscriptions[mqtt_id].values() ]: self._subrequest_callbacks[mqtt_id].callback(None) elif isinstance(inc_msg, message.Event): topic = inc_msg.topic or self._topic_lookup[inc_msg.subscription] try: payload_format, mapped_topic, payload = yield self.factory.transform_wamp( topic, inc_msg) except: self.log.failure() else: self._mqtt.send_publish(mapped_topic, 0, payload, retained=inc_msg.retained or False) elif isinstance(inc_msg, message.Goodbye): if self._mqtt.transport: self._mqtt.transport.loseConnection() self._mqtt.transport = None else: self.log.warn('cannot process unimplemented message: {inc_msg}', inc_msg=inc_msg) def connectionMade(self, ignore_handshake=False): if ignore_handshake or not ISSLTransport.providedBy(self.transport): self._when_ready() def connectionLost(self, reason): if self._wamp_session: msg = message.Goodbye() self._wamp_session.onMessage(msg) del self._wamp_session def handshakeCompleted(self): self._when_ready() def _when_ready(self): if self._wamp_session: return self._mqtt.transport = self.transport self._wamp_session = RouterSession( self.factory._router_session_factory._routerFactory) self._wamp_transport = WampTransport(self.factory, self.on_message, self.transport) self._wamp_session.onOpen(self._wamp_transport) self._wamp_session._transport_config = self.factory._options def process_connect(self, packet): try: self.log.debug( 'WampMQTTServerProtocol.process_connect(packet={packet})', packet=packet) self._waiting_for_connect = Deferred() roles = { u"subscriber": role.RoleSubscriberFeatures(payload_transparency=True), u"publisher": role.RolePublisherFeatures(payload_transparency=True, x_acknowledged_event_delivery=True) } realm = self.factory._options.get('realm', None) methods = [] if ISSLTransport.providedBy(self.transport): methods.append(u"tls") if packet.username and packet.password: methods.append(u"ticket") msg = message.Hello(realm=realm, roles=roles, authmethods=methods, authid=packet.username) self._pw_challenge = packet.password else: methods.append(u"anonymous") msg = message.Hello(realm=realm, roles=roles, authmethods=methods, authid=packet.client_id) self._wamp_session.onMessage(msg) if packet.flags.will: @inlineCallbacks @self._waiting_for_connect.addCallback 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) return self._waiting_for_connect except: self.log.failure() @inlineCallbacks 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_publish_qos_0(self, event): try: return self._publish(event) except: self.log.failure() def process_publish_qos_1(self, event): try: return self._publish(event, acknowledge=True) except: self.log.failure() def process_puback(self, event): return def process_pubrec(self, event): return def process_pubrel(self, event): return def process_pubcomp(self, event): return 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: self.log.failure() packet_watch[request_id] = {"response": 128} @inlineCallbacks def process_unsubscribe(self, packet): for topic in packet.topics: if topic in self._subscriptions: yield self._subscriptions.pop(topic).unsubscribe() return def dataReceived(self, data): self._mqtt.dataReceived(data)