# Path: pyaiot/common/auth.py
# def auth_token(keys):
#     """Generate a token from the given private and secret keys."""
#     return Fernet(keys.private.encode()).encrypt(keys.secret.encode())
# 
# Path: pyaiot/common/messaging.py
# def check_broker_data(data):
#     """"Utility function that checks the data object.
# 
#     :param data: a dict with only 'uid', 'endpoint' and 'payload' keys.
# 
#     :return True of the data is correct, False otherwise
# 
#     >>> check_broker_data({'uid':1, 'endpoint':'/test', 'payload': 'ok'})
#     True
#     >>> check_broker_data({'endpoint':'/test', 'payload': 'ok'})
#     False
#     >>> check_broker_data({'uid':1, 'payload': 'ok'})
#     False
#     >>> check_broker_data({'uid':1, 'endpoint':'/test'})
#     False
#     >>> check_broker_data({'uid':1, 'endpoint':'/test', 'payload': 'ok',
#     ...                    'extra': 'too many'})
#     False
#     """
# 
#     if 'uid' not in data:
#         logger.debug("Invalid broker data: missing uid")
#     elif 'endpoint' not in data:
#         logger.debug("Invalid broker data: missing endpoint")
#     elif 'payload' not in data:
#         logger.debug("Invalid broker data: missing payload")
#     elif len(data.keys()) > 3:
#         logger.debug("Invalid broker data: too many keys")
#     else:
#         return True
#     return False
# 
# class Message():
#     """Utility class for generating and parsing service messages."""
# 
#     @staticmethod
#     def serialize(message):
#         return json.dumps(message, ensure_ascii=False)
# 
#     @staticmethod
#     def new_node(uid, dst="all"):
#         """Generate a text message indicating a new node."""
#         return Message.serialize({'type': 'new', 'uid': uid, 'dst': dst})
# 
#     @staticmethod
#     def out_node(uid):
#         """Generate a text message indicating a node to remove."""
#         return Message.serialize({'type': 'out', 'uid': uid})
# 
#     @staticmethod
#     def reset_node(uid):
#         """Generate a text message indicating a node reset."""
#         return Message.serialize({'type': 'reset', 'uid': uid})
# 
#     @staticmethod
#     def update_node(uid, endpoint, data, dst="all"):
#         """Generate a text message indicating a node update."""
#         return Message.serialize({'type': 'update',
#                                   'uid': uid,
#                                   'endpoint': endpoint,
#                                   'data': data,
#                                   'dst': dst})
# 
#     @staticmethod
#     def gateway_alive():
#         """Generate a text message indicating that a gateway is alive."""
#         return Message.serialize({'type': 'update', 'uid': 'alive'})
# 
#     @staticmethod
#     def discover_node():
#         """Generate a text message for websocket node discovery."""
#         return Message.serialize({'request': 'discover'})
# 
#     @staticmethod
#     def check_message(raw):
#         """Verify a received message is correctly formatted."""
#         reason = None
#         try:
#             message = json.loads(raw)
#         except TypeError as exc:
#             logger.warning(exc)
#             reason = "Invalid message '{}'.".format(raw)
#             message = None
#         except json.JSONDecodeError:
#             reason = ("Invalid message received "
#                       "'{}'. Only JSON format is supported.".format(raw))
#             message = None
# 
#         if message is not None:
#             if not hasattr(message, '__iter__'):
#                 reason = "Invalid message '{}'.".format(message)
#             elif 'type' not in message and 'data' not in message:
#                 reason = "Invalid message '{}'.".format(message)
#             elif (message['type'] != 'new' and message['type'] != 'update' and
#                   message['type'] != 'out' and message['type'] != 'reset'):
#                 reason = "Invalid message type '{}'.".format(message['type'])
# 
#         if reason is not None:
#             logger.warning(reason)
#             message = None
# 
#         return message, reason


import json
import logging
import asyncio
from abc import ABCMeta, abstractmethod
from tornado import web, gen
from tornado.ioloop import PeriodicCallback
from tornado.websocket import websocket_connect
from pyaiot.common.auth import auth_token
from pyaiot.common.messaging import check_broker_data, Message
        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 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 get_node(self, uid):
        """Return the node matching the given uid."""
        return self.nodes[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 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():

# Path: pyaiot/common/auth.py
# def auth_token(keys):
#     """Generate a token from the given private and secret keys."""
#     return Fernet(keys.private.encode()).encrypt(keys.secret.encode())
# 
# Path: pyaiot/common/messaging.py
# def check_broker_data(data):
#     """"Utility function that checks the data object.
# 
#     :param data: a dict with only 'uid', 'endpoint' and 'payload' keys.
# 
#     :return True of the data is correct, False otherwise
# 
#     >>> check_broker_data({'uid':1, 'endpoint':'/test', 'payload': 'ok'})
#     True
#     >>> check_broker_data({'endpoint':'/test', 'payload': 'ok'})
#     False
#     >>> check_broker_data({'uid':1, 'payload': 'ok'})
#     False
#     >>> check_broker_data({'uid':1, 'endpoint':'/test'})
#     False
#     >>> check_broker_data({'uid':1, 'endpoint':'/test', 'payload': 'ok',
#     ...                    'extra': 'too many'})
#     False
#     """
# 
#     if 'uid' not in data:
#         logger.debug("Invalid broker data: missing uid")
#     elif 'endpoint' not in data:
#         logger.debug("Invalid broker data: missing endpoint")
#     elif 'payload' not in data:
#         logger.debug("Invalid broker data: missing payload")
#     elif len(data.keys()) > 3:
#         logger.debug("Invalid broker data: too many keys")
#     else:
#         return True
#     return False
# 
# class Message():
#     """Utility class for generating and parsing service messages."""
# 
#     @staticmethod
#     def serialize(message):
#         return json.dumps(message, ensure_ascii=False)
# 
#     @staticmethod
#     def new_node(uid, dst="all"):
#         """Generate a text message indicating a new node."""
#         return Message.serialize({'type': 'new', 'uid': uid, 'dst': dst})
# 
#     @staticmethod
#     def out_node(uid):
#         """Generate a text message indicating a node to remove."""
#         return Message.serialize({'type': 'out', 'uid': uid})
# 
#     @staticmethod
#     def reset_node(uid):
#         """Generate a text message indicating a node reset."""
#         return Message.serialize({'type': 'reset', 'uid': uid})
# 
#     @staticmethod
#     def update_node(uid, endpoint, data, dst="all"):
#         """Generate a text message indicating a node update."""
#         return Message.serialize({'type': 'update',
#                                   'uid': uid,
#                                   'endpoint': endpoint,
#                                   'data': data,
#                                   'dst': dst})
# 
#     @staticmethod
#     def gateway_alive():
#         """Generate a text message indicating that a gateway is alive."""
#         return Message.serialize({'type': 'update', 'uid': 'alive'})
# 
#     @staticmethod
#     def discover_node():
#         """Generate a text message for websocket node discovery."""
#         return Message.serialize({'request': 'discover'})
# 
#     @staticmethod
#     def check_message(raw):
#         """Verify a received message is correctly formatted."""
#         reason = None
#         try:
#             message = json.loads(raw)
#         except TypeError as exc:
#             logger.warning(exc)
#             reason = "Invalid message '{}'.".format(raw)
#             message = None
#         except json.JSONDecodeError:
#             reason = ("Invalid message received "
#                       "'{}'. Only JSON format is supported.".format(raw))
#             message = None
# 
#         if message is not None:
#             if not hasattr(message, '__iter__'):
#                 reason = "Invalid message '{}'.".format(message)
#             elif 'type' not in message and 'data' not in message:
#                 reason = "Invalid message '{}'.".format(message)
#             elif (message['type'] != 'new' and message['type'] != 'update' and
#                   message['type'] != 'out' and message['type'] != 'reset'):
#                 reason = "Invalid message type '{}'.".format(message['type'])
# 
#         if reason is not None:
#             logger.warning(reason)
#             message = None
# 
#         return message, reason


# Path: pyaiot/gateway/common/gateway.py
import json
import logging
import asyncio
from abc import ABCMeta, abstractmethod
from tornado import web, gen
from tornado.ioloop import PeriodicCallback
from tornado.websocket import websocket_connect
from pyaiot.common.auth import auth_token
from pyaiot.common.messaging import check_broker_data, Message

        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 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 get_node(self, uid):
        """Return the node matching the given uid."""
        return self.nodes[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 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))