# -*- coding: utf-8 -*- import os import sys import signal import time from tornado.ioloop import IOLoop from tornado.web import StaticFileHandler, Application from cache import Cache from item.handlers import EpubHandler, ReaderHandler, FileHandler from item.handlers import OMLHandler, UploadHandler from item.icons import IconHandler import db import node.server import oxtornado import downloads import settings import setup import state import tasks import websocket import ui_websocket import update import logging logger = logging.getLogger(__name__) class MainHandler(OMLHandler): def get(self, path): version = settings.MINOR_VERSION.split('-')[0] if version == 'git': version = int(time.mktime(time.gmtime())) path = os.path.join(settings.static_path, 'html', 'oml.html') with open(path) as fd: content = fd.read() content = content.replace('.js?1', '.js?%s' % version) if state.update: content = content.replace('oml.js', 'oml.update.js') self.set_header('Content-Type', 'text/html') self.set_header('Content-Length', str(len(content))) self.set_header('Cache-Control', 'no-cache, no-store, must-revalidate') self.set_header('Pragma', 'no-cache') self.set_header('Expires', '0') self.write(content) def log_request(handler): if settings.DEBUG_HTTP: if handler.get_status() < 400: log_method = logger.info elif handler.get_status() < 500: log_method = logger.warning else: log_method = logger.error request_time = 1000.0 * handler.request.request_time() log_method("%d %s %.2fms", handler.get_status(), handler._request_summary(), request_time) def shutdown(): state.shutdown = True if state.tor: state.tor._shutdown = True if state.nodes: logger.debug('shutdown nodes') state.nodes.join() if state.downloads: logger.debug('shutdown downloads') state.downloads.join() logger.debug('shutdown http_server') if state.tasks: logger.debug('shutdown tasks') state.tasks.join() if state.update: logger.debug('shutdown updates') state.update.join() if state.node: state.node.stop() if state.tor: logger.debug('shutdown tor') state.tor.shutdown() for peer in state.peers: state.peers[peer].join() if state.PID and os.path.exists(state.PID): logger.debug('remove %s', state.PID) os.unlink(state.PID) def run(): PID = sys.argv[2] if len(sys.argv) > 2 else None if len(sys.argv) > 3 and sys.argv[2] == 'debug': PID = sys.argv[3] debug = True else: debug = False log_format = '%(asctime)s:%(levelname)s:%(name)s:%(message)s' if debug: logging.basicConfig(level=logging.DEBUG, format=log_format) else: logging.basicConfig(level=logging.DEBUG, handlers=[logging.FileHandler(settings.log_path, 'w', 'utf-8')], format=log_format) options = { 'debug': False, 'log_function': log_request, 'gzip': True } common_handlers = [ (r'/(favicon.ico)', StaticFileHandler, {'path': settings.static_path}), (r'/static/oxjs/(.*)', StaticFileHandler, {'path': os.path.join(settings.base_dir, '..', 'oxjs')}), (r'/static/cbr.js/(.*)', StaticFileHandler, {'path': os.path.join(settings.base_dir, '..', 'reader', 'cbr.js')}), (r'/static/epub.js/(.*)', StaticFileHandler, {'path': os.path.join(settings.base_dir, '..', 'reader', 'epub.js')}), (r'/static/pdf.js/(.*)', StaticFileHandler, {'path': os.path.join(settings.base_dir, '..', 'reader', 'pdf.js')}), (r'/static/txt.js/(.*)', StaticFileHandler, {'path': os.path.join(settings.base_dir, '..', 'reader', 'txt.js')}), (r'/static/(.*)', StaticFileHandler, {'path': settings.static_path}), (r'/(.*)/epub/(.*)', EpubHandler), (r'/(.*?)/reader/', ReaderHandler), (r'/(.*?)/cbr/', FileHandler), (r'/(.*?)/pdf/', FileHandler), (r'/(.*?)/txt/', FileHandler), (r'/(.*?)/get/', FileHandler, { 'attachment': True }), (r'/(.*)/(cover|preview)(\d*).jpg', IconHandler), ] handlers = common_handlers + [ (r'/api/upload/', UploadHandler, dict(context=db.session)), (r'/api/', oxtornado.ApiHandler, dict(context=db.session)), (r'/ui_socket', ui_websocket.Handler), (r'/ws', websocket.Handler), (r"(.*)", MainHandler), ] public_handlers = common_handlers + [ (r'/api/', oxtornado.ApiHandler, dict(context=db.session, public=True)), (r'/ws', websocket.Handler, dict(public=True)), (r"(.*)", MainHandler), ] setup.create_db() http_server = Application(handlers, **options) max_buffer_size = 2*1024*1024*1024 http_server.listen(settings.server['port'], settings.server['address'], max_buffer_size=max_buffer_size) # public server if settings.preferences.get('enableReadOnlyService'): public_port = settings.server.get('public_port') public_address = settings.server['public_address'] if public_port: public_server = Application(public_handlers, **options) public_server.listen(public_port, public_address) if PID: with open(PID, 'w') as pid: pid.write('%s' % os.getpid()) state.update = update.update_available() state.PID = PID state.http_server = http_server state.main = IOLoop.instance() state.cache = Cache(ttl=60) def start_node(): import nodes import tor import bandwidth state.bandwidth = bandwidth.Bandwidth() state.tor = tor.Tor() state.nodes = nodes.Nodes() state.node = node.server.start() def publish(): if not state.tor.is_online(): state.main.call_later(10, publish) else: nodes.publish_node() state.main.add_callback(publish) state.main.call_later(10, lambda: state.tasks.queue('scanimport')) if not state.update: state.downloads = downloads.Downloads() state.tasks = tasks.Tasks() state.main.add_callback(start_node) else: state.update = update.Update() if ':' in settings.server['address']: host = '[%s]' % settings.server['address'] elif not settings.server['address']: host = '127.0.0.1' else: host = settings.server['address'] url = 'http://%s:%s/' % (host, settings.server['port']) print('open browser at %s' % url) logger.debug('Starting OML %s at %s', settings.VERSION, url) signal.signal(signal.SIGTERM, shutdown) try: state.main.start() except: print('shutting down...') shutdown()