#!/usr/bin/env python # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 from __future__ import division, print_function import json import os import signal import mimetypes from tornado.httpserver import HTTPServer from tornado.ioloop import IOLoop, PeriodicCallback from tornado.web import Application import tornado import websocket from websocket import trigger_event import state from tasks import Tasks import link import logging logger = logging.getLogger('server') root_dir = os.path.normpath(os.path.abspath(os.path.dirname(__file__))) STATIC_PATH = os.path.join(root_dir, 'static') class BaseHandler(tornado.web.RequestHandler): def serve_static(self, path, mimetype=None, include_body=True): if not mimetype: mimetype = mimetypes.guess_type(path)[0] logging.debug('serve %s', path) if os.path.exists(path): self.set_header('Content-Type', mimetype) self.set_header('Content-Length', str(os.stat(path).st_size)) if include_body: with open(path) as fd: self.write(fd.read()) else: self.set_status(404) return def render_json(self, response): response = json.dumps(response) self.set_header('Content-Type', 'application/json') self.set_header('Content-Length', str(len(response))) self.write(response) self.finish() class RemoteHandler(BaseHandler): def post(self, action): data = json.loads(self.request.body) response = {} print ('GOT remote request', action, data) if action == 'info': response = state.info elif action == 'message': data['from'] = self.request.headers['From'] trigger_event(action, data) else: response = {'error': 'unknown action'} return self.render_json(response) class MainHandler(BaseHandler): def get(self, path): path = path[1:] if not path: path = 'index.html' path = os.path.join(STATIC_PATH, path) self.serve_static(path) def post(self, path): action = path.split('/')[1] data = json.loads(self.request.body) response = {} if action in ('info', 'ping'): if 'id' in data: id = data['id'] del data['id'] response = link.remote_json(id, action, data) return self.render_json(response) if __name__ == '__main__': address = '' port = int(os.environ.get('PORT', 8000)) logging.basicConfig(level=logging.DEBUG) options = { 'debug': True, } handlers = [ (r'/ws', websocket.Handler), (r"/remote/(.*)", RemoteHandler), (r"(.*)", MainHandler), ] http_server = HTTPServer(Application(handlers, **options)) http_server.listen(port, address) state.tasks = Tasks() state.main = IOLoop.instance() state._status = PeriodicCallback(lambda: state.info.update(link.post('info')), 60000) state._status.start() if ':' in address: host = '[%s]' % address elif not address: host = '[::1]' else: host = address url = 'http://%s:%s/' % (host, port) link.add('chat', url + 'remote/') state.info = link.post('info') print('listening at %s' % url) def shutdown(): state.tasks.join() http_server.stop() signal.signal(signal.SIGTERM, shutdown) try: state.main.start() except: print('shutting down...') shutdown()