2b5dac2c42
End-to-end BLE streaming: provider + client + per-protocol wire encoders with whole-strip averaging, desktop (bleak) and Android (Kotlin BleBridge via Chaquopy) transports, discovery with protocol-family detection that auto-fills the UI, throttled not-connected warning + 10 s reconnect cooldown so a dropped link no longer stalls the pipeline at ~30 s/frame, and an explicit asyncio.wait_for wrapper around bleak connect() since the WinRT backend doesn't always honor the timeout kwarg. Also rewrites server/restart.ps1 to be parameterized (-Port / -Module / -PythonVersion / timeouts / -Quiet), pick the right interpreter via the py launcher, pre-flight the target module, poll port readiness on both shutdown and startup, redirect child stdout/stderr so Start-Process doesn't hang on inherited Git-Bash handles, and return proper exit codes. Rolls in concurrent work: Android BLE permissions + launcher icons + ru/zh resources, Chaquopy-safe value_stream psutil fallback, setup-required modal, asset-store test coverage, and misc system/config touch-ups.
85 lines
4.0 KiB
Markdown
85 lines
4.0 KiB
Markdown
# Server Operations
|
|
|
|
**Read this file when restarting, starting, or managing the server process.**
|
|
|
|
## Server Modes
|
|
|
|
Two independent server modes with separate configs, ports, and data directories:
|
|
|
|
| Mode | Command | Config | Port | API Key | Data |
|
|
| ---- | ------- | ------ | ---- | ------- | ---- |
|
|
| **Real** | `python -m ledgrab` | `config/default_config.yaml` | 8080 | `development-key-change-in-production` | `data/` |
|
|
| **Demo** | `python -m ledgrab.demo` | `config/demo_config.yaml` | 8081 | `demo` | `data/demo/` |
|
|
|
|
Demo mode can also be triggered via the `LEDGRAB_DEMO` environment variable (`true`, `1`, or `yes`). This works with any launch method — Python, Docker (`-e LEDGRAB_DEMO=true`), or the installed app (`set LEDGRAB_DEMO=true` before `LedGrab.bat`).
|
|
|
|
Both modes can run simultaneously on different ports.
|
|
|
|
## Restart Procedure
|
|
|
|
Use the PowerShell restart script — it gracefully shuts the running server down (so stores persist to disk), kills stragglers, launches a detached replacement, and polls the port until it's actually accepting connections. Exit code is 0 on success, 1 if the new server failed to bind the port, 2 on environment errors.
|
|
|
|
### Real server
|
|
|
|
```bash
|
|
powershell -ExecutionPolicy Bypass -File "c:\Users\Alexei\Documents\led-grab-mixed\led-grab\server\restart.ps1"
|
|
```
|
|
|
|
### Demo server
|
|
|
|
```bash
|
|
powershell -ExecutionPolicy Bypass -File "c:\Users\Alexei\Documents\led-grab-mixed\led-grab\server\restart.ps1" `
|
|
-Port 8081 -Module ledgrab.demo -ConfigPath "config\demo_config.yaml"
|
|
```
|
|
|
|
### Useful parameters
|
|
|
|
- `-Port <int>` / `-Module <name>` — override the target (default: 8080 / `ledgrab`).
|
|
- `-StartupTimeoutSec <int>` — how long to wait for the new server to bind the port (default: 30).
|
|
- `-ShutdownTimeoutSec <int>` — how long to wait for graceful shutdown before force-killing (default: 15).
|
|
- `-Quiet` — suppress progress output.
|
|
- `-SkipBrowser:$false` — allow the app to open a browser tab on startup (default: skipped).
|
|
|
|
**Do NOT use** `Stop-Process -Name python` — it kills unrelated Python processes (VS Code extensions, etc.).
|
|
|
|
**Do NOT use** bash background `&` jobs — they get killed when the shell session ends.
|
|
|
|
## When to Restart
|
|
|
|
**Restart required** for changes to:
|
|
|
|
- API routes (`api/routes/`, `api/schemas/`)
|
|
- Core logic (`core/*.py`)
|
|
- Configuration (`config.py`)
|
|
- Utilities (`utils/*.py`)
|
|
- Data models (`storage/`)
|
|
|
|
**No restart needed** for:
|
|
|
|
- Static files (`static/js/`, `static/css/`) — but **must rebuild bundle**: `cd server && npm run build`
|
|
- Locale files (`static/locales/*.json`) — loaded by frontend
|
|
- Documentation files (`*.md`)
|
|
|
|
## Auto-Reload Note
|
|
|
|
Auto-reload is disabled (`reload=False` in `main.py`) due to watchfiles causing an infinite reload loop. Manual restart is required after server code changes.
|
|
|
|
## Demo Mode Awareness
|
|
|
|
**When adding new entity types, engines, device providers, or stores — keep demo mode in sync:**
|
|
|
|
1. **New entity stores**: Add the store's file path to `StorageConfig` in `config.py` — `model_post_init()` auto-rewrites `data/` to `data/demo/` paths when demo is active.
|
|
2. **New capture engines**: Verify demo mode filtering works — demo engines use `is_demo_mode()` gate in `is_available()`.
|
|
3. **New audio engines**: Same as capture engines — `is_available()` must respect `is_demo_mode()`.
|
|
4. **New device providers**: Gate discovery with `is_demo_mode()` like `DemoDeviceProvider.discover()`.
|
|
5. **New seed data**: Update `server/src/ledgrab/core/demo_seed.py` to include sample entities.
|
|
6. **Frontend indicators**: Demo state exposed via `GET /api/v1/version` -> `demo_mode: bool`. Frontend stores it as `demoMode` in app state and sets `document.body.dataset.demo = 'true'`.
|
|
7. **Backup/Restore**: New stores added to `STORE_MAP` in `system.py` automatically work in demo mode since the data directory is already isolated.
|
|
|
|
### Key files
|
|
|
|
- Config flag: `server/src/ledgrab/config.py` -> `Config.demo`, `is_demo_mode()`
|
|
- Demo engines: `core/capture_engines/demo_engine.py`, `core/audio/demo_engine.py`
|
|
- Demo devices: `core/devices/demo_provider.py`
|
|
- Seed data: `core/demo_seed.py`
|