Files
NexusDashboard/app/settings_example.py
Bob G 69480cfa3e Speed up property model viewer: on-demand rendering, shared UGC caches, validators and gzip (#134)
* Speed up property model viewer loading

- Render the viewer on demand (load completion, camera change, resize)
  instead of every animation frame
- Share the UGC brick geometry cache and parsed Materials.xml across all
  UGC models on the converter
- Serve model and ldddb files with strong ETag/Last-Modified validators
  and conditional requests so repeat visits get 304s
- Gzip model and ldddb responses (COMPRESS_MODEL_RESPONSES), optionally
  storing .gz copies on disk (CACHE_COMPRESSED_MODELS)

Co-authored-by: HailStorm32 <demetriv.s.7@gmail.com>

* Add configurable redraw behaviour while property models load

PROPERTY_VIEWER_LOAD_REDRAW ('none' or 'interval') and
PROPERTY_VIEWER_REDRAW_INTERVAL_MS control whether the property viewer
redraws as individual models finish loading. A final draw always happens
once all loads complete or fail, and a loading indicator is shown
meanwhile. Also wrap long lines added by this branch for flake8.

Co-authored-by: HailStorm32 <demetriv.s.7@gmail.com>

* Show model loading progress in the property viewer

Replace the static 'Loading models...' badge in the upper-left corner with
a progress indicator, e.g. 'Loading models: 42% (89/203)', counting loaded
and failed models out of the total. When everything is done it shows
'Loaded 100% (203/203)' (with '(N failed)' if any), turns green (orange on
failures) and fades to a faint badge after a few seconds.

The indicator is a DOM element updated at most once per animation frame,
so it does not trigger canvas redraws in either redraw mode.

Co-authored-by: HailStorm32 <demetriv.s.7@gmail.com>

* Make the loading progress badge more opaque and readable

Use a ~93% opaque background for all states (dark while loading, darker
green when done, orange on failures), bold white text with a subtle text
shadow, border and drop shadow, and only fade to 70% opacity after
completion so it stays legible over colourful models.

Co-authored-by: HailStorm32 <demetriv.s.7@gmail.com>

* Batch UGC models and load the viewer's brick data asynchronously

Brick-built (UGC) models used to be loaded with synchronous XHRs on the
main thread: one request per model's LXFML plus one per brick primitive
file, strictly one after another, with the page frozen meanwhile. On a
remote server every request costs a network round trip, so a property
with 654 UGC models took about two minutes to load.

- New route properties.get_ugc_models/<property id> (login required, like
  get_model) returns all UGC LXFML of a property as one JSON object
  ({content id: lxfml}) from a single DB query. It is gzip-encoded per
  COMPRESS_MODEL_RESPONSES and has an ETag over the whole set, so repeat
  loads get a 304. The per-model get_model route keeps working.
- The viewer lists the brick database, fetches the LXFML (batched on
  view_models, per model with bounded concurrency otherwise) and then each
  needed brick primitive exactly once with at most 8 requests in flight,
  all with async fetch. Meshes are then built in short slices so the page
  stays responsive. The progress badge counts brick-built models as they
  are built and shows the fetch stage (e.g. 'bricks 120/385').
- Loading finishes once both the loading manager (pre-built models,
  ground texture) and the brick-built models are done; redraw modes are
  unchanged ('none' draws once at the end, 'interval' at most every N ms).
- get_model for a UGC model only decompresses the LXFML when it has to
  send a body (a matching If-None-Match skips it).

Co-authored-by: HailStorm32 <demetriv.s.7@gmail.com>

* Show the prebuilt material stage on the loading badge

While prebuilt models load, the badge now shows how many MTL files have
arrived (e.g. 'materials 120/203'), so progress moves from the start on
prebuilt-heavy properties instead of sitting at 0% until the first OBJ
loads.

Co-authored-by: HailStorm32 <demetriv.s.7@gmail.com>

* Show a rendering state on the badge before the final render

The final full render can block the main thread for a second or more on
large properties, which made the badge look frozen. Once all loads are
done the badge now shows 'Rendering N parts…' with a CSS spinner (a
transform animation the compositor keeps running), waits two animation
frames so it is painted, then renders and shows the Loaded state.

Co-authored-by: HailStorm32 <demetriv.s.7@gmail.com>

---------

Co-authored-by: bob-g-code <346622190+bob-g-code@users.noreply.github.com>
Co-authored-by: HailStorm32 <demetriv.s.7@gmail.com>
2026-11-01 07:20:48 -06:00

94 lines
3.3 KiB
Python

# Settings common to all environments (development|staging|production)
# Application settings
APP_NAME = "Nexus Dashboard"
APP_SYSTEM_ERROR_SUBJECT_LINE = APP_NAME + " system error"
APP_SECRET_KEY = ""
APP_DATABASE_URI = "mysql+pymysql://<username>:<password>@<host>:<port>/<database>"
CLIENT_LOCATION = 'app/luclient/'
CD_SQLITE_LOCATION = 'app/luclient/res/'
CACHE_LOCATION = 'app/cache/'
CONFIG_LINK = False
CONFIG_LINK_TITLE = ""
CONFIG_LINK_HREF = ""
CONFIG_LINK_TEXT = ""
# Flask settings
CSRF_ENABLED = True
# Flask-SQLAlchemy settings
SQLALCHEMY_TRACK_MODIFICATIONS = False
WTF_CSRF_TIME_LIMIT = 86400
# Flask-User settings
USER_APP_NAME = APP_NAME
USER_ENABLE_CHANGE_PASSWORD = True # Allow users to change their password
USER_ENABLE_CHANGE_USERNAME = False # Allow users to change their username
USER_ENABLE_REGISTER = False # Allow new users to register
# Should alwyas be set to true
USER_REQUIRE_RETYPE_PASSWORD = True # Prompt for `retype password`
USER_ENABLE_USERNAME = True # Register and Login with username
# Email Related Settings
USER_ENABLE_EMAIL = False # Register with Email WILL - DISABLE OTHER THINGS TOO
USER_ENABLE_CONFIRM_EMAIL = True # Force users to confirm their email
USER_ENABLE_INVITE_USER = False # Allow users to be invited
USER_REQUIRE_INVITATION = False # Only invited users may - WILL DISABLE REGISTRATION
USER_ENABLE_FORGOT_PASSWORD = True # Allow users to reset their passwords
MAIL_SERVER = 'smtp.gmail.com'
MAIL_PORT = 587
MAIL_USE_SSL = False
MAIL_USE_TLS = True
MAIL_USERNAME = None
MAIL_PASSWORD = None
USER_EMAIL_SENDER_NAME = None
USER_EMAIL_SENDER_EMAIL = None
# Require Play Key
REQUIRE_PLAY_KEY = True
# Password hashing settings DO NOT CHANGE
USER_PASSLIB_CRYPTCONTEXT_SCHEMES = ['bcrypt'] # bcrypt for password hashing
# Flask-User routing settings
USER_AFTER_LOGIN_ENDPOINT = "main.index"
USER_AFTER_LOGOUT_ENDPOINT = "main.index"
# Option will be removed once this feature is full implemeted
ENABLE_CHAR_XML_UPLOAD = False
# Recaptcha settings
# See: https://flask-wtf.readthedocs.io/en/1.2.x/form/#recaptcha
RECAPTCHA_ENABLE = False
RECAPTCHA_PUBLIC_KEY = ''
RECAPTCHA_PRIVATE_KEY = ''
# Optional
# RECAPTCHA_API_SERVER = ''
# RECAPTCHA_PARAMETERS = ''
RECAPTCHA_DATA_ATTRS = {'theme': 'white', 'size': 'invisible'}
# Property model viewer response compression
# Gzip model (OBJ/MTL/LXFML) and LDD brick database responses for clients that
# accept it. Set to False to always send uncompressed files.
COMPRESS_MODEL_RESPONSES = True
# When True, a gzip copy is written to disk next to each cached file the first
# time it is served (regenerated if the source file is newer) and served
# directly: uses more disk space, but no CPU per request.
# When False, responses are compressed in memory on every request at a fast
# compression level and nothing extra is stored.
CACHE_COMPRESSED_MODELS = False
# Property model viewer redraw while models are loading
# 'none': do not redraw as individual models finish loading; draw once when
# all loads have completed (or failed), then only on camera move/resize.
# 'interval': redraw at most every PROPERTY_VIEWER_REDRAW_INTERVAL_MS while
# loading so models appear progressively, then a final draw.
# Can be overridden per page for testing with ?redraw=none|interval&redraw_ms=N
PROPERTY_VIEWER_LOAD_REDRAW = 'none'
PROPERTY_VIEWER_REDRAW_INTERVAL_MS = 500