diff options
Diffstat (limited to 'fg21sim/webui/handlers')
| -rw-r--r-- | fg21sim/webui/handlers/websocket.py | 107 | 
1 files changed, 30 insertions, 77 deletions
diff --git a/fg21sim/webui/handlers/websocket.py b/fg21sim/webui/handlers/websocket.py index 81e5ba3..a772aa8 100644 --- a/fg21sim/webui/handlers/websocket.py +++ b/fg21sim/webui/handlers/websocket.py @@ -20,7 +20,7 @@ References  import logging  import tornado.websocket -from tornado.escape import json_decode, json_encode +from tornado.escape import json_encode  from tornado.options import options  from ..utils import get_host_ip, ip_in_network @@ -31,25 +31,40 @@ logger = logging.getLogger(__name__)  class WSHandler(tornado.websocket.WebSocketHandler):      """ -    WebSocket for bi-directional communication between the Web UI and -    the server, which can deal with the configurations and execute the -    simulation task. - -    Generally, WebSocket send and receive data as *string*.  Therefore, -    the more complex data are stringified as JSON string before sending, -    which will be parsed after receive. - -    Each message (as a JSON object or Python dictionary) has a ``type`` -    field which will be used to determine the following action to take. +    Push messages (e.g., logging messages, configurations) to the client. + +    NOTE +    ---- +    WebSocket is a bi-directional and real-time communication protocol, which +    is great for active messages pushing. +    However, WebSocket is a rather low-level protocol.  It receives and sends +    messages independently, so it does not provide any support of +    request-response operations, RPC (remote-procedure call), etc. +    Therefore, it is hard/problematic to implement some interactions similar +    to the traditional AJAX techniques. + +    There exists some high-level sub-protocols built upon the WebSocket, e.g., +    WAMP [1]_, which provides better features and are easier to use, allowing +    to fully replace the AJAX etc. techniques. +    However, the Tornado (v4.3) currently does not support them, and the +    corresponding client JavaScript tool is also required. + +    XXX/WARNING +    ----------- +    ``WebSocket.on_message()``: may NOT be a coroutine at the moment (v4.3). +    See [2]_ and [3]_ .      Attributes      ----------      from_localhost : bool          Set to ``True`` if the access is from the localhost,          otherwise ``False``. -    configs : `~ConfigManager` -        A ``ConfigManager`` instance, for configuration manipulations when -        communicating with the Web UI. + +    References +    ---------- +    .. _[1] WAMP: Web Application Messaging Protocl, http://wamp-proto.org/ +    .. _[2] https://stackoverflow.com/a/35543856/4856091 +    .. _[3] https://stackoverflow.com/a/33724486/4856091      """      from_localhost = None @@ -100,63 +115,9 @@ class WSHandler(tornado.websocket.WebSocketHandler):          self.application.ws_clients.remove(self)          logger.warning("Removed closed WebSocket client: {0}".format(self)) -    # FIXME/XXX: -    # * How to be non-blocking ?? -    # NOTE: WebSocket.on_message: may NOT be a coroutine at the moment (v4.3) -    # References: -    # [1] https://stackoverflow.com/a/35543856/4856091 -    # [2] https://stackoverflow.com/a/33724486/4856091 -    def on_message(self, message): -        """ -        Handle incoming messages and dispatch task according to the -        message type. - -        NOTE -        ---- -        The received message (parsed to a Python dictionary) has a ``type`` -        item which will be used to determine the following action to take. - -        Currently supported message types are: -        ``configs``: -            Request or set the configurations -        ``console``: -            Control the simulation tasks, or request logging messages -        ``results``: -            Request the simulation results - -        The sent message also has a ``type`` item of same value, which the -        client can be used to figure out the proper actions. -        There is a ``success`` item which indicates the status of the -        requested operation, and an ``error`` recording the error message -        if ``success=False``. -        """ -        logger.debug("WebSocket: received message: {0}".format(message)) -        msg = json_decode(message) -        try: -            msg_type = msg["type"] -        except (KeyError, TypeError): -            logger.warning("WebSocket: skip invalid message") -            response = {"success": False, -                        "type": None, -                        "error": "type is missing"} -        else: -            if msg_type == "results": -                # Request the simulation results -                response = self._handle_results(msg) -            else: -                # Message of unknown type -                logger.warning("WebSocket: " + -                               "unknown message type: {0}".format(msg_type)) -                response = {"success": False, -                            "type": msg_type, -                            "error": "unknown message type %s" % msg_type} -        # -        msg_response = json_encode(response) -        self.write_message(msg_response) -      def broadcast(self, message):          """Broadcast/push the given message to all connected clients.""" -        for ws in self.application.ws_clients: +        for ws in self.application.websockets:              ws.write_message(message)      def _push_configs(self): @@ -177,11 +138,3 @@ class WSHandler(tornado.websocket.WebSocketHandler):          self.write_message(message)          logger.info("WebSocket: Pushed current configurations data " +                      "with validation errors to the client") - -    def _handle_results(self, msg): -        # Got a message of supported types -        msg_type = msg["type"] -        logger.info("WebSocket: " + -                    "handle message of type: {0}".format(msg_type)) -        response = {"success": True, "type": msg_type} -        return response  | 
