summaryrefslogtreecommitdiff
path: root/run_server.py
diff options
context:
space:
mode:
Diffstat (limited to 'run_server.py')
-rw-r--r--run_server.py136
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()