Files
appRobotFileservice/README.md
chk b68bdfa9b4 Initiales Projekt-Skelett appRobotFileservice
Ausgelagertes Programm-/File-Handling (vormals GCode.receiveFC im appRobotDriver,
ToDo_4 / ToDo_6b). Express-Service mit .gcode + .json-Storage, aktivem Programm +
Cursor, Teaching (FPoint) und Playback. Speicherung in Grad, driver-nativ (Radian)
zum Driver. Konzept/API unter doc/draft_filehandeling*.md. Tests: jest (13 gruen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 10:12:41 +02:00

130 lines
5.1 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) und **Playback** (Programm abspielen).
Dieses Projekt wurde aus dem `appRobotDriver` ausgelagert (vormals `GCode.receiveFC`,
ToDo_4 / ToDo_6b). Konzept und Schnittstelle:
[`doc/draft_filehandeling.md`](doc/draft_filehandeling.md) ·
[`doc/draft_filehandeling_API.md`](doc/draft_filehandeling_API.md).
## Rolle in der Architektur
```
Steuerungen → appRobotDriver → appRobotFileservice
(Joystick, …) (Gateway) (dieses Projekt, passiv)
```
- 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.
- Dieser Service ist **passiv und driver-agnostisch**: er ruft den Driver nie an,
kennt weder dessen URL noch dessen Pose. Beim `FPoint` schickt der **Driver die
Pose mit**.
- **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** (standardnahe `.gcode`, 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`) — der Driver
rechnet nie um.
## Dateiformat
`.gcode` sieht aus wie Standard-G-Code; Zeitstempel und Cursor stehen im
**Kommentarfeld** (`;…`, standardkonform):
```
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! <- Cursor (!)
```
- `;<epoch>` = Aufnahme-Zeitstempel · abschließendes `!` = Cursor-Zeile.
- Der Cursor lebt zur Laufzeit als In-Memory-Index (schnelles Stepping ohne
Neuschreiben) und wird beim Speichern/Entladen als `!` zurückgeschrieben.
- `<id>.json` ist ein Sidecar mit Metadaten (Name, Zeiten, `lineCount`, `angleUnit`).
## Start
```
npm install
npm start # http://localhost:2100
npm test # jest
```
HTTP (kein TLS) — der Service ist intern (Driver → Service). TLS kann später analog
zum Driver-`InfoServer` ergänzt werden.
## API (Kurzüberblick)
Vollständig in [`doc/draft_filehandeling_API.md`](doc/draft_filehandeling_API.md).
| FCode (am Driver) | Endpoint |
|---|---|
| `FList` | `GET /api/programs` |
| `FShow [id]` | `GET /api/programs/:id` |
| `FSave <name>` | `POST /api/programs` |
| `FLoad <id>` | `PUT /api/active` |
| `FClear` | `POST /api/active/clear` |
| `FPoint` | `POST /api/active/points` |
| `FPlus` / `FMinus` | `POST /api/active/next` / `/prev` |
| `FFirst` / `FLast` | `POST /api/active/first` / `/last` |
| `FGoto <n>` | `POST /api/active/goto` |
| `FPlay` / `FStop` | `POST /api/active/play` / `/stop` |
Beispiel:
```bash
# Teaching: leeres Programm aktiv, Pose aufnehmen, speichern
curl -X PUT localhost:2100/api/active -H 'content-type: application/json' -d '{"id":"demo_c"}'
curl -X POST localhost:2100/api/active/points -H 'content-type: application/json' \
-d '{"pose":{"x":0,"y":300,"z":0,"a":1.5708,"b":-1.5708,"c":0,"e":0},"feedrate":1000}'
curl -X POST localhost:2100/api/programs -H 'content-type: application/json' -d '{"name":"Demo C","fromActive":true}'
# Playback: laden, erste Zeile (Radian) holen → der Driver führt sie aus
curl -X PUT localhost:2100/api/active -H 'content-type: application/json' -d '{"id":"demo_c"}'
curl -X POST localhost:2100/api/active/first
```
> Hinweis: `PUT /api/active` legt ein nicht existierendes Programm **leer an** (für
> Teaching). `EMPTY_PROGRAM`/`CURSOR_OUT_OF_RANGE` betreffen nur das Stepping/Playback.
## Konfiguration (Env)
| Variable | Default | Zweck |
|---|---|---|
| `FILE_SERVICE_PORT` | `2100` | Port |
| `STORAGE_DIR` | `./GCodeFiles` | 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) |
## Projektstruktur
```
index.js Einstiegspunkt (startet den Server)
src/
config.js Env-Konfiguration
server.js Express-App (createApp)
errors.js Fehler-Envelope + Middleware
auth.js Bearer-Auth (für Schreibzugriffe)
gcode/units.js Grad↔Radian, Zeilenformat, Cursor-/Kommentar-Helfer
store/fileStore.js .gcode + .json Persistenz (id-basiert, kein Pfad-Zugriff)
active/activeState.js aktives Programm + Cursor (Single Source of Truth)
routes/programs.js /api/programs*
routes/active.js /api/active*
test/ jest (units, fileStore, activeState)
doc/ Konzept + API (Drafts)
GCodeFiles/ Programm-Storage (zur Laufzeit)
```
## Status
Erste lauffähige Umsetzung. Offen u. a.: WebSocket-Event-Kanal (Live-Cursor),
Playlists („nächste File"), benannte Labels im Sidecar, TLS. Siehe „Offene Fragen"
in [`doc/draft_filehandeling.md`](doc/draft_filehandeling.md).