MacroQuest‑compatible EQBCS server reimplemented in Python, with multi‑instance support, Docker/Compose packaging, and an optional VS Code‑driven deploy workflow.
Wire‑compatible with the EQBCS protocol used by MacroQuest plugins. Point your MQ clients at the host:port you expose here and (optionally) a password; no client changes required.
The repo ships with a ready‑to‑use docker-compose.yml that can launch N parallel servers on a contiguous port range.
- Clone the repo and open it in a shell at the repo root.
- (Optional) Edit
docker-compose.ymlenvironment values to your liking (see Environment variables). - Bring it up:
docker compose up -d
- MQ clients can connect to any of the exposed ports (e.g.,
22112–22116by default).
Heads‑up on port mapping: The
ports:stanza maps a range, and must matchEQBCS_PY_PORT_RANGE_STARTandEQBCS_PY_SERVER_COUNT. Example mapping from the included compose file:ports: - "22112-22116:22112-22116"With
EQBCS_PY_PORT_RANGE_START=22112andEQBCS_PY_SERVER_COUNT=5, that exposes instances on 22112..22116.
You can override any env just for a run:
- Linux/macOS:
EQBCS_PY_SERVER_COUNT=3 EQBCS_PY_PORT_RANGE_START=23112 docker compose up -d
- PowerShell:
$env:EQBCS_PY_SERVER_COUNT=3; $env:EQBCS_PY_PORT_RANGE_START=23112; docker compose up -d
The repo includes .vscode/deploy.py, an interactive SSH deploy helper that:
- Stores connection profiles in your OS keyring
- Rsync‑style uploads the repo to your server (excludes dotfolders and build junk)
- Runs
docker compose downthendocker compose build && docker compose up -dremotely
Run it directly
python .vscode/deploy.pyIt will prompt once for a profile (host, port, user, ~/remotePath, and either a key file or password), then remember it. You can choose a profile name via DEPLOY_PROFILE (defaults to the current folder name).
Run from VS Code Tasks (if you wire one) If you prefer Tasks, add a simple task that invokes the script:
Then ⇧⌘P / Ctrl+Shift+P → Tasks: Run Task → Deploy: Upload & Compose up.
python server.py -p 2112 -i 0.0.0.0 # default EQBCS port
# optional: require a password; clients must use LOGIN:<password>=
python server.py -p 2112 -s "MySecret"
# enable verbose logging
python server.py -p 2112 -vWhen running in Docker, the entrypoint spawns multiple instances for you. For a single local instance, you typically don’t need any env vars.
These are read by the server and/or the Docker entrypoint.
| Name | Type / Values | Default | Used by | Description |
|---|---|---|---|---|
EQBCS_PY_PORT_RANGE_START |
integer | 22112 (Docker) / CLI port |
entrypoint + server | First port in the range. Instance N runs on PORT_RANGE_START + N. The server uses this to compute the instance number for password selection. |
EQBCS_PY_SERVER_COUNT |
integer ≥ 1 | 1 |
entrypoint | How many instances to spawn in the container. Compose must map the entire range. |
EQBCS_PY_BIND |
IP | 0.0.0.0 |
entrypoint → server -i |
Bind address for each instance. |
EQBCS_PY_LOG_LEVEL |
DEBUG / INFO / WARNING / ERROR |
INFO |
server | Sets the server log level (overrides -v). |
EQBCS_PY_LOG_FILE |
path | (unset) | server | If set, logs also go to this file (in addition to stdout). |
Accepts 1/true/yes/on (case‑insensitive) for on.
| Name | Default | What it does |
|---|---|---|
EQBCS_PY_LOG_KEEPALIVE |
0 |
Log PING/PONG keepalive traffic. |
EQBCS_PY_LOG_RX_RAW |
0 |
Log raw inbound frames (noisy; for debugging protocol issues). |
EQBCS_PY_LOG_STATE |
0 |
Log connection lifecycle / state transitions. |
EQBCS_PY_LOG_CTRL_SUMMARY |
0 |
Log control command summaries. |
EQBCS_PY_LOG_CTRL_RECIPIENTS |
0 |
Log resolved recipients for TELL/BCI, etc. |
| Name | Type | Default | What it does |
|---|---|---|---|
EQBCS_PY_CLIENT_TIMEOUT |
seconds (int) | 120 |
If a client fails to PONG for this many seconds, disconnect it. Set 0 to disable disconnect (legacy advisory mode). |
You can set a master policy and optionally override it per instance. Each policy accepts:
"none"/"null"/"false"/"0"/"off"/ (unset) → no password required"auto"→ generates a secure password once per run, logs it at startup- any other string → use that exact password
| Name | Applies to | Example |
|---|---|---|
EQBCS_PY_MASTER_PASSWORD |
default for all instances | EQBCS_PY_MASTER_PASSWORD=auto |
EQBCS_PY_INSTANCE{N}_PASSWORD |
overrides instance N only (N = 0‑based) | EQBCS_PY_INSTANCE3_PASSWORD=MySecret |
Instance number (N) mapping:
If your range starts at 22112, then:
- instance 0 → port 22112
- instance 1 → port 22113
- …
Tip: You can mix policies. Example:
EQBCS_PY_MASTER_PASSWORD=autobutEQBCS_PY_INSTANCE0_PASSWORD=nonefor a public “no‑password” local instance alongside passworded ones.
Key bits of the shipped compose file:
services:
eqbcs:
build: .
container_name: eqemu_eqbcs_py
environment:
EQBCS_PY_SERVER_COUNT: 5
EQBCS_PY_PORT_RANGE_START: 22112
EQBCS_PY_LOG_LEVEL: INFO
EQBCS_PY_LOG_CTRL_SUMMARY: 0
EQBCS_PY_LOG_CTRL_RECIPIENTS: 0
EQBCS_PY_LOG_STATE: 0
EQBCS_PY_LOG_RX_RAW: 0
EQBCS_PY_LOG_KEEPALIVE: 0
ports:
- "22112-22116:22112-22116"
restart: unless-stopped
stop_signal: SIGTERM
stop_grace_period: 10s# Build
docker build -t eqemu_eqbcs_py .
# Run 5 instances on 22112..22116
docker run -d --name eqemu_eqbcs_py \
-e EQBCS_PY_SERVER_COUNT=5 \
-e EQBCS_PY_PORT_RANGE_START=22112 \
-e EQBCS_PY_LOG_LEVEL=INFO \
-p 22112-22116:22112-22116 \
--restart unless-stopped \
eqemu_eqbcs_py-p, --port <int> Port to listen on (default 2112)
-i, --bind <addr> Bind address (default 0.0.0.0)
-l, --logfile <path> Also write logs to this file
-v, --debug Enable verbose logging (INFO→DEBUG)
-s, --password <str> Require password; clients must send LOGIN:<password>=
In Docker, the entrypoint computes port per instance using
EQBCS_PY_PORT_RANGE_START + indexand passes-i/-pto each process.
- If you set
"auto"passwords, the generated secret is printed at startup logs—treat logs accordingly. - Exposed ports are open; restrict with firewall/security groups as needed.
- Anyone with write access to your GitHub/CI that can change envs or compose can change passwords—protect those paths.
- Clients can’t connect: Check that the exposed port range matches the envs (
docker compose ps+ your firewall). - Password rejected: Confirm which instance you’re on and its policy (master vs
INSTANCE{N}override). - Too chatty logs: Leave detail toggles at
0and setEQBCS_PY_LOG_LEVEL=INFO.
Actively iterating. Protocol behaviors are tracked in buildspec.yaml (spec doc, not AWS CodeBuild).
TBD.