2014-05-04 17:26:43 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
2014-09-02 22:32:44 +00:00
|
|
|
|
2024-06-08 12:31:46 +00:00
|
|
|
import asyncio
|
2014-05-04 17:26:43 +00:00
|
|
|
import os
|
|
|
|
import sys
|
2014-08-22 16:42:08 +00:00
|
|
|
import signal
|
2014-09-05 17:02:19 +00:00
|
|
|
import time
|
2014-05-21 23:06:08 +00:00
|
|
|
|
2014-05-04 17:26:43 +00:00
|
|
|
from tornado.ioloop import IOLoop
|
2024-06-09 13:47:36 +00:00
|
|
|
import tornado.web
|
|
|
|
from tornado.web import Application
|
2014-05-04 17:26:43 +00:00
|
|
|
|
2014-08-12 08:16:57 +00:00
|
|
|
from cache import Cache
|
|
|
|
from item.handlers import EpubHandler, ReaderHandler, FileHandler
|
2015-06-06 17:54:44 +00:00
|
|
|
from item.handlers import OMLHandler, UploadHandler
|
2024-06-09 13:47:36 +00:00
|
|
|
from item.handlers import CropHandler
|
2014-08-12 08:16:57 +00:00
|
|
|
from item.icons import IconHandler
|
2014-08-09 21:40:05 +00:00
|
|
|
import db
|
2014-05-04 17:26:43 +00:00
|
|
|
import node.server
|
2014-05-19 20:14:24 +00:00
|
|
|
import oxtornado
|
2016-02-18 06:45:15 +00:00
|
|
|
import downloads
|
2014-08-12 08:16:57 +00:00
|
|
|
import settings
|
|
|
|
import setup
|
|
|
|
import state
|
2014-05-28 15:36:26 +00:00
|
|
|
import tasks
|
2014-08-12 08:16:57 +00:00
|
|
|
import websocket
|
2019-01-21 04:58:08 +00:00
|
|
|
import ui_websocket
|
2016-01-12 15:00:51 +00:00
|
|
|
import update
|
2014-05-21 22:50:59 +00:00
|
|
|
|
2014-08-12 08:16:57 +00:00
|
|
|
import logging
|
2014-05-21 23:06:08 +00:00
|
|
|
|
2015-11-29 14:56:38 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
2015-03-22 14:04:42 +00:00
|
|
|
|
2024-06-09 13:47:36 +00:00
|
|
|
class StaticFileHandler(tornado.web.StaticFileHandler):
|
|
|
|
def get_content_type(self):
|
|
|
|
if self.request.path.split('?')[0].endswith('.mjs'):
|
|
|
|
return 'application/javascript'
|
|
|
|
return super().get_content_type()
|
|
|
|
|
2014-05-21 23:06:08 +00:00
|
|
|
class MainHandler(OMLHandler):
|
|
|
|
|
|
|
|
def get(self, path):
|
2015-03-08 12:26:38 +00:00
|
|
|
version = settings.MINOR_VERSION.split('-')[0]
|
2014-09-05 17:02:19 +00:00
|
|
|
if version == 'git':
|
|
|
|
version = int(time.mktime(time.gmtime()))
|
2016-01-12 15:00:51 +00:00
|
|
|
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')
|
2014-09-05 17:02:19 +00:00
|
|
|
self.set_header('Content-Type', 'text/html')
|
|
|
|
self.set_header('Content-Length', str(len(content)))
|
2016-01-14 04:03:26 +00:00
|
|
|
self.set_header('Cache-Control', 'no-cache, no-store, must-revalidate')
|
|
|
|
self.set_header('Pragma', 'no-cache')
|
|
|
|
self.set_header('Expires', '0')
|
2014-09-05 17:02:19 +00:00
|
|
|
self.write(content)
|
2014-05-04 17:26:43 +00:00
|
|
|
|
2015-11-29 16:07:01 +00:00
|
|
|
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)
|
2015-12-02 21:05:23 +00:00
|
|
|
|
2024-06-08 12:31:46 +00:00
|
|
|
async def shutdown():
|
2016-01-31 16:45:14 +00:00
|
|
|
state.shutdown = True
|
2016-01-08 04:32:24 +00:00
|
|
|
if state.tor:
|
|
|
|
state.tor._shutdown = True
|
2016-01-31 16:45:14 +00:00
|
|
|
if state.nodes:
|
|
|
|
logger.debug('shutdown nodes')
|
2024-06-08 12:31:46 +00:00
|
|
|
await state.nodes.join()
|
2016-01-08 04:32:24 +00:00
|
|
|
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()
|
2016-02-10 14:02:32 +00:00
|
|
|
if state.update:
|
|
|
|
logger.debug('shutdown updates')
|
|
|
|
state.update.join()
|
2016-01-08 04:32:24 +00:00
|
|
|
if state.node:
|
|
|
|
state.node.stop()
|
|
|
|
if state.tor:
|
|
|
|
logger.debug('shutdown tor')
|
|
|
|
state.tor.shutdown()
|
2016-02-10 14:02:32 +00:00
|
|
|
for peer in state.peers:
|
|
|
|
state.peers[peer].join()
|
2016-01-08 04:32:24 +00:00
|
|
|
if state.PID and os.path.exists(state.PID):
|
|
|
|
logger.debug('remove %s', state.PID)
|
|
|
|
os.unlink(state.PID)
|
|
|
|
|
2014-05-04 17:26:43 +00:00
|
|
|
def run():
|
|
|
|
PID = sys.argv[2] if len(sys.argv) > 2 else None
|
2016-01-08 04:32:24 +00:00
|
|
|
if len(sys.argv) > 3 and sys.argv[2] == 'debug':
|
|
|
|
PID = sys.argv[3]
|
|
|
|
debug = True
|
|
|
|
else:
|
|
|
|
debug = False
|
2014-05-04 17:26:43 +00:00
|
|
|
|
2019-01-17 10:30:22 +00:00
|
|
|
log_format = '%(asctime)s:%(levelname)s:%(name)s:%(message)s'
|
2016-01-08 04:32:24 +00:00
|
|
|
if debug:
|
2015-11-29 16:07:01 +00:00
|
|
|
logging.basicConfig(level=logging.DEBUG, format=log_format)
|
2015-03-07 13:47:12 +00:00
|
|
|
else:
|
|
|
|
logging.basicConfig(level=logging.DEBUG,
|
2016-02-12 13:07:21 +00:00
|
|
|
handlers=[logging.FileHandler(settings.log_path, 'w', 'utf-8')],
|
2015-11-29 16:07:01 +00:00
|
|
|
format=log_format)
|
2016-02-12 13:07:21 +00:00
|
|
|
|
2014-05-04 17:26:43 +00:00
|
|
|
options = {
|
2014-05-26 10:10:56 +00:00
|
|
|
'debug': False,
|
2015-11-29 16:07:01 +00:00
|
|
|
'log_function': log_request,
|
2014-05-25 10:59:43 +00:00
|
|
|
'gzip': True
|
2014-05-04 17:26:43 +00:00
|
|
|
}
|
|
|
|
|
2019-01-17 10:30:22 +00:00
|
|
|
common_handlers = [
|
2015-03-07 07:38:26 +00:00
|
|
|
(r'/(favicon.ico)', StaticFileHandler, {'path': settings.static_path}),
|
2024-06-10 13:57:12 +00:00
|
|
|
(r'/static/oxjs/(.*)', StaticFileHandler, {'path': os.path.join(settings.top_dir, 'oxjs')}),
|
|
|
|
(r'/static/cbr.js/(.*)', StaticFileHandler, {'path': os.path.join(settings.top_dir, 'reader', 'cbr.js')}),
|
|
|
|
(r'/static/epub.js/(.*)', StaticFileHandler, {'path': os.path.join(settings.top_dir, 'reader', 'epub.js')}),
|
|
|
|
(r'/static/pdf.js/(.*)', StaticFileHandler, {'path': os.path.join(settings.top_dir, 'reader', 'pdf.js')}),
|
|
|
|
(r'/static/txt.js/(.*)', StaticFileHandler, {'path': os.path.join(settings.top_dir, 'reader', 'txt.js')}),
|
2015-03-07 07:38:26 +00:00
|
|
|
(r'/static/(.*)', StaticFileHandler, {'path': settings.static_path}),
|
2014-08-09 16:33:59 +00:00
|
|
|
(r'/(.*)/epub/(.*)', EpubHandler),
|
|
|
|
(r'/(.*?)/reader/', ReaderHandler),
|
2015-03-14 07:35:15 +00:00
|
|
|
(r'/(.*?)/cbr/', FileHandler),
|
2014-08-09 16:33:59 +00:00
|
|
|
(r'/(.*?)/pdf/', FileHandler),
|
|
|
|
(r'/(.*?)/txt/', FileHandler),
|
2014-12-13 20:01:54 +00:00
|
|
|
(r'/(.*?)/get/', FileHandler, {
|
2015-05-14 11:08:16 +00:00
|
|
|
'attachment': True
|
2014-12-13 20:01:54 +00:00
|
|
|
}),
|
2024-06-09 13:47:36 +00:00
|
|
|
(r'/(.*)/2048p(\d*),(\d*),(\d*),(\d*),(\d*).jpg', CropHandler),
|
2014-08-09 16:33:59 +00:00
|
|
|
(r'/(.*)/(cover|preview)(\d*).jpg', IconHandler),
|
2019-01-17 10:30:22 +00:00
|
|
|
]
|
|
|
|
handlers = common_handlers + [
|
2015-06-06 17:54:44 +00:00
|
|
|
(r'/api/upload/', UploadHandler, dict(context=db.session)),
|
2014-08-09 21:40:05 +00:00
|
|
|
(r'/api/', oxtornado.ApiHandler, dict(context=db.session)),
|
2019-01-21 04:58:08 +00:00
|
|
|
(r'/ui_socket', ui_websocket.Handler),
|
2014-05-04 17:26:43 +00:00
|
|
|
(r'/ws', websocket.Handler),
|
2014-08-09 16:33:59 +00:00
|
|
|
(r"(.*)", MainHandler),
|
2014-05-04 17:26:43 +00:00
|
|
|
]
|
2019-01-17 10:30:22 +00:00
|
|
|
public_handlers = common_handlers + [
|
|
|
|
(r'/api/', oxtornado.ApiHandler, dict(context=db.session, public=True)),
|
|
|
|
(r'/ws', websocket.Handler, dict(public=True)),
|
|
|
|
(r"(.*)", MainHandler),
|
|
|
|
]
|
2014-05-04 17:26:43 +00:00
|
|
|
|
2016-01-18 05:23:59 +00:00
|
|
|
setup.create_db()
|
2019-01-13 08:01:09 +00:00
|
|
|
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)
|
2014-05-17 00:14:15 +00:00
|
|
|
|
2019-01-17 10:30:22 +00:00
|
|
|
# public server
|
2024-06-08 11:47:52 +00:00
|
|
|
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)
|
2019-01-17 10:30:22 +00:00
|
|
|
|
2014-05-04 17:26:43 +00:00
|
|
|
if PID:
|
|
|
|
with open(PID, 'w') as pid:
|
|
|
|
pid.write('%s' % os.getpid())
|
|
|
|
|
2016-01-12 15:00:51 +00:00
|
|
|
state.update = update.update_available()
|
2016-01-08 04:32:24 +00:00
|
|
|
state.PID = PID
|
|
|
|
state.http_server = http_server
|
2014-05-17 00:14:15 +00:00
|
|
|
state.main = IOLoop.instance()
|
2016-01-05 15:12:25 +00:00
|
|
|
state.cache = Cache(ttl=60)
|
2014-05-17 00:14:15 +00:00
|
|
|
|
2014-05-04 17:26:43 +00:00
|
|
|
def start_node():
|
|
|
|
import nodes
|
2015-11-26 00:26:10 +00:00
|
|
|
import tor
|
2015-11-30 23:26:35 +00:00
|
|
|
import bandwidth
|
|
|
|
state.bandwidth = bandwidth.Bandwidth()
|
2015-11-26 00:26:10 +00:00
|
|
|
state.tor = tor.Tor()
|
|
|
|
state.nodes = nodes.Nodes()
|
2019-02-10 12:16:35 +00:00
|
|
|
state.node = node.server.start()
|
2017-06-03 20:50:14 +00:00
|
|
|
|
2015-12-02 21:05:23 +00:00
|
|
|
def publish():
|
2015-11-26 00:26:10 +00:00
|
|
|
if not state.tor.is_online():
|
2016-01-09 05:46:35 +00:00
|
|
|
state.main.call_later(10, publish)
|
2015-11-26 00:26:10 +00:00
|
|
|
else:
|
|
|
|
nodes.publish_node()
|
2015-12-02 21:05:23 +00:00
|
|
|
state.main.add_callback(publish)
|
2016-01-24 10:34:29 +00:00
|
|
|
state.main.call_later(10, lambda: state.tasks.queue('scanimport'))
|
2016-01-12 15:00:51 +00:00
|
|
|
|
|
|
|
if not state.update:
|
2016-02-18 06:45:15 +00:00
|
|
|
state.downloads = downloads.Downloads()
|
2016-01-12 15:00:51 +00:00
|
|
|
state.tasks = tasks.Tasks()
|
|
|
|
state.main.add_callback(start_node)
|
|
|
|
else:
|
2016-02-10 14:02:32 +00:00
|
|
|
state.update = update.Update()
|
2016-01-12 15:00:51 +00:00
|
|
|
|
2014-05-14 09:57:11 +00:00
|
|
|
if ':' in settings.server['address']:
|
|
|
|
host = '[%s]' % settings.server['address']
|
|
|
|
elif not settings.server['address']:
|
2015-02-22 11:23:06 +00:00
|
|
|
host = '127.0.0.1'
|
2014-05-14 09:57:11 +00:00
|
|
|
else:
|
|
|
|
host = settings.server['address']
|
|
|
|
url = 'http://%s:%s/' % (host, settings.server['port'])
|
2014-08-11 11:08:28 +00:00
|
|
|
print('open browser at %s' % url)
|
2015-03-22 14:04:42 +00:00
|
|
|
logger.debug('Starting OML %s at %s', settings.VERSION, url)
|
2014-08-22 16:42:08 +00:00
|
|
|
|
2024-06-08 12:31:46 +00:00
|
|
|
signal.signal(signal.SIGTERM, lambda _, __: sys.exit(0))
|
2014-08-22 16:42:08 +00:00
|
|
|
|
2014-08-09 18:32:41 +00:00
|
|
|
try:
|
|
|
|
state.main.start()
|
|
|
|
except:
|
2014-08-09 21:40:05 +00:00
|
|
|
print('shutting down...')
|
2024-06-08 12:31:46 +00:00
|
|
|
asyncio.run(shutdown())
|