diff --git a/cps.py b/cps.py index 039c2a5e1..97863504f 100755 --- a/cps.py +++ b/cps.py @@ -42,9 +42,25 @@ def hide_console_windows(): if __name__ == '__main__': - if os.name == "nt": + # Only hide the console window on Windows when there is no interactive + # console attached. This preserves the ability to use Ctrl+C from a + # terminal (stdin is a tty) to stop the server. + if os.name == "nt" and not sys.stdin.isatty(): hide_console_windows() - main() + + try: + main() + except KeyboardInterrupt: + # Allow stopping the server with Ctrl+C from an interactive console. + try: + # Try to perform a graceful stop if web_server is available. + # Import here to avoid import-time side-effects when not needed. + from cps import web_server + web_server.stop() + except Exception: + pass + print('\nCalibre-Web: received interrupt, shutting down') + sys.exit(0) diff --git a/cps/server.py b/cps/server.py index dca407a7e..bf53a3d46 100644 --- a/cps/server.py +++ b/cps/server.py @@ -216,6 +216,12 @@ class WebServer(object): try: sock, output = self._make_gevent_listener() log.info('Starting Gevent server on %s', output) + # Also print to stdout so interactive terminals show a clear success message + try: + print(f"Calibre-Web: server started on {output}") + except Exception: + print(f"Calibre-Web: error {output}") + pass self.wsgiserver = WSGIServer(sock, self.app, log=self.access_logger, handler_class=MyWSGIHandler, error_log=log, spawn=Pool(), **ssl_args) @@ -266,6 +272,12 @@ class WebServer(object): output = _readable_listen_address(self.listen_address, self.listen_port) http_server.listen(self.listen_port, self.listen_address) log.info('Starting Tornado server on %s', output) + # Also print to stdout so interactive terminals show a clear success message + try: + print(f"Calibre-Web: server started on {output}") + except Exception: + print(f"Calibre-Web: error {output}") + pass self.wsgiserver = IOLoop.current() self.wsgiserver.start()