# Path: pyaiot/common/messaging.py
# 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
# class GatewayBase(web.Application, GatewayBaseMixin, metaclass=ABCMeta):
#     """Base gateway application.
# 
#     All abstractmethods should be reimplemented to match the specific
#     communication protocols used by subclasses (CoAP, MQTT, websocket, etc).
#     """
# 
#     def __init__(self, keys, options, handlers=[]):
#         if options.debug:
#             logger.setLevel(logging.DEBUG)
# 
#         self.options = options
#         self.nodes = {}
#         self.broker = None
#         self.keys = keys
#         settings = {'debug': True}
# 
#         # Create connection to broker
#         asyncio.ensure_future(self.create_broker_connection(
#             "ws://{}:{}/gw".format(options.broker_host, options.broker_port)))
# 
#         super().__init__(handlers, **settings)
#         logger.debug('Base Gateway application started')
# 
#     @abstractmethod
#     def update_node_resource(self, node, resource, value):
#         """Send an update to a node to change its resource with given value.
# 
#         This is dependent on the protocol used to communicate with nodes (CoAP,
#         MQTT, etc) and has to be implemented in the protocol specific nodes
#         controller.
# 
#         Should be a coroutine."""
# 
#     @abstractmethod
#     def discover_node(self, node):
#         """Start a discovery procedure on a node.
# 
#         After the discovery is done, all resources (or endpoints) exposed by a
#         node are available using the `resource` attribute of the given node.
# 
#         This is dependent on the protocol used to communicate with nodes (CoAP,
#         MQTT, etc) and has to be implemented in the protocol specific nodes
#         controller.
# 
#         Should be a coroutine."""
# 
# Path: pyaiot/gateway/common/node.py
# class Node():
#     """Class for managed nodes."""
# 
#     def __init__(self, uid, **default_resources):
#         self.uid = uid
#         self.last_seen = time.time()
# 
#         self.resources = default_resources
# 
#     def __eq__(self, other):
#         return self.uid == other.uid
# 
#     def __gt__(self, other):
#         return self.uid > other.uid
# 
#     def __repr__(self):
#         return "Node <{}>".format(self.uid)
# 
#     def update_last_seen(self):
#         self.last_seen = time.time()
# 
#     def set_resource_value(self, resource, value):
#         if resource not in self.resources:
#             self.resources.update({resource: value})
#         else:
#             self.resources[resource] = value
# 
#     def clear_resources(self):
#         self.resources = {}


import logging
import uuid
import json
from tornado import websocket
from pyaiot.common.messaging import Message
from pyaiot.gateway.common import GatewayBase, Node
        self.application.add_node(node)

    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 on_close(self):
        """Remove websocket from internal list."""
        logger.debug("Node websocket closed")
        self.application.remove_ws(self)


class WebsocketGateway(GatewayBase):
    """Gateway application for websocket nodes on a network."""

    PROTOCOL = 'WebSocket'

    def __init__(self, keys, options):
        if options.debug:
            logger.setLevel(logging.DEBUG)

        handlers = [
            (r"/node", WebsocketNodeHandler),
        ]


# Path: pyaiot/common/messaging.py
# 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
# class GatewayBase(web.Application, GatewayBaseMixin, metaclass=ABCMeta):
#     """Base gateway application.
# 
#     All abstractmethods should be reimplemented to match the specific
#     communication protocols used by subclasses (CoAP, MQTT, websocket, etc).
#     """
# 
#     def __init__(self, keys, options, handlers=[]):
#         if options.debug:
#             logger.setLevel(logging.DEBUG)
# 
#         self.options = options
#         self.nodes = {}
#         self.broker = None
#         self.keys = keys
#         settings = {'debug': True}
# 
#         # Create connection to broker
#         asyncio.ensure_future(self.create_broker_connection(
#             "ws://{}:{}/gw".format(options.broker_host, options.broker_port)))
# 
#         super().__init__(handlers, **settings)
#         logger.debug('Base Gateway application started')
# 
#     @abstractmethod
#     def update_node_resource(self, node, resource, value):
#         """Send an update to a node to change its resource with given value.
# 
#         This is dependent on the protocol used to communicate with nodes (CoAP,
#         MQTT, etc) and has to be implemented in the protocol specific nodes
#         controller.
# 
#         Should be a coroutine."""
# 
#     @abstractmethod
#     def discover_node(self, node):
#         """Start a discovery procedure on a node.
# 
#         After the discovery is done, all resources (or endpoints) exposed by a
#         node are available using the `resource` attribute of the given node.
# 
#         This is dependent on the protocol used to communicate with nodes (CoAP,
#         MQTT, etc) and has to be implemented in the protocol specific nodes
#         controller.
# 
#         Should be a coroutine."""
# 
# Path: pyaiot/gateway/common/node.py
# class Node():
#     """Class for managed nodes."""
# 
#     def __init__(self, uid, **default_resources):
#         self.uid = uid
#         self.last_seen = time.time()
# 
#         self.resources = default_resources
# 
#     def __eq__(self, other):
#         return self.uid == other.uid
# 
#     def __gt__(self, other):
#         return self.uid > other.uid
# 
#     def __repr__(self):
#         return "Node <{}>".format(self.uid)
# 
#     def update_last_seen(self):
#         self.last_seen = time.time()
# 
#     def set_resource_value(self, resource, value):
#         if resource not in self.resources:
#             self.resources.update({resource: value})
#         else:
#             self.resources[resource] = value
# 
#     def clear_resources(self):
#         self.resources = {}


# Path: pyaiot/gateway/ws/gateway.py
import logging
import uuid
import json
from tornado import websocket
from pyaiot.common.messaging import Message
from pyaiot.gateway.common import GatewayBase, Node

        self.application.add_node(node)

    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 on_close(self):
        """Remove websocket from internal list."""
        logger.debug("Node websocket closed")
        self.application.remove_ws(self)


class WebsocketGateway(GatewayBase):
    """Gateway application for websocket nodes on a network."""

    PROTOCOL = 'WebSocket'

    def __init__(self, keys, options):
        if options.debug:
            logger.setLevel(logging.DEBUG)

        handlers = [
            (r"/node", WebsocketNodeHandler),
        ]


        GatewayBase.__init__(self, keys, options, handlers=handlers)