Files
appRobotFileservice/README.md
2026-06-15 09:22:41 +02:00

157 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# appRobotFileservice
Programm-/File-Handling-Service für den AppRobot. Speichert **G-Code-Programme**
(`.gcode` + `.json`-Sidecar), hält das **aktive Programm + Cursor** und unterstützt
**Teaching** (Pose aufnehmen), **Playback** (Programm abspielen) sowie einen
**Browser-basierten Datei-Browser** auf Port 2100.
## Rolle in der Architektur
```
Steuerungen → appRobotDriver → appRobotFileservice ← Browser (Port 2100)
(Joystick, …) (Gateway) (dieses Projekt)
[Senden-Modus, lokales Netz]
└──► appRobotDriver WS
```
- **Steuerungen** kennen nur den Driver. Datei-Befehle (**FCodes** wie `FList`,
`FPoint`, `FPlus`) schickt die Steuerung an den Driver, der sie als REST-Aufrufe
hierher weiterreicht.
- **Browser** spricht direkt mit dem Fileservice (Port 2100). Im **Senden-Modus**
sendet der Fileservice die G-Code-Zeile server-seitig an den Driver — der Browser
verbindet sich nie direkt mit dem Driver.
- **Playback**: dieser Service liefert die nächste Zeile **driver-nativ (Radian)**
zurück; ausgeführt wird sie vom Driver.
## Einheiten (wichtig)
- **Gespeichert** wird in **Grad** (Standard-G-Code, lesbar): `a/b/c/e` in Grad,
`x/y/z` in mm.
- **Am Wire / zum Driver** ist alles **driver-nativ**: `a/b/c/e` in **Radian**.
- Die Umrechnung passiert **ausschließlich hier** (`src/gcode/units.js`).
## Dateiformat
`.gcode` ist die **einzige verbindliche Positions-Abfolge** — reiner Standard-G-Code,
Zeitstempel und Cursor-Marker stehen im Kommentarfeld:
```
G90 G1 x0 y300 z0 a90.00 b-90.00 c0.00 e0.00 f1000 ;1759566014
G90 G1 x310 y444 z0.5 a90.00 b-90.00 c0.00 e6.88 f1000 ;1759566112!
```
- `;<epoch>` = Aufnahme-Zeitstempel.
- `;!` (Ausrufezeichen am Ende des Kommentars) = **Cursor-Marker**: zeigt die
zuletzt angefahrene Zeile. Primäre Cursor-Quelle beim Lesen. Direkt im Texteditor
sichtbar.
- `<id>.json` ist ein Sidecar mit Metadaten (Name, Zeiten, `lineCount`, `angleUnit`).
`cursor` im Sidecar dient nur als Fallback für Altdateien ohne `;!`-Marker.
## Start
```
npm install
npm start # http://localhost:2100
npm test # jest
```
HTTP (kein TLS) — der Service ist intern. Konfiguration via Env-Variablen (s. u.).
## Konfiguration (Env)
| Variable | Default | Zweck |
|---|---|---|
| `FILE_SERVICE_PORT` | `2100` | Port |
| `STORAGE_DIR` | `./GCodeFiles` | Wurzel-Verzeichnis für `.gcode` + `.json` |
| `FILE_EXT` | `gcode` | `gcode` oder `ngc` |
| `STORE_ANGLE_UNIT` | `deg` | Speichereinheit der Winkel |
| `FILE_API_KEY` | | Bearer-Token für Schreibzugriffe (fehlt → offen, Dev) |
| `DRIVER_WS_URL` | | WS-URL des appRobotDriver (z. B. `wss://appRobotDriver:2095`); leer → Senden-Modus deaktiviert |
| `DRIVER_TIMEOUT_MS` | `10000` | Maximale Wartezeit auf Driver-Antwort (ms) |
## API (Kurzüberblick)
### Programme
| Endpoint | Methode | Zweck |
|---|---|---|
| `GET /api/programs?dir=` | GET | Programme auflisten |
| `POST /api/programs` | POST | Programm anlegen |
| `DELETE /api/programs/:id?dir=` | DELETE | Programm löschen |
| `GET /api/programs/:id/download` | GET | `.gcode`-Datei herunterladen |
### Ordner
| Endpoint | Methode | Zweck |
|---|---|---|
| `GET /api/folders?dir=` | GET | Unterordner auflisten |
| `POST /api/folders` | POST | Unterordner anlegen |
| `DELETE /api/folders/:name?dir=` | DELETE | Unterordner (rekursiv) löschen |
### Aktives Programm
| FCode (am Driver) | Endpoint | Hinweis |
|---|---|---|
| `FList` | `GET /api/programs` | |
| `FLoad <id>` | `PUT /api/active` | `{ id, dir }` |
| `FClear` | `POST /api/active/clear` | |
| `FPoint` | `POST /api/active/points` | |
| `FPlus` / `FMinus` | `POST /api/active/next` / `/prev` | `?execute=true` → auch an Driver senden |
| `FFirst` / `FLast` | `POST /api/active/first` / `/last` | `?execute=true` → auch an Driver senden |
| `FGoto <n>` | `POST /api/active/goto` | |
| `FPlay` / `FStop` | `POST /api/active/play` / `/stop` | |
| — | `DELETE /api/active/lines/:index` | Zeile löschen |
### Senden-Modus (`?execute=true`)
`POST /api/active/next?execute=true` bewegt den Cursor UND sendet die G-Code-Zeile
an den Driver (server-seitig). Der Endpoint wartet auf die Driver-Antwort:
- **Erfolg** (M114-Broadcast) → HTTP 200 `{ cursor, line, driverPos }`
- **Driver-Fehler** → HTTP 502 `{ error, message }`
- **Timeout** → HTTP 504
### Konfiguration
| Endpoint | Zweck |
|---|---|
| `GET /api/health` | Liveness-Check |
| `GET /api/config` | `{ driverConfigured: bool }` — ob `DRIVER_WS_URL` gesetzt ist |
## Projektstruktur
```
index.js Einstiegspunkt (startet den Server)
src/
config.js Env-Konfiguration (inkl. driverWsUrl, driverTimeoutMs)
server.js Express-App (createApp, /api/config, /api/health)
errors.js Fehler-Envelope + Middleware
auth.js Bearer-Auth (für Schreibzugriffe)
driverClient.js WS-Client zum Driver (Senden-Modus)
gcode/units.js Grad↔Radian, Zeilenformat, Cursor-Marker (;!)
store/fileStore.js .gcode + .json Persistenz (mit dir-Support, max. 5 Ebenen)
active/activeState.js Aktives Programm + Cursor (Singleton, ;!-Persistenz)
routes/programs.js /api/programs* inkl. /download
routes/active.js /api/active* inkl. ?execute=true
routes/folders.js /api/folders*
public/
index.html Browser-UI (Datei-Browser + Stepping + Senden-Modus)
index.css Design-System (dark theme, CSS-Variablen)
test/
units.test.js Einheiten + Cursor-Marker-Funktionen
fileStore.test.js Persistenz-Tests (;!-Marker, dir-Support)
activeState.test.js ActiveState-Tests (Teaching, Stepping, Cursor-Persistenz)
driverClient.test.js WS-Client (Erfolg, Fehler, Timeout)
doc/
fileBrowser.md Browser-UI Ist-Zustand
commandsFromGCodeFile.md Senden-Modus Konzept + Implementierungsplan
draft_filehandeling.md Original-Konzept (historisch)
draft_filehandeling_API.md Original-API-Entwurf (historisch)
GCodeFiles/ Programm-Storage zur Laufzeit
```
## Status
Produktiv einsetzbar. Offen: Upload via Browser, Inline-Editor, Live-Updates via SSE
(statt 5s-Polling). Siehe [`doc/fileBrowser.md`](doc/fileBrowser.md).