Create attractive VASL scenarios, with loads of useful information embedded to assist with game play.
https://vasl-templates.org
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
7.6 KiB
185 lines
7.6 KiB
#!/usr/bin/env python3
|
|
""" Main entry point for the application. """
|
|
|
|
import sys
|
|
import os
|
|
import os.path
|
|
import threading
|
|
import traceback
|
|
import logging
|
|
import urllib.request
|
|
|
|
import PyQt5.QtWebEngineWidgets
|
|
from PyQt5.QtWidgets import QApplication, QMessageBox
|
|
from PyQt5.QtCore import Qt, QSettings, QDir
|
|
import PyQt5.QtCore
|
|
import click
|
|
|
|
from vasl_templates.webapp.utils import SimpleError
|
|
|
|
# FUDGE! This needs to be created before showing any UI elements e.g. an error message box.
|
|
qt_app = QApplication( sys.argv )
|
|
|
|
app_settings = None
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
_QT_LOGGING_LEVELS = {
|
|
PyQt5.QtCore.QtCriticalMsg: logging.CRITICAL,
|
|
PyQt5.QtCore.QtFatalMsg: logging.ERROR,
|
|
PyQt5.QtCore.QtWarningMsg: logging.WARNING,
|
|
PyQt5.QtCore.QtInfoMsg: logging.INFO,
|
|
PyQt5.QtCore.QtDebugMsg: logging.DEBUG,
|
|
}
|
|
|
|
def qtMessageHandler( msg_type, context, msg ):# pylint: disable=unused-argument
|
|
"""Handle PyQt logging messages."""
|
|
# FUDGE! PyQt issues a bunch of warning messages because we had to proxy WebChannel requests
|
|
# via the MainWindow object - we filter them out here.
|
|
if "has no notify signal and is not constant" in msg:
|
|
return
|
|
logging.getLogger( "qt" ).log( _QT_LOGGING_LEVELS[msg_type], "%s", msg )
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
@click.command()
|
|
@click.option( "--template-pack", help="Template pack to auto-load (ZIP file or directory)." )
|
|
@click.option( "--default-scenario", help="Default scenario settings." )
|
|
@click.option( "--remote-debugging", help="Chrome DevTools port number." )
|
|
@click.option( "--debug", help="Debug config file." )
|
|
def main( template_pack, default_scenario, remote_debugging, debug ):
|
|
"""Manage HTML labels in a VASL scenario."""
|
|
try:
|
|
return _do_main( template_pack, default_scenario, remote_debugging, debug )
|
|
except Exception as ex: #pylint: disable=broad-except
|
|
# log the error
|
|
# NOTE: If we get here, there was probably an error during startup, so we can't
|
|
# assume too much about how much of our expected environment has been set up.
|
|
try:
|
|
fname = os.path.join( QDir.homePath(), "vasl-templates.log" )
|
|
with open( fname, "w" ) as fp:
|
|
traceback.print_exc( file=fp )
|
|
except: #pylint: disable=bare-except
|
|
pass
|
|
QMessageBox.warning( None, "Unexpected error", str(ex) )
|
|
return -1
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
def _do_main( template_pack, default_scenario, remote_debugging, debug ): #pylint: disable=too-many-locals,too-many-branches
|
|
"""Do main processing."""
|
|
|
|
# NOTE: We do these imports here (instead of at the top of the file) so that we can catch errors.
|
|
from vasl_templates.webapp import app as webapp
|
|
from vasl_templates.webapp import load_debug_config
|
|
from vasl_templates.webapp import main as webapp_main, snippets as webapp_snippets
|
|
|
|
# configure the default template pack
|
|
if template_pack:
|
|
if template_pack.lower().endswith( ".zip" ):
|
|
rc = os.path.isfile( template_pack )
|
|
else:
|
|
rc = os.path.isdir( template_pack )
|
|
if not rc:
|
|
click.echo( "ERROR: The template pack must be a ZIP file, or a directory containing the template files." )
|
|
return 1
|
|
webapp_snippets.default_template_pack = template_pack
|
|
|
|
# configure the default scenario
|
|
if default_scenario:
|
|
if not os.path.isfile( default_scenario ):
|
|
raise SimpleError( "Can't find the default scenario file." )
|
|
webapp_main.default_scenario = default_scenario
|
|
|
|
# configure remote debugging
|
|
if remote_debugging:
|
|
remote_debugging = remote_debugging.replace( "localhost", "127.0.0.1" )
|
|
os.environ["QTWEBENGINE_REMOTE_DEBUGGING"] = remote_debugging
|
|
|
|
# load the application settings
|
|
app_settings_fname = "vasl-templates.ini" if sys.platform == "win32" else ".vasl-templates.conf"
|
|
if not os.path.isfile( app_settings_fname ) :
|
|
app_settings_fname = os.path.join( QDir.homePath(), app_settings_fname )
|
|
# FUDGE! Declaring app_settings as global here doesn't work on Windows (?!), we have to do this weird import :-/
|
|
import vasl_templates.main #pylint: disable=import-self
|
|
vasl_templates.main.app_settings = QSettings( app_settings_fname, QSettings.IniFormat )
|
|
|
|
# install the debug config file
|
|
if debug:
|
|
load_debug_config( debug )
|
|
|
|
# connect PyQt's logging to Python logging
|
|
PyQt5.QtCore.qInstallMessageHandler( qtMessageHandler )
|
|
|
|
# install the server settings
|
|
try:
|
|
from vasl_templates.server_settings import install_server_settings #pylint: disable=cyclic-import
|
|
install_server_settings( True )
|
|
except Exception as ex: #pylint: disable=broad-except
|
|
# NOTE: We used to advise the user to check the app config file for errors, but exceptions can be thrown
|
|
# for reasons other than errors in that file (e.g. bad JSON in the vehicle/ordnance data files).
|
|
logging.critical( traceback.format_exc() )
|
|
from vasl_templates.main_window import MainWindow #pylint: disable=cyclic-import
|
|
MainWindow.showErrorMsg( "Couldn't install the server settings:\n\n{}".format( ex ) )
|
|
return 2
|
|
|
|
# disable the Flask "do not use in a production environment" warning
|
|
import flask.cli
|
|
flask.cli.show_server_banner = lambda *args: None
|
|
|
|
# see if we can connect to the webapp server
|
|
port = webapp.config["FLASK_PORT_NO"]
|
|
url = "http://localhost:{}/ping".format( port )
|
|
try:
|
|
resp = urllib.request.urlopen( url ).read()
|
|
except: #pylint: disable=bare-except
|
|
resp = None
|
|
if resp:
|
|
raise SimpleError( "The application is already running." )
|
|
|
|
# start the webapp server
|
|
def webapp_thread():
|
|
"""Run the webapp server."""
|
|
try:
|
|
webapp.run( host="localhost", port=port, use_reloader=False )
|
|
except Exception as ex:
|
|
logging.critical( "WEBAPP SERVER EXCEPTION: %s", ex )
|
|
logging.critical( traceback.format_exc() )
|
|
raise
|
|
thread = threading.Thread( target=webapp_thread )
|
|
thread.start()
|
|
|
|
# check if we should disable OpenGL
|
|
# Using the QWebEngineView crashes on Windows 7 in a VM. It uses OpenGL, which is
|
|
# apparently not well supported on Windows, and is dependent on the graphics card driver:
|
|
# https://stackoverflow.com/a/50393872
|
|
# https://stackoverflow.com/questions/33090346/is-there-any-way-to-use-qtwebengine-without-opengl
|
|
# Switching to software rendering (AA_UseSoftwareOpenGL) got things going :shrug:
|
|
# Also see: https://doc.qt.io/qt-5/windows-requirements.html
|
|
opengl_type = webapp.config.get( "OPENGL_TYPE" )
|
|
if opengl_type:
|
|
logging.info( "Setting OpenGL: %s", opengl_type )
|
|
opengl_type = getattr( Qt, opengl_type )
|
|
QApplication.setAttribute( opengl_type )
|
|
|
|
# check if we should disable the embedded browser
|
|
disable_browser = webapp.config.get( "DISABLE_WEBENGINEVIEW" )
|
|
|
|
# run the application
|
|
url = "http://localhost:{}".format( port )
|
|
from vasl_templates.main_window import MainWindow #pylint: disable=cyclic-import
|
|
main_window = MainWindow( url, disable_browser )
|
|
main_window.show()
|
|
ret_code = qt_app.exec_()
|
|
|
|
# shutdown the webapp server
|
|
url = "http://localhost:{}/shutdown".format( port )
|
|
urllib.request.urlopen( url ).read()
|
|
thread.join()
|
|
|
|
return ret_code
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit( main() ) #pylint: disable=no-value-for-parameter
|
|
|