mirror of
https://github.com/UNITRONIX/BetterDesk.git
synced 2026-09-10 17:45:42 +00:00
dd0889e3d6
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.
4.9 KiB
4.9 KiB
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 (
--cdapflag orCDAP_ENABLED=true) - API key created via
POST /api/keysor the web console - WebSocket library for your language
Quick Start (Go)
The reference agent is at betterdesk-agent/. It demonstrates the full lifecycle:
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:
pip install betterdesk-cdap # or: pip install -e sdks/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)
npm install betterdesk-cdap # or: npm install ./sdks/nodejs/
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
- Connect — Establish WebSocket to
ws://server:21122/cdap - Authenticate — Send
authmessage, wait forauth_response - Register manifest — Send device info, capabilities, and widget definitions
- Heartbeat loop — Periodically send metrics and widget values
- Handle commands — Listen for
commandmessages, execute, respond - 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: truefor destructive actions (reboot, clear data) - Use text for string values (hostname, IP address, firmware version)
- Group related widgets with the
groupfield 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.