def fetch_nodes_cache(self, client): """ Send cached nodes information to a given client. :param client: the ID of the client """ logger.debug( "Fetching cached information of registered nodes '{}'.".format( self.nodes)) for node in self.nodes.values(): self.send_to_broker(Message.new_node(node.uid, dst=client)) for resource, value in node.resources.items(): self.send_to_broker( Message.update_node(node.uid, resource, value, dst=client))
def remove_node(self, node): """ Remove the given node from known nodes and notify the broker. """ self.nodes.pop(node.uid) logger.debug("Remaining nodes {}".format(self.nodes)) self.send_to_broker(Message.out_node(node.uid))
def forward_data_from_node(self, node, resource, value): """ Send data received from a node to the broker via the gateway. """ logger.debug( "Sending data received from node '{}': '{}', '{}'.".format( node, resource, value)) node.set_resource_value(resource, value) self.send_to_broker(Message.update_node(node.uid, resource, value))
def on_message(self, raw): """ Triggered when a message is received from the web client. """ message, reason = Message.check_message(raw) if message is not None: self.application.on_node_message(self, message) else: logger.debug("Invalid message, closing websocket") self.close(code=1003, reason="{}.".format(reason))
def reset_node(self, node, default_resources={}): """ Reset a node: clear the current resource and reinitialize them. """ node.clear_resources() node.set_resource_value('protocol', self.PROTOCOL) for resource, value in default_resources.items(): node.set_resource_value(resource, value) self.send_to_broker(Message.reset_node(node.uid)) self.discover_node(node)
def add_node(self, node): """ Add a new node to the list of nodes and notify the broker. """ node.set_resource_value('protocol', self.PROTOCOL) self.nodes.update({node.uid: node}) self.send_to_broker(Message.new_node(node.uid)) # for res, value in node.resources.items(): # self.send_to_broker(Message.update_node(node.uid, res, value)) yield self.discover_node(node)
def remove_ws(self, ws): """ Remove websocket that has been closed. """ if ws in self.clients: self.clients.pop(ws) elif ws in self.gateways.keys(): # Notify clients that the nodes behind the closed gateway are out. for node_uid in self.gateways[ws]: self.broadcast(Message.out_node(node_uid)) self.gateways.pop(ws)
def on_client_message(self, ws, message): """ Handle a message received from a client. """ logger.debug( "Handling message '{}' received from client websocket.".format( message)) if message['type'] == "new": logger.info("New client connected: {}".format(ws.uid)) if ws.uid not in self.clients.keys(): self.clients.update({ws.uid: ws}) elif message['type'] == "update": logger.debug("New message from client: {}".format(ws.uid)) # Simply forward this message to satellite gateways logger.debug("Forwarding message {} to gateways".format(message)) for gw in self.gateways: gw.write_message(Message.serialize(message))
def on_message(self, raw): """ Triggered when a message is received from the broker child. """ if not self.authentified: if verify_auth_token(raw, self.application.keys): logger.info("Gateway websocket authentication verified") self.authentified = True self.application.gateways.update({self: []}) else: logger.info( "Gateway websocket authentication failed, closing.") self.close() else: message, reason = Message.check_message(raw) if message is not None: self.application.on_gateway_message(self, message) else: logger.debug("Invalid message, closing websocket") self.close(code=1003, reason="{}.".format(reason))
def main(args): """ Main function. """ try: ws = websocket.create_connection("ws://{}:{}/node".format( args.gateway_host, args.gateway_port)) except ConnectionRefusedError: print("Cannot connect to ws://{}:{}".format(args.gateway_host, args.gateway_port)) return init_node(ws) while True: try: msg = ws.recv() except: print("Connection closed") break else: print(msg) if msg == Message.discover_node(): init_node(ws) else: msg = json.loads(msg) if msg['payload'] == '1': ws.send( json.dumps({ 'type': 'update', 'data': { 'led': '1' } })) else: ws.send( json.dumps({ 'type': 'update', 'data': { 'led': '0' } }))
def on_gateway_message(self, ws, message): """ Handle a message received from a gateway. This method redirect messages from gateways to the right destinations: - for freshly new information initiated by nodes => broadcast - for replies to new client connection => only send to this client """ logger.debug( "Handling message '{}' received from gateway.".format(message)) if message['type'] == "new": # Received when notifying clients of a new node available if not message['uid'] in self.gateways[ws]: self.gateways[ws].append(message['uid']) if message['dst'] == "all": # Occurs when an unknown new node arrived self.broadcast(Message.serialize(message)) elif message['dst'] in self.clients.keys(): # Occurs when a single client has just connected self.send_to_client(message['dst'], Message.serialize(message)) elif (message['type'] == "out" and message['uid'] in self.gateways[ws]): # Node disparition are always broadcasted to clients self.gateways[ws].remove(message['uid']) self.broadcast(Message.serialize(message)) elif message['type'] == "reset": # Occurs when a node has reset (reboot, firmware update): # require broadcast self.broadcast(Message.serialize(message)) elif (message['type'] in "update" and message['uid'] in self.gateways[ws]): if message['dst'] == "all": # Occurs when a new update was pushed by a node: # require broadcast self.broadcast(Message.serialize(message)) elif message['dst'] in self.clients.keys(): # Occurs when a new client has just connected: # Only the cached information of a node are pushed to this # specific client self.send_to_client(message['dst'], Message.serialize(message))
def discover_node(self, node): for ws, uid in self.node_mapping.items(): if node.uid == uid: yield ws.write_message(Message.discover_node()) break