| from Queue import Queue |
| import logging |
| import os |
| import socket |
| import threading |
| import time |
| |
| # This line makes sure that tornado is installed and in sys.path |
| import thirdparty.autoinstalled.tornado |
| import tornado.ioloop |
| import tornado.web |
| import tornado.websocket |
| import tornado.template |
| from tornado.httpserver import HTTPServer |
| |
| |
| class FeedbackServer: |
| def __init__(self): |
| self._client = None |
| self._feedback_server_thread = None |
| self._port = 9090 |
| self._application = None |
| self._server_is_ready = None |
| self._io_loop = None |
| self._messages = Queue() |
| self._client_loaded = threading.Semaphore(0) |
| |
| def _create_app(self): |
| return HTTPServer(tornado.web.Application([ |
| (r'/ws', FeedbackServer.WSHandler(self)), |
| (r'/', FeedbackServer.MainHandler(self)), |
| ])) |
| |
| def _start_server(self): |
| self._io_loop = tornado.ioloop.IOLoop() |
| self._io_loop.make_current() |
| self._application = self._create_app() |
| while True: |
| try: |
| self._application.listen(self._port) |
| print 'Running feedback server at http://localhost:{}'.format(self._port) |
| break |
| except socket.error as err: |
| self._port += 1 |
| except: |
| print 'Feedback server failed to start' |
| break |
| self._server_is_ready.release() |
| self._io_loop.start() |
| |
| def _send_all_messages(self): |
| if self._client: |
| while not self._messages.empty(): |
| message = self._messages.get() |
| self._client.write_message(message) |
| |
| def start(self): |
| self._server_is_ready = threading.Semaphore(0) |
| self._feedback_server_thread = threading.Thread(target=self._start_server) |
| self._feedback_server_thread.start() |
| self._server_is_ready.acquire() |
| return self._port |
| |
| def stop(self): |
| self._client_loaded = threading.Semaphore(0) |
| self._application.stop() |
| self._io_loop.add_callback(lambda x: x.stop(), self._io_loop) |
| self._feedback_server_thread.join() |
| |
| def send_message(self, new_message): |
| self._messages.put(new_message) |
| self._io_loop.add_callback(self._send_all_messages) |
| |
| def wait_until_client_has_loaded(self): |
| self._client_loaded.acquire() |
| |
| @staticmethod |
| def MainHandler(feedback_server): |
| class Handler(tornado.web.RequestHandler): |
| def get(self): |
| loader = tornado.template.Loader('.') |
| client_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'feedback_client.html') |
| self.write(loader.load(client_path).generate(port=feedback_server._port)) |
| |
| return Handler |
| |
| @staticmethod |
| def WSHandler(feedback_server): |
| class Handler(tornado.websocket.WebSocketHandler): |
| def open(self): |
| feedback_server._client = self |
| feedback_server._client_loaded.release() |
| |
| def on_close(self): |
| feedback_server._client = None |
| |
| return Handler |