openmedialibrary/oml/server.py
2024-06-08 14:31:06 +01:00

207 lines
6.8 KiB
Python

# -*- coding: utf-8 -*-
import asyncio
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)
async def shutdown():
state.shutdown = True
if state.tor:
state.tor._shutdown = True
if state.nodes:
logger.debug('shutdown nodes')
await 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, lambda _, __: sys.exit(0))
try:
state.main.start()
except:
print('shutting down...')
asyncio.run(shutdown())