You've already forked calibre-web
							
							
				mirror of
				https://github.com/janeczku/calibre-web.git
				synced 2025-10-30 23:57:40 +02:00 
			
		
		
		
	Refactored WSGIServer handling
Restart of gevent server now working
This commit is contained in:
		
							
								
								
									
										44
									
								
								cps.py
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								cps.py
									
									
									
									
									
								
							| @@ -10,44 +10,12 @@ sys.path.append(base_path) | ||||
| sys.path.append(os.path.join(base_path, 'cps')) | ||||
| sys.path.append(os.path.join(base_path, 'vendor')) | ||||
|  | ||||
| from cps import web | ||||
| try: | ||||
|     from gevent.pywsgi import WSGIServer | ||||
|     gevent_present = True | ||||
| except ImportError: | ||||
|     from tornado.wsgi import WSGIContainer | ||||
|     from tornado.httpserver import HTTPServer | ||||
|     from tornado.ioloop import IOLoop | ||||
|     gevent_present = False | ||||
| from cps.server import Server | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     if gevent_present: | ||||
|         web.app.logger.info('Attempting to start gevent') | ||||
|         web.start_gevent() | ||||
|     else: | ||||
|         web.app.logger.info('Starting Tornado webserver') | ||||
|         # Max Buffersize set to 200MB | ||||
|         if web.ub.config.get_config_certfile() and web.ub.config.get_config_keyfile(): | ||||
|             ssl={"certfile": web.ub.config.get_config_certfile(), | ||||
|                  "keyfile": web.ub.config.get_config_keyfile()} | ||||
|         else: | ||||
|             ssl=None | ||||
|         http_server = HTTPServer(WSGIContainer(web.app), | ||||
|                     max_buffer_size = 209700000, | ||||
|                     ssl_options=ssl) | ||||
|         http_server.listen(web.ub.config.config_port) | ||||
|         IOLoop.instance().start() | ||||
|         IOLoop.instance().close(True) | ||||
|     Server.startServer() | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     if web.helper.global_task == 0: | ||||
|         web.app.logger.info("Performing restart of Calibre-web") | ||||
|         if os.name == 'nt': | ||||
|             arguments = ["\"" + sys.executable + "\""] | ||||
|             for e in sys.argv: | ||||
|                 arguments.append("\"" + e + "\"") | ||||
|             os.execv(sys.executable, arguments) | ||||
|         else: | ||||
|             os.execl(sys.executable, sys.executable, *sys.argv) | ||||
|     else: | ||||
|         web.app.logger.info("Performing shutdown of Calibre-web") | ||||
|     sys.exit(0) | ||||
|   | ||||
| @@ -36,12 +36,12 @@ import threading | ||||
| import shutil | ||||
| import requests | ||||
| import zipfile | ||||
| from tornado.ioloop import IOLoop | ||||
| try: | ||||
|     import gdriveutils as gd | ||||
| except ImportError: | ||||
|     pass | ||||
| import web | ||||
| import server | ||||
|  | ||||
| try: | ||||
|     import unidecode | ||||
| @@ -50,7 +50,6 @@ except ImportError: | ||||
|     use_unidecode = False | ||||
|  | ||||
| # Global variables | ||||
| global_task = None | ||||
| updater_thread = None | ||||
|  | ||||
| RET_SUCCESS = 1 | ||||
| @@ -388,7 +387,6 @@ class Updater(threading.Thread): | ||||
|         self.status = 0 | ||||
|  | ||||
|     def run(self): | ||||
|         global global_task | ||||
|         self.status = 1 | ||||
|         r = requests.get('https://api.github.com/repos/janeczku/calibre-web/zipball/master', stream=True) | ||||
|         fname = re.findall("filename=(.+)", r.headers['content-disposition'])[0] | ||||
| @@ -400,19 +398,13 @@ class Updater(threading.Thread): | ||||
|         self.status = 4 | ||||
|         self.update_source(os.path.join(tmp_dir, os.path.splitext(fname)[0]), ub.config.get_main_dir) | ||||
|         self.status = 5 | ||||
|         global_task = 0 | ||||
|         db.session.close() | ||||
|         db.engine.dispose() | ||||
|         ub.session.close() | ||||
|         ub.engine.dispose() | ||||
|         self.status = 6 | ||||
|  | ||||
|         if web.gevent_server: | ||||
|             web.gevent_server.stop() | ||||
|         else: | ||||
|             # stop tornado server | ||||
|             server = IOLoop.instance() | ||||
|             server.add_callback(server.stop) | ||||
|         server.Server.setRestartTyp(True) | ||||
|         server.Server.stopServer() | ||||
|         self.status = 7 | ||||
|  | ||||
|     def get_update_status(self): | ||||
|   | ||||
							
								
								
									
										103
									
								
								cps/server.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								cps/server.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| #!/usr/bin/env python | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
|  | ||||
| from socket import error as SocketError | ||||
| import sys | ||||
| import os | ||||
| try: | ||||
|     from gevent.pywsgi import WSGIServer | ||||
|     from gevent import monkey | ||||
|     from gevent.pool import Pool | ||||
|     from gevent import __version__ as geventVersion | ||||
|     gevent_present = True | ||||
| except ImportError: | ||||
|     from tornado.wsgi import WSGIContainer | ||||
|     from tornado.httpserver import HTTPServer | ||||
|     from tornado.ioloop import IOLoop | ||||
|     from tornado import version as tornadoVersion | ||||
|     gevent_present = False | ||||
|  | ||||
| import web | ||||
|  | ||||
|  | ||||
| class server: | ||||
|  | ||||
|     wsgiserver = None | ||||
|     restart= False | ||||
|  | ||||
|     def __init__(self): | ||||
|         pass | ||||
|  | ||||
|     def start_gevent(self): | ||||
|         try: | ||||
|             ssl_args = dict() | ||||
|             if web.ub.config.get_config_certfile() and web.ub.config.get_config_keyfile(): | ||||
|                 ssl_args = {"certfile": web.ub.config.get_config_certfile(), | ||||
|                             "keyfile": web.ub.config.get_config_keyfile()} | ||||
|             if os.name == 'nt': | ||||
|                 self.wsgiserver= WSGIServer(('0.0.0.0', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args) | ||||
|             else: | ||||
|                 self.wsgiserver = WSGIServer(('', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args) | ||||
|             self.wsgiserver.serve_forever() | ||||
|  | ||||
|         except SocketError: | ||||
|             web.app.logger.info('Unable to listen on \'\', trying on IPv4 only...') | ||||
|             self.wsgiserver = WSGIServer(('0.0.0.0', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args) | ||||
|             self.wsgiserver.serve_forever() | ||||
|         except: | ||||
|             pass | ||||
|  | ||||
|     def startServer(self): | ||||
|         if gevent_present: | ||||
|             web.app.logger.info('Starting Gevent server') | ||||
|             # leave subprocess out to allow forking for fetchers and processors | ||||
|             monkey.patch_all(subprocess=False) | ||||
|             self.start_gevent() | ||||
|         else: | ||||
|             web.app.logger.info('Starting Tornado server') | ||||
|             if web.ub.config.get_config_certfile() and web.ub.config.get_config_keyfile(): | ||||
|                 ssl={"certfile": web.ub.config.get_config_certfile(), | ||||
|                      "keyfile": web.ub.config.get_config_keyfile()} | ||||
|             else: | ||||
|                 ssl=None | ||||
|             # Max Buffersize set to 200MB | ||||
|             http_server = HTTPServer(WSGIContainer(web.app), | ||||
|                         max_buffer_size = 209700000, | ||||
|                         ssl_options=ssl) | ||||
|             http_server.listen(web.ub.config.config_port) | ||||
|             self.wsgiserver=IOLoop.instance() | ||||
|             self.wsgiserver.start()     # wait for stop signal | ||||
|             self.wsgiserver.close(True) | ||||
|  | ||||
|         if self.restart == True: | ||||
|             web.app.logger.info("Performing restart of Calibre-web") | ||||
|             if os.name == 'nt': | ||||
|                 arguments = ["\"" + sys.executable + "\""] | ||||
|                 for e in sys.argv: | ||||
|                     arguments.append("\"" + e + "\"") | ||||
|                 os.execv(sys.executable, arguments) | ||||
|             else: | ||||
|                 os.execl(sys.executable, sys.executable, *sys.argv) | ||||
|         else: | ||||
|             web.app.logger.info("Performing shutdown of Calibre-web") | ||||
|         sys.exit(0) | ||||
|  | ||||
|     def setRestartTyp(self,starttyp): | ||||
|         self.restart=starttyp | ||||
|  | ||||
|     def stopServer(self): | ||||
|         if gevent_present: | ||||
|             self.wsgiserver.close() | ||||
|         else: | ||||
|             self.wsgiserver.add_callback(self.wsgiserver.stop) | ||||
|  | ||||
|     def getNameVersion(self): | ||||
|         if gevent_present: | ||||
|             return {'gevent':geventVersion} | ||||
|         else: | ||||
|             return {'tornado':tornadoVersion} | ||||
|  | ||||
|  | ||||
| # Start Instance of Server | ||||
| Server=server() | ||||
| @@ -38,6 +38,18 @@ | ||||
|       <th>Python</th> | ||||
|       <td>{{versions['PythonVersion']}}</td> | ||||
|     </tr> | ||||
|     {% if 'tornado' in versions %} | ||||
|     <tr> | ||||
|       <th>Tornado web server</th> | ||||
|       <td>v{{versions['tornado']}}</td> | ||||
|     </tr> | ||||
|     {% endif %} | ||||
|     {% if 'gevent' in versions %} | ||||
|     <tr> | ||||
|       <th>Gevent web server</th> | ||||
|       <td>v{{versions['gevent']}}</td> | ||||
|     </tr> | ||||
|     {% endif %} | ||||
|     <tr> | ||||
|       <th>Kindlegen</th> | ||||
|       <td>{{versions['KindlegenVersion']}}</td> | ||||
| @@ -70,10 +82,6 @@ | ||||
|       <th>Flask Principal</th> | ||||
|       <td>v{{versions['flask_principal']}}</td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|       <th>Tornado web server</th> | ||||
|       <td>v{{versions['tornado']}}</td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|       <th>ISO639 Languages</th> | ||||
|       <td>v{{versions['iso639']}}</td> | ||||
|   | ||||
							
								
								
									
										47
									
								
								cps/web.py
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								cps/web.py
									
									
									
									
									
								
							| @@ -71,15 +71,12 @@ import subprocess | ||||
| import re | ||||
| import db | ||||
| from shutil import move, copyfile | ||||
| from tornado.ioloop import IOLoop | ||||
| import shutil | ||||
| import gdriveutils | ||||
| import tempfile | ||||
| import hashlib | ||||
| from redirect import redirect_back, is_safe_url | ||||
|  | ||||
| from tornado import version as tornadoVersion | ||||
| from socket import error as SocketError | ||||
|  | ||||
| try: | ||||
|     from urllib.parse import quote | ||||
| @@ -93,13 +90,13 @@ except ImportError: | ||||
|     from flask_login.__about__ import __version__ as flask_loginVersion | ||||
|  | ||||
| import time | ||||
| import server | ||||
|  | ||||
| current_milli_time = lambda: int(round(time.time() * 1000)) | ||||
|  | ||||
|  | ||||
| # Global variables | ||||
| gdrive_watch_callback_token = 'target=calibreweb-watch_files' | ||||
| global_task = None | ||||
|  | ||||
| ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'djvu', 'prc', 'doc', 'docx', 'fb2']) | ||||
|  | ||||
| @@ -218,8 +215,6 @@ app = (Flask(__name__)) | ||||
| app.wsgi_app = ReverseProxied(app.wsgi_app) | ||||
| cache_buster.init_cache_busting(app) | ||||
|  | ||||
| gevent_server = None | ||||
|  | ||||
| formatter = logging.Formatter( | ||||
|     "[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s") | ||||
| file_handler = RotatingFileHandler(config.get_config_logfile(), maxBytes=50000, backupCount=2) | ||||
| @@ -1471,7 +1466,8 @@ def stats(): | ||||
|     versions['flask'] = flaskVersion | ||||
|     versions['flasklogin'] = flask_loginVersion | ||||
|     versions['flask_principal'] = flask_principalVersion | ||||
|     versions['tornado'] = tornadoVersion | ||||
|     versions.update(server.Server.getNameVersion()) | ||||
|     # versions['tornado'] = tornadoVersion | ||||
|     versions['iso639'] = iso639Version | ||||
|     versions['requests'] = requests.__version__ | ||||
|     versions['pysqlite'] = db.engine.dialect.dbapi.version | ||||
| @@ -1640,9 +1636,7 @@ def on_received_watch_confirmation(): | ||||
| @login_required | ||||
| @admin_required | ||||
| def shutdown(): | ||||
|     # global global_task | ||||
|     task = int(request.args.get("parameter").strip()) | ||||
|     helper.global_task = task | ||||
|     if task == 1 or task == 0:  # valid commandos received | ||||
|         # close all database connections | ||||
|         db.session.close() | ||||
| @@ -1650,15 +1644,15 @@ def shutdown(): | ||||
|         ub.session.close() | ||||
|         ub.engine.dispose() | ||||
|         # stop gevent server | ||||
|         # gevent_server.stop() | ||||
|         # stop tornado server | ||||
|         server = IOLoop.instance() | ||||
|         server.add_callback(server.stop) | ||||
|  | ||||
|         showtext = {} | ||||
|         if task == 0: | ||||
|             showtext['text'] = _(u'Server restarted, please reload page') | ||||
|             server.Server.setRestartTyp(True) | ||||
|         else: | ||||
|             showtext['text'] = _(u'Performing shutdown of server, please close window') | ||||
|             server.Server.setRestartTyp(False) | ||||
|         server.Server.stopServer() | ||||
|         return json.dumps(showtext) | ||||
|     else: | ||||
|         if task == 2: | ||||
| @@ -2498,7 +2492,6 @@ def basic_configuration(): | ||||
|  | ||||
|  | ||||
| def configuration_helper(origin): | ||||
|     # global global_task | ||||
|     reboot_required = False | ||||
|     gdriveError=None | ||||
|     db_change = False | ||||
| @@ -2705,10 +2698,9 @@ def configuration_helper(origin): | ||||
|             # db.engine.dispose() # ToDo verify correct | ||||
|             ub.session.close() | ||||
|             ub.engine.dispose() | ||||
|             # stop tornado server | ||||
|             server = IOLoop.instance() | ||||
|             server.add_callback(server.stop) | ||||
|             helper.global_task = 0 | ||||
|             # stop Server | ||||
|             server.Server.setRestartTyp(True) | ||||
|             server.Server.stopServer() | ||||
|             app.logger.info('Reboot required, restarting') | ||||
|         if origin: | ||||
|             success = True | ||||
| @@ -3386,22 +3378,3 @@ def upload(): | ||||
|     else: | ||||
|         return redirect(url_for("index")) | ||||
|  | ||||
| def start_gevent(): | ||||
|     from gevent.pywsgi import WSGIServer | ||||
|     global gevent_server | ||||
|     try: | ||||
|         ssl_args=dict() | ||||
|         if ub.config.get_config_certfile() and ub.config.get_config_keyfile(): | ||||
|             ssl_args = {"certfile": ub.config.get_config_certfile(), | ||||
|                         "keyfile": ub.config.get_config_keyfile()} | ||||
|         if os.name == 'nt': | ||||
|             gevent_server = WSGIServer(('0.0.0.0', ub.config.config_port), app, **ssl_args) | ||||
|         else: | ||||
|             gevent_server = WSGIServer(('', ub.config.config_port), app, **ssl_args) | ||||
|         gevent_server.serve_forever() | ||||
|     except SocketError: | ||||
|         app.logger.info('Unable to listen on \'\', trying on IPv4 only...') | ||||
|         gevent_server = WSGIServer(('0.0.0.0', ub.config.config_port), app, **ssl_args) | ||||
|         gevent_server.serve_forever() | ||||
|     except: | ||||
|         pass | ||||
|   | ||||
		Reference in New Issue
	
	Block a user