minimost (App Factory)

minimost

Flask application factory for the MiniMost chat platform.

This module is the primary entry point for the MiniMost application. It exposes create_app(), which constructs a fully-configured flask.Flask instance ready to serve HTTP requests.

Typical usage in development:

from minimost import create_app

app = create_app()
app.run(host="127.0.0.1", port=5000)

Typical usage with a WSGI server such as Gunicorn:

gunicorn "minimost:create_app()" --config gunicorn.conf.py

Module-level attributes

_APP_VERSIONstr

The package version string, resolved once at import time by _read_version(). Available in every Jinja2 template as {{ app_version }}.

minimost._read_version() str[source]

Return the package version string.

The version lives in minimost._version, which ships inside the package and is therefore importable from an installed wheel and on every supported Python version (unlike importlib.metadata, which is 3.8+). The same module is the build-time source of truth via the dynamic-version config in pyproject.toml.

If the module cannot be imported for any reason, the string "unknown" is returned so the application always has a displayable value.

Returns:

The version string, for example "0.1.0", or "unknown" if the version cannot be determined.

Return type:

str

minimost._max_upload_size_mb() int[source]

Return the configured max upload size in MB (default 25).

minimost._max_avatar_size_mb() int[source]

Return the configured max avatar size in MB (default 5).

minimost._stun_port() int[source]

Return the configured STUN UDP port (default 3478).

The bundled STUN server lets LAN WebRTC peers gather a real-IP server-reflexive candidate, avoiding the mDNS .local host-candidate resolution that otherwise breaks calls on LANs without avahi/Bonjour.

minimost._provision_tls(app) None[source]

Generate the self-signed TLS cert/key once, for any WSGI server.

Historically only the development server and the bundled Gunicorn config generated certificates, so running MiniMost under another WSGI server (waitress, uWSGI, mod_wsgi, …) silently meant no HTTPS — and therefore no voice/video calling. Doing it here means any server that loads minimost:create_app() gets certificates provisioned, with no server-specific glue.

Generation is idempotent (see minimost.certs.ensure_certs()) and the resolved paths are stored in app.config['TLS_CERT_FILE'] and ['TLS_KEY_FILE'] so a launcher can point its TLS listener at them. Note that generating the files does not terminate TLS — the WSGI server still has to be configured to serve HTTPS using these paths.

Set MINIMOST_SKIP_TLS=1 to skip generation entirely, e.g. when TLS is terminated upstream by a reverse proxy, or under the test suite.

Parameters:

app – The Flask application whose config receives the cert paths.

minimost.create_app()[source]

Create and configure the MiniMost Flask application.

This is the canonical application factory used by every execution path — the CLI entry point (minimost.__main__), the Gunicorn WSGI configuration, and any test suite that imports the package.

The factory performs the following steps in order:

  1. Instantiate a flask.Flask application object.

  2. Provision the secret key — read from secret.key in the project root, generating a fresh 64-character hex token if the file does not exist. The secret key is required for Flask’s signed session cookies.

  3. Set upload limit to 16 MiB via MAX_CONTENT_LENGTH. Requests that exceed this size are rejected by Flask before the route handler runs.

  4. Inject the version into every Jinja2 template context via a context processor, making {{ app_version }} available in all templates.

  5. Register blueprintsauth_bp, chat_bp, and presence_bp.

The auth.db and presence.db databases are also initialised as a side effect of importing minimost.database and minimost.presence at module load time.

Returns:

A configured flask.Flask application instance.

Return type:

flask.Flask

Example:

app = create_app()
with app.test_client() as client:
    response = client.get("/login")
    assert response.status_code == 200
minimost._migrate_search_indexes() None[source]

Ensure the shared message database and its search index exist at boot.

init_messages_db() is idempotent and builds (then rebuilds, once) the FTS5 trigram index if it is missing, so calling it at startup transparently upgrades a database that predates the index. Runs once per worker at boot.

minimost._start_cleanup_scheduler(interval_hours: int = 24, days: int = 30, message_days: int = 770, initial_delay_seconds: int = 5) None[source]

Start a daemon thread that periodically purges old upload files.

Runs minimost.clean.delete_files_older_than() once shortly after startup and then every interval_hours hours. The thread is a daemon so it exits automatically when the server process shuts down — no teardown required.

The retention period is read from the "image_retention_days" key in settings.json at each run, so changes to the file take effect on the next scheduled cleanup without restarting the server. If the key is absent or the file cannot be read, days is used as the fallback.

Two optional size caps are also honoured each run: "max_upload_dir_size_mb" bounds the total size of uploads/ (oldest files deleted first), and "max_message_db_size_mb" bounds the shared messages.db (oldest messages deleted first). Either is disabled when its key is absent or non-positive.

Multiple Gunicorn workers each start their own thread; concurrent runs are safe because delete_files_older_than() tolerates FileNotFoundError on files already removed by another worker.

Parameters:
  • interval_hours – Hours between cleanup runs. Defaults to 24.

  • days – Fallback retention period in days if settings.json does not specify "image_retention_days". Defaults to 30.

  • message_days – Fallback retention period in days for messages if settings.json does not specify "message_retention_days".

  • initial_delay_seconds – Seconds to wait after startup before the first cleanup run, giving the server time to finish booting. Defaults to 5.