77 lines
3.5 KiB
Markdown
77 lines
3.5 KiB
Markdown
# Server Hostname (Source `hostname` cvar) Design
|
|
|
|
**Goal:** Allow users to set the L4D2 server name (`hostname` cvar) that players see in the server browser and MOTD, with an ephemeral auto-generated fallback.
|
|
|
|
**Architecture:** A new `hostname VARCHAR(128)` column on the `servers` table. Empty string means "auto-generate at deploy time." The fallback is resolved ephemerally in `initialize_server` — computed fresh from `user.username + server.name` on each deploy, never persisted. Explicit overrides are stored and emitted verbatim.
|
|
|
|
---
|
|
|
|
## Model
|
|
|
|
Add one column to `Server` in `l4d2web/models.py`:
|
|
|
|
```python
|
|
hostname: Mapped[str] = mapped_column(String(128), default="", nullable=False)
|
|
```
|
|
|
|
Default `""` means auto-generate. Non-empty means explicit override.
|
|
|
|
## Behavior
|
|
|
|
| `hostname` value | Deploy result |
|
|
|---|---|
|
|
| `""` (empty) | Emit `hostname "<username> <server.name>"` — computed fresh each deploy, never written to DB |
|
|
| `"My Server"` | Emit `hostname "My Server"` verbatim |
|
|
| User clears the field | Resets to `""`, next deploy auto-generates |
|
|
|
|
The fallback is ephemeral — `initialize_server` resolves it in-memory for the spec YAML. The DB row stays empty. This means renames auto-propagate to the hostname on the next deploy without manual updates.
|
|
|
|
## Spec Payload
|
|
|
|
`build_server_spec_payload()` gains an optional `resolved_hostname: str = ""` keyword parameter. When non-empty, a `hostname "..."` line is inserted into the config array, before the `rcon_password` line (so rcon remains last-wins).
|
|
|
|
`initialize_server()` resolves the hostname:
|
|
|
|
```python
|
|
with session_scope() as db:
|
|
user = db.get(User, server.user_id)
|
|
resolved = server.hostname or f"{user.username} {server.name}"
|
|
```
|
|
|
|
## UI
|
|
|
|
On `server_detail.html`, a new row in the info `<dl>` block, placed after the RCON password row:
|
|
|
|
```
|
|
Hostname: [ _______________ ] [Save]
|
|
Leave empty for auto: "alice alpha"
|
|
```
|
|
|
|
- Input `name="hostname"`, `maxlength="128"`
|
|
- `value="{{ server.hostname }}"` (empty when not set)
|
|
- `placeholder="{{ user.username }} {{ server.name }}"` (previews auto-generated value)
|
|
- Form submits to `POST /servers/<id>` — same endpoint as the rename form
|
|
- No hostname field in the create-server modal; new servers always start with `hostname=""`
|
|
|
|
## Routes
|
|
|
|
**`POST /servers/<int:server_id>`** (update_server_form) — unchanged signature; just also saves `request.form.get("hostname", "")` to `server.hostname`.
|
|
|
|
**`POST /servers`** (create_server) — unchanged; `hostname` defaults to `""` from the model default.
|
|
|
|
## Files Touched
|
|
|
|
| File | Change |
|
|
|---|---|
|
|
| `l4d2web/models.py` | Add `hostname` column to `Server` |
|
|
| `l4d2web/alembic/versions/0011_server_hostname.py` | Migration — `ADD COLUMN hostname VARCHAR(128) NOT NULL DEFAULT ''` |
|
|
| `l4d2web/routes/server_routes.py` | `update_server_form` saves `hostname` from form |
|
|
| `l4d2web/services/l4d2_facade.py` | `build_server_spec_payload` accepts `resolved_hostname=`, emits `hostname "..."` line. `initialize_server` resolves fallback. |
|
|
| `l4d2web/templates/server_detail.html` | Hostname form row in info `<dl>` |
|
|
| `l4d2web/tests/test_servers.py` | Tests for create default, update, clear |
|
|
| `l4d2web/tests/test_l4d2_facade.py` | Tests for hostname in spec, fallback resolution |
|
|
|
|
## Open / Closed
|
|
|
|
- **Explicit vs ephemeral:** Explicit overrides persist; empty means auto at deploy time. No toggle, no "locked" mode needed in v1.
|
|
- **No hostname in create modal:** Simplifies the form. Hostname is configured post-creation on the detail page.
|