Architecture
Technology stack
The GUI is built on top of three libraries:
Flask — WSGI web framework, handles routing, sessions, and template rendering.
Jinja2 — templating engine (included with Flask); templates live in
gui/templates/.HTMX — JavaScript library loaded from CDN; drives partial page updates and SSE subscriptions without writing custom fetch/XHR code.
All application logic lives in gui/app.py. No core files are modified.
Server-Sent Events (SSE)
Two independent SSE streams deliver real-time data to the browser.
Runner stream
When fwtester.py completes each test, it commits the result to the SQLite
database (fwtester-sqlite3.db, table tests_results). The endpoint
/runner/db-stream polls the database for new rows and emits each one as an
HTML fragment (a <tr> element). HTMX appends each fragment to the results
table body using hx-swap="beforeend".
A second endpoint, /runner/stream, tails outputs/logs/fwtester.log and
forwards each line as an SSE message. This is used by the log viewer modal
inside the Runner page.
Hot-test stream
/hot-test/stream reads the standard output of the run_hot_test.py
subprocess line by line and forwards each line as an SSE message. When the
subprocess exits, the generator emits an event: close message so the
browser-side EventSource can call src.close() and stop reconnecting.
Key files
File |
Purpose |
|---|---|
|
Flask application: all routes, SSE generators, helper functions. |
|
|
|
Translation dictionary and |
|
User authentication: SQLite storage, PBKDF2-SHA256 hashing, session management. |
|
Portable systemd service installer. |
|
Removes the systemd service. |
|
Jinja2 templates: one per page plus HTMX partials ( |
|
Application stylesheet (no external CSS framework). |
|
GUI-specific Python dependencies (Flask). |
HotTestRunner
HotTestRunner (gui/run_hot_test.py) is a subclass of FwTester with
three overrides:
__init__— skips loadingtests.csv; setsself._teststo a single constructed CSV rule string built from the CLI arguments._resume()— always returns-1so the single test is never skipped by the resume logic.generate_report()— no-op; hot-test results are not written to the report CSV.
It uses fwtester_hot-sqlite3.db as its database to avoid interfering with
the main runner’s resume state. fwnics.csv and routes.csv must still be
present.
Internationalisation (i18n)
All user-visible strings are looked up through the t(key, locale) function
defined in gui/i18n.py. The function resolves:
The string for the requested locale.
Falls back to the English (
en) string if the key is missing for that locale.Falls back to the key name itself if the key is not found in any locale.
The active locale is stored in the Flask session and changed via
GET /set-lang?lang=<code>. Supported codes: en, es, ca.
Note
Because the server runs with debug=False, Python modules are loaded once
at startup and are not reloaded between requests. Changes to gui/i18n.py
require a service restart to take effect.
Authentication
gui/auth.py manages user accounts in the users table of
fwtester-sqlite3.db. Passwords are stored as PBKDF2-SHA256 hashes using
Python’s hashlib.pbkdf2_hmac. Sessions are handled by Flask’s built-in
signed cookie mechanism.
The users table coexists with the tests_results table in the same
database file. The “Clear results” operation issues a DELETE FROM
tests_results statement and does not touch the users table.