Source code for openquake.commands.webui

# -*- coding: utf-8 -*-
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (C) 2016-2026 GEM Foundation
#
# OpenQuake is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# OpenQuake is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with OpenQuake.  If not, see <http://www.gnu.org/licenses/>.

import os
import sys
import subprocess
import webbrowser

import psutil

from openquake.baselib import config, general
from openquake.commonlib import dbapi
from openquake.commonlib.auth import API_KEY
from openquake.server.db import actions
from openquake.server.utils import check_webserver_running

commands = ['start', 'status', 'stop']


def _find_webui_process(hostport):
    """Find the Uvicorn process listening on the requested port."""
    _host, port = hostport.rsplit(':', 1)
    for connection in psutil.net_connections(kind='tcp'):
        if (connection.status == psutil.CONN_LISTEN and
                connection.laddr.port == int(port)):
            try:
                return psutil.Process(connection.pid)
            except psutil.NoSuchProcess:
                return None
    return None


def _status(hostport):
    """Print whether the WebUI responds on the requested address."""
    url = 'http://' + hostport
    running = check_webserver_running(url, max_retries=1, warn=False)
    print('running' if running else 'stopped')
    return running


def _stop(hostport):
    """Stop the Uvicorn process serving the requested WebUI port."""
    process = _find_webui_process(hostport)
    if process is None:
        print('WebUI is not running')
        return
    process.terminate()
    try:
        process.wait(timeout=10)
    except psutil.TimeoutExpired:
        process.kill()
        process.wait()
    print('stopped')


[docs]def runserver(hostport=None, skip_browser=False): """Start Uvicorn and serve the combined WebUI application.""" url = 'http://' + hostport if check_webserver_running(url, max_retries=1, warn=False): if not skip_browser: webbrowser.open(url) return host, port = hostport.rsplit(':', 1) api_host = '127.0.0.1' if host == '0.0.0.0' else host env = os.environ.copy() env.update( OQ_API_KEY=API_KEY, OQ_WEBAPI_SERVER='http://%s:%s' % (api_host, port)) process = subprocess.Popen([ sys.executable, '-m', 'uvicorn', 'openquake.server.asgi:app', '--host', host, '--port', port, ], env=env) if not skip_browser and check_webserver_running(url): webbrowser.open(url) try: process.wait() except KeyboardInterrupt: process.terminate() process.wait() if process.returncode not in (0, -15): sys.exit(process.returncode)
[docs]def main(cmd, hostport='127.0.0.1:8800', skip_browser: bool = False): """ Start the webui server in foreground. Other webui commands can be launched after activating the openquake virtual environment, using Django’s command-line utility for administrative tasks, e.g.: manage.py <command> [options] """ if cmd == 'status': _status(hostport) return if cmd == 'stop': _stop(hostport) return os.environ.setdefault('OQ_API_KEY', API_KEY) api_host, api_port = hostport.rsplit(':', 1) if api_host == '0.0.0.0': api_host = '127.0.0.1' os.environ.setdefault( 'OQ_WEBAPI_SERVER', 'http://%s:%s' % (api_host, api_port)) dbpath = os.path.realpath(os.path.expanduser(config.dbserver.file)) if os.path.isfile(dbpath) and not os.access(dbpath, os.W_OK): sys.exit('This command must be run by the proper user: ' 'see the documentation for details') actions.upgrade_db(dbapi.db) print('Starting, using version %s' % general.engine_version()) runserver(hostport, skip_browser)
main.cmd = dict(help='webui command', choices=commands) main.hostport = 'a string of the form <hostname:port>' main.skip_browser = 'do not automatically open the browser'