diff options
Diffstat (limited to 'run_server.py')
-rw-r--r-- | run_server.py | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/run_server.py b/run_server.py new file mode 100644 index 0000000..8c284d2 --- /dev/null +++ b/run_server.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python +# +# This file serves the static files in the +# web directory and provides API endpoints +# to read/write the existing markers. +# + +import os +from cStringIO import StringIO +import hashlib +import threading +import json + +import cherrypy + +class SynchronizedJSON(object): + def __init__(self, filename): + self._filename = filename + if os.path.exists(self._filename): + with open(self._filename, 'rb') as f: + self._data = f.read() + else: + self._data = '{}' + + self._sync_id = '' + self._update_sync_id() + + self.lock = threading.Lock() + self.cond = threading.Condition(self.lock) + + def _update_sync_id(self): + doc = json.loads(self._data) + if 'sync-id' in doc: + del doc['sync-id'] + hashed_data = json.dumps(doc) + h = hashlib.sha256() + h.update(hashed_data) + doc['sync-id'] = h.hexdigest() + self._data = json.dumps(doc) + self._sync_id = h.hexdigest() + + @property + def data(self): + assert self.lock.locked() + return self._data + + @property + def sync_id(self): + assert self.lock.locked() + return self._sync_id + + def set_data(self, data): + assert self.lock.locked() + + if self._data == data: + return + + self._data = data + self._update_sync_id() + + with open(self._filename + '.new', 'wb') as f: + f.write(data) + f.flush() + os.fsync(f.fileno()) + os.rename(self._filename + '.new', self._filename) + + self.cond.notify_all() + +class EventMapMarkerApi(object): + def __init__(self, path): + self.marker_doc = SynchronizedJSON(os.path.join(path, 'markers.json')) + + @cherrypy.expose + def get(self): + cherrypy.response.headers['Content-Type']= 'application/json' + with self.marker_doc.lock: + return self.marker_doc.data + + @cherrypy.expose + def poll(self, current): + cherrypy.response.headers['Content-Type']= 'application/json' + with self.marker_doc.lock: + while self.marker_doc.sync_id == current: + self.marker_doc.cond.wait(2) + if cherrypy.engine.state != cherrypy.engine.states.STARTED: + break + yield ' ' + yield self.marker_doc.data + + @cherrypy.expose + def post(self): + content_length = cherrypy.request.headers['Content-Length'] + data = cherrypy.request.body.read(int(content_length)) + + doc = json.loads(data) + + # Check sync-id + with self.marker_doc.lock: + self.marker_doc.set_data(data) + +class EventMapApi(object): + def __init__(self, path): + self.markers = EventMapMarkerApi(path) + +def test_log(msg, level): + print "%s, %s" % (msg, level) + +if __name__ == '__main__': + current_dir = os.path.dirname(os.path.abspath(__file__)) + cherrypy.engine.subscribe('log', test_log) + cherrypy.config.update({ + 'server.socket_host': '127.0.0.1', + 'server.socket_port': 8023, + 'server.thread_pool_max': 500, + 'server.thread_pool': 100, + 'log.screen': True + }) + + cherrypy.tree.mount(None, '/', { + '/': { + 'tools.staticdir.on': True, + 'tools.staticdir.dir': os.path.join(current_dir, 'web'), + 'tools.staticdir.index': 'index.html', + } + }) + + cherrypy.tree.mount(EventMapApi(current_dir), '/api', { + '/': { + 'response.timeout': 600, + 'response.stream': True + } + }) + + cherrypy.engine.signals.subscribe() + cherrypy.engine.start() + cherrypy.engine.block() |