diff options
Diffstat (limited to 'glances/outputs/glances_restful_api.py')
-rw-r--r-- | glances/outputs/glances_restful_api.py | 63 |
1 files changed, 55 insertions, 8 deletions
diff --git a/glances/outputs/glances_restful_api.py b/glances/outputs/glances_restful_api.py index ca8da563..b65f77d1 100644 --- a/glances/outputs/glances_restful_api.py +++ b/glances/outputs/glances_restful_api.py @@ -2,7 +2,7 @@ # # This file is part of Glances. # -# SPDX-FileCopyrightText: 2023 Nicolas Hennion <nicolas@nicolargo.com> +# SPDX-FileCopyrightText: 2024 Nicolas Hennion <nicolas@nicolargo.com> # # SPDX-License-Identifier: LGPL-3.0-only # @@ -14,7 +14,6 @@ import sys import tempfile from io import open import webbrowser -import socket from urllib.parse import urljoin # Replace typing_extensions by typing when Python 3.8 support will be dropped @@ -43,10 +42,37 @@ try: except ImportError: logger.critical('Uvicorn import error. Glances cannot start in web server mode.') sys.exit(2) +import contextlib +import threading +import time security = HTTPBasic() +class GlancesUvicornServer(uvicorn.Server): + def install_signal_handlers(self): + pass + + @contextlib.contextmanager + def run_in_thread(self, timeout=3): + thread = threading.Thread(target=self.run) + thread.start() + try: + chrono = Timer(timeout) + while not self.started and not chrono.finished(): + time.sleep(0.5) + # Timeout reached + # Something go wrong... + # The Uvicorn server should be stopped + if not self.started: + self.should_exit = True + thread.join() + yield + finally: + self.should_exit = True + thread.join() + + class GlancesRestfulApi(object): """This class manages the Restful API server.""" @@ -88,8 +114,13 @@ class GlancesRestfulApi(object): self._app.include_router(APIRouter(prefix=self.url_prefix.rstrip('/'))) # Set path for WebUI - self.STATIC_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static/public') - self.TEMPLATE_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static/templates') + webui_root_path = config.get_value( + 'outputs', 'webui_root_path', default=os.path.dirname(os.path.realpath(__file__)) + ) + if webui_root_path == '': + webui_root_path = os.path.dirname(os.path.realpath(__file__)) + self.STATIC_PATH = os.path.join(webui_root_path, 'static/public') + self.TEMPLATE_PATH = os.path.join(webui_root_path, 'static/templates') self._templates = Jinja2Templates(directory=self.TEMPLATE_PATH) # FastAPI Enable CORS @@ -245,6 +276,8 @@ class GlancesRestfulApi(object): # Statics files self._app.mount("/static", StaticFiles(directory=self.STATIC_PATH), name="static") + logger.info("Get WebUI in {}".format(self.STATIC_PATH)) + bindmsg = 'Glances Web User Interface started on {}'.format(self.bind_url) else: bindmsg = 'The WebUI is disable (--disable-webui)' @@ -269,11 +302,23 @@ class GlancesRestfulApi(object): # 2) Glances standalone mode is running on Windows OS webbrowser.open(self.bind_url, new=2, autoraise=1) - # Run the Web application + # Start Uvicorn server + self._start_uvicorn() + + def _start_uvicorn(self): + # Run the Uvicorn Web server + uvicorn_config = uvicorn.Config( + self._app, host=self.args.bind_address, port=self.args.port, access_log=self.args.debug + ) try: - uvicorn.run(self._app, host=self.args.bind_address, port=self.args.port, access_log=self.args.debug) - except socket.error as e: + self.uvicorn_server = GlancesUvicornServer(config=uvicorn_config) + except Exception as e: logger.critical('Error: Can not ran Glances Web server ({})'.format(e)) + self.uvicorn_server = None + else: + with self.uvicorn_server.run_in_thread(): + while not self.uvicorn_server.should_exit: + time.sleep(1) def end(self): """End the Web server""" @@ -467,12 +512,14 @@ class GlancesRestfulApi(object): try: # Get the RAW value of the stat ID - statval = self.stats.get_plugin(plugin).get_export() + statval = self.stats.get_plugin(plugin).get_raw() except Exception as e: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Cannot get plugin %s (%s)" % (plugin, str(e)) ) + print(statval) + if isinstance(statval, list): statval = statval[:nb] |