133 lines
6.6 KiB
Markdown
133 lines
6.6 KiB
Markdown
# doka-lobby
|
|
|
|
Web UI for Dota 2 joinable custom lobbies from the game coordinator. The admin page can also create a custom-game lobby, notify browsers and Telegram recipients as it fills, and make the Steam bot leave safely before the lobby launches.
|
|
|
|
The app keeps the latest lobby snapshot in memory, refreshes it every 3 minutes, and streams updates to the browser. There is no database. Steam account credentials and the refresh token can be persisted on a PVC.
|
|
|
|
## Local run
|
|
|
|
```powershell
|
|
npm install
|
|
$env:AUTH_ADMIN_PASSWORD = "admin-password"
|
|
npm start
|
|
```
|
|
|
|
Open:
|
|
|
|
```text
|
|
http://localhost:3000
|
|
```
|
|
|
|
Use `/admin` to enter the admin password, save and switch Steam accounts, submit a Steam Guard code when Steam asks for it, configure lobby creation, and enable notifications.
|
|
|
|
## Steam accounts and Steam Guard
|
|
|
|
The admin page can store multiple Steam account/password profiles. **Save and activate** updates the selected profile and reconnects Steam and the Dota GC without restarting Node. **Activate selected** switches to another saved profile in the same way. Account switching is blocked while the bot owns or monitors a lobby so it cannot disconnect unexpectedly and spoil a game.
|
|
|
|
Passwords are stored only in the server-side credentials file and are never returned by the admin API. Each account has its own cached refresh token. `steam-user` machine authorization files are persisted in `STEAM_DATA_DIR`; together these normally avoid repeated Steam Guard prompts. Steam Guard codes themselves are not cached because they are one-time, short-lived values.
|
|
|
|
## Lobby automation
|
|
|
|
The **Create lobby** form requires the Workshop ID, internal addon/game-mode name, map name, region, and custom-game player limits. The internal name, CRC, and Workshop timestamp are copied automatically when you click **Create template** on an existing lobby in the lobby list; after admin authorization, the creation form is prefilled. This prevents the GC from accepting a half-configured lobby object that is not published in the custom-game list.
|
|
|
|
Two thresholds are configured for every lobby start:
|
|
|
|
- **Notify at real players** sends a Web Push notification once the lobby reaches that many users.
|
|
- **Bot leaves at real players** sends `CMsgPracticeLobbyLeave` immediately at that many users while the lobby is still in its UI/waiting state.
|
|
|
|
Both values exclude the bot. The leave threshold must be lower than the custom-game maximum because Dota initially places the lobby owner in Radiant slot 1. The bot stays there while waiting, matching the official client and known working GC clients, then leaves at the configured real-player threshold so its slot becomes available before the lobby is full.
|
|
|
|
Admin identities are exact, case-insensitive Steam persona names separated by commas. A SteamID64 can be entered instead of a name for immediate matching that is not affected by renames or duplicate persona names. When any configured admin identity appears, the bot leaves immediately.
|
|
|
|
The application never sends an abandon command. If the lobby has already left the UI/waiting state, automatic and manual leave are blocked and a critical browser notification is sent, avoiding an abandon penalty.
|
|
|
|
Browser push requires HTTPS outside `localhost`. Click **Enable on this browser**, allow notifications, then use **Send test**. Subscriptions and VAPID keys are stored on the same persistent volume as Steam auth.
|
|
|
|
## Telegram notifications
|
|
|
|
Create a bot with `@BotFather`, enter its token and numeric Telegram user IDs on `/admin`, then click **Save Telegram** and **Send test**. Every recipient must first open the bot and send it a message; Telegram does not let a bot initiate a private conversation.
|
|
|
|
For each lobby the bot sends one tracker message to every configured recipient. It edits that message whenever the phase, publication state, player count, player names, or roster changes. Threshold, leave, and safety events are also sent as separate Telegram alerts so they generate a normal notification.
|
|
|
|
When Dota 2 Workshop content is installed on the same machine, the app reads `publish_data.txt` to resolve the internal addon name immediately. Set `DOTA_WORKSHOP_DIR` to the `steamapps/workshop/content/570` directory when Steam uses a non-standard library path.
|
|
|
|
The app also reads `ClientVersion` from `game/dota/steam.inf` and sends it in GC hello/lobby-create messages. On a container without Dota files, set `DOTA_CLIENT_VERSION` to that value from an up-to-date Dota installation, or mount the file and set `DOTA_STEAM_INF` to its container path. The admin page shows the detected value and source.
|
|
|
|
## Kubernetes configuration
|
|
|
|
Mount a PVC to `/data` and set:
|
|
|
|
```yaml
|
|
env:
|
|
- name: AUTH_ADMIN_PASSWORD
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: doka-lobby-admin
|
|
key: password
|
|
- name: STEAM_AUTH_FILE
|
|
value: /data/.steam-auth.json
|
|
- name: STEAM_CREDENTIALS_FILE
|
|
value: /data/.steam-credentials.json
|
|
- name: STEAM_DATA_DIR
|
|
value: /data/node-steam-user
|
|
- name: LOBBY_SETTINGS_FILE
|
|
value: /data/.lobby-settings.json
|
|
- name: WEB_PUSH_FILE
|
|
value: /data/.web-push.json
|
|
- name: TELEGRAM_FILE
|
|
value: /data/.telegram.json
|
|
- name: WEB_PUSH_SUBJECT
|
|
value: mailto:admin@example.com
|
|
- name: DOTA_CLIENT_VERSION
|
|
value: "6888" # example only; copy the current value from game/dota/steam.inf
|
|
- name: PORT
|
|
value: "3000"
|
|
volumeMounts:
|
|
- name: data
|
|
mountPath: /data
|
|
```
|
|
|
|
Run one replica only. A single Steam account should not be used by multiple pods at once.
|
|
|
|
## Auth files
|
|
|
|
- `.steam-credentials.json` stores saved Steam account/password profiles and the active account.
|
|
- `.steam-auth.json` stores a separate Steam refresh token for every saved account.
|
|
- `node-steam-user/` stores Steam Guard machine authorization files.
|
|
- `.lobby-settings.json` stores the last validated lobby form values.
|
|
- `.web-push.json` stores VAPID keys and browser subscriptions.
|
|
- `.telegram.json` stores the Telegram bot token, recipient IDs, and tracker message IDs.
|
|
- All credential and notification state is ignored by git and the Docker build context.
|
|
|
|
If the refresh token is still valid, restarts use it. If it is missing or expired, the app falls back to the saved Steam account/password and may ask for Steam Guard again.
|
|
|
|
## Docker image CI
|
|
|
|
GitHub Actions builds and pushes:
|
|
|
|
```text
|
|
ultradesu/doka2-lobby-list
|
|
```
|
|
|
|
Configure repository secrets:
|
|
|
|
- `DOCKERHUB_USERNAME`
|
|
- `DOCKERHUB_TOKEN`
|
|
|
|
The workflow publishes `latest` on the default branch, branch/tag refs, and `sha-*` tags.
|
|
|
|
## Options
|
|
|
|
```powershell
|
|
node index.js --port 3001
|
|
node index.js --region 3
|
|
node index.js --game-id 123456789
|
|
node index.js --refresh-ms 180000
|
|
```
|
|
|
|
One-shot console mode:
|
|
|
|
```powershell
|
|
node index.js --once --map "ffa"
|
|
```
|