Files
UNITRONIX dd0889e3d6 Add SessionManager; update docs, i18n & CI
Introduce a SessionManager for relay-based remote sessions in the Tauri MGMT client: new SessionCommand API, start/stop/session input routing, clipboard/recording/quality controls, and notification read/dismiss state. Wire AppState with new mutexes and show main window on startup. CI: add SBOM generation (anchore) and Trivy vulnerability scan steps. Misc: change console Docker DB path, large README/CHANGELOG updates (chat E2E, unattended access/WOL, i18n expansion, CDAP/SDK docs), and many web-nodejs assets/locales/routes/views/services and server-side changes.
2026-04-05 13:42:07 +02:00

150 lines
4.9 KiB
Markdown

# Building a CDAP Agent
This guide walks through building a custom CDAP agent that connects to a BetterDesk server.
## Prerequisites
- BetterDesk server running with CDAP enabled (`--cdap` flag or `CDAP_ENABLED=true`)
- API key created via `POST /api/keys` or the web console
- WebSocket library for your language
## Quick Start (Go)
The reference agent is at `betterdesk-agent/`. It demonstrates the full lifecycle:
```bash
cd betterdesk-agent
go build -o betterdesk-agent .
./betterdesk-agent \
--server ws://your-server:21122/cdap \
--auth-method api_key \
--api-key YOUR_KEY \
--device-id MY-DEVICE-001 \
--device-name "Office Workstation" \
--device-type os_agent
```
## Quick Start (Python)
Using the BetterDesk Python SDK:
```bash
pip install betterdesk-cdap # or: pip install -e sdks/python/
```
```python
import asyncio
from betterdesk_cdap import CDAPBridge, Widget
class MyAgent(CDAPBridge):
def __init__(self):
super().__init__(
server_url="ws://your-server:21122/cdap",
device_id="MY-PY-AGENT",
device_name="Python Agent",
device_type="custom_agent",
auth_method="api_key",
api_key="YOUR_KEY"
)
# Define widgets
self.add_widget(Widget.gauge("temp", "Temperature", group="Sensors",
unit="°C", min_val=0, max_val=100,
danger=80, warning=60))
self.add_widget(Widget.button("restart", "Restart Service",
group="Actions", command="restart_svc",
confirm=True))
async def on_connected(self):
print("Connected to server!")
async def on_command(self, command_id, command, args):
if command == "restart_svc":
# Execute the command
import subprocess
subprocess.run(["systemctl", "restart", "myservice"])
await self.send_command_response(command_id, True, "Service restarted")
else:
await self.send_command_response(command_id, False, f"Unknown: {command}")
async def collect_metrics(self):
"""Called every heartbeat interval."""
import psutil
return {
"temp": read_temperature_sensor(),
}
asyncio.run(MyAgent().run())
```
## Quick Start (Node.js)
```bash
npm install betterdesk-cdap # or: npm install ./sdks/nodejs/
```
```javascript
const { CDAPBridge, Widget } = require('betterdesk-cdap');
const agent = new CDAPBridge({
serverUrl: 'ws://your-server:21122/cdap',
deviceId: 'MY-NODE-AGENT',
deviceName: 'Node.js Agent',
deviceType: 'custom_agent',
authMethod: 'api_key',
apiKey: 'YOUR_KEY'
});
agent.addWidget(Widget.gauge('cpu', 'CPU Usage', {
group: 'System', unit: '%', min: 0, max: 100, danger: 90
}));
agent.on('command', async (cmdId, command, args) => {
if (command === 'ping') {
agent.sendCommandResponse(cmdId, true, 'pong');
}
});
agent.on('connected', () => console.log('Connected!'));
agent.connect();
```
## Agent Lifecycle
1. **Connect** — Establish WebSocket to `ws://server:21122/cdap`
2. **Authenticate** — Send `auth` message, wait for `auth_response`
3. **Register manifest** — Send device info, capabilities, and widget definitions
4. **Heartbeat loop** — Periodically send metrics and widget values
5. **Handle commands** — Listen for `command` messages, execute, respond
6. **Reconnect** — On disconnect, exponential backoff reconnect (2s, 4s, 8s... max 60s)
## Widget Best Practices
- Use **gauge** for numeric metrics with known ranges (CPU, temperature, battery)
- Use **toggle** for on/off controls (enable/disable service, relay switch)
- Use **button** with `confirm: true` for destructive actions (reboot, clear data)
- Use **text** for string values (hostname, IP address, firmware version)
- Group related widgets with the `group` field for organized display
- Keep widget IDs stable across reconnects (don't generate random IDs)
## Capabilities
Only declare capabilities your agent actually supports:
| Capability | When to declare |
|------------|----------------|
| `telemetry` | Agent collects and reports system/sensor metrics |
| `commands` | Agent can execute named commands |
| `terminal` | Agent provides PTY terminal access |
| `file_transfer` | Agent supports file browse/read/write/delete |
| `clipboard` | Agent can get/set system clipboard |
| `screenshot` | Agent can capture screen |
| `audio` | Agent supports audio streaming |
## Security Notes
- **Never hardcode API keys** in source code. Use environment variables or config files.
- **Validate all commands** before executing. Reject unknown commands.
- **Path traversal protection** — Validate file paths in file_transfer operations. The reference agent uses `safePath()` to prevent `../../` attacks.
- **Rate limiting** — Don't flood the server with state updates. Batch changes with `bulk_update`.