98 lines
3.1 KiB
Python
98 lines
3.1 KiB
Python
|
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
|