195 lines
8.5 KiB
Markdown
195 lines
8.5 KiB
Markdown
# Research: Remote Single-File Copy To Host
|
|
|
|
## Relevante file analysis
|
|
|
|
### Backend
|
|
|
|
- [routes_files.py](/workspace/webmanager-mvp/webui/backend/app/api/routes_files.py)
|
|
Bevat de bestaande lokale upload-route (`POST /api/files/upload`) en de remote read-only Phase 3 routes (`view`, `info`, `download`, `image`) via `RemoteFileService`.
|
|
- [routes_copy.py](/workspace/webmanager-mvp/webui/backend/app/api/routes_copy.py)
|
|
Bevat de bestaande copy-route (`POST /api/files/copy`) die volledig uitgaat van host-side source en host-side destination.
|
|
- [file_ops_service.py](/workspace/webmanager-mvp/webui/backend/app/services/file_ops_service.py)
|
|
Bevat lokale file-acties. Relevant is vooral `upload()`, omdat die host-write doet na `PathGuard`-validatie van een doeldirectory.
|
|
- [copy_task_service.py](/workspace/webmanager-mvp/webui/backend/app/services/copy_task_service.py)
|
|
Bevat task-opbouw, destination-validatie en taakcreatie voor copy, maar gaat uit van een lokale bron die via `PathGuard` naar een host-pad resolveert.
|
|
- [remote_file_service.py](/workspace/webmanager-mvp/webui/backend/app/services/remote_file_service.py)
|
|
Bevat al de benodigde remote read-path parsing, share-validatie via registry, agent-auth, error mapping en een gestreamde `prepare_download()` naar de agent.
|
|
- [filesystem_adapter.py](/workspace/webmanager-mvp/webui/backend/app/fs/filesystem_adapter.py)
|
|
Bevat de feitelijke host-write helpers:
|
|
- `write_uploaded_file(path, file_stream, overwrite=False)`
|
|
- `copy_file(source, destination, on_progress=None)`
|
|
`copy_file` vereist een lokale bron op de host en is dus niet bruikbaar voor remote input. `write_uploaded_file` schrijft een inkomende stream naar een hostpad en is conceptueel het dichtstbij.
|
|
- [path_guard.py](/workspace/webmanager-mvp/webui/backend/app/security/path_guard.py)
|
|
Houdt host-write validatie strikt lokaal. Dat moet zo blijven; remote paden mogen hier niet als bronsemantiek in terechtkomen.
|
|
- [tasks_runner.py](/workspace/webmanager-mvp/webui/backend/app/tasks_runner.py)
|
|
Bevat task-based copy/move uitvoering, maar alleen voor host-side bronpaden. Wel relevant als patroon voor een aparte remote-to-host worker.
|
|
- [schemas.py](/workspace/webmanager-mvp/webui/backend/app/api/schemas.py)
|
|
Bevat bestaande `CopyRequest` en upload/copy response-modellen. Voor een aparte feature is waarschijnlijk een nieuw requestmodel nodig.
|
|
|
|
### Frontend
|
|
|
|
- [app.js](/workspace/webmanager-mvp/webui/html/app.js)
|
|
Relevante bestaande flows:
|
|
- `uploadFileRequest()` gebruikt uitsluitend `/api/files/upload`
|
|
- `startCopySelected()` gebruikt uitsluitend `/api/files/copy`
|
|
- remote browse/view/download is al source-aware
|
|
- remote copy is nu bewust geblokkeerd
|
|
Dit bevestigt dat upload-flow en copy-flow momenteel twee losse UI-contracten zijn.
|
|
|
|
### Agent
|
|
|
|
- [finder_commander/app/main.py](/workspace/webmanager-mvp/finder_commander/app/main.py)
|
|
Agent heeft al wat voor deze feature nodig is:
|
|
- strikte `share + relative path` validatie
|
|
- `GET /api/info`
|
|
- `GET /api/download`
|
|
Voor remote single-file copy naar host is geen nieuwe remote write-API nodig.
|
|
|
|
## Oordeel over hergebruik van upload-internals
|
|
|
|
### Bestaande upload-functionaliteit aanpassen?
|
|
|
|
Nee.
|
|
|
|
Reden:
|
|
|
|
- de bestaande upload-route, upload-requestvorm en upload-UI werken al goed
|
|
- upload is browser -> host via multipart/form-data
|
|
- de gewenste feature is agent/remote -> host via backend-proxy/stream
|
|
- dat is een ander contract, andere foutbron en andere bronsemantiek
|
|
|
|
### Interne host-write logica hergebruiken?
|
|
|
|
Ja, maar alleen op intern helper/service-niveau.
|
|
|
|
Concreet oordeel:
|
|
|
|
- `FilesystemAdapter.copy_file()` is niet geschikt voor hergebruik
|
|
Reden: vereist een lokale host-bronpad als source.
|
|
- `FilesystemAdapter.write_uploaded_file()` is deels relevant
|
|
Reden: dit doet precies de host-write van een inkomende stream naar een doelbestand.
|
|
- Direct hergebruik van `FileOpsService.upload()` is niet verstandig
|
|
Reden: die methode is semantisch en contractueel gekoppeld aan multipart upload en `UploadFile`.
|
|
|
|
Best passende richting:
|
|
|
|
- niet hergebruiken via bestaande upload-endpoints of upload-flow
|
|
- wel overwegen om de onderliggende stream-naar-bestand write logica te hergebruiken of te veralgemeniseren in `FilesystemAdapter`
|
|
- voorkeur: een nieuwe sibling-helper zoals `write_stream_file(...)` of een kleine interne extractie, zodat upload ongewijzigd blijft en remote copy dezelfde veilige host-write primitief kan gebruiken
|
|
|
|
## Ontwerpvoorstel
|
|
|
|
### Feature
|
|
|
|
`Copy remote file to host`
|
|
|
|
### Scope
|
|
|
|
- alleen single file
|
|
- alleen source onder `/Clients/...`
|
|
- alleen destination op host-side lokale map
|
|
- geen mappen
|
|
- geen overwrite in eerste change request tenzij expliciet gewenst
|
|
- geen upload-route hergebruik
|
|
- geen brede refactor
|
|
|
|
### Backendontwerp
|
|
|
|
Voeg een aparte backend feature toe, niet via `POST /api/files/upload` en niet via bestaande `POST /api/files/copy`.
|
|
|
|
Voorkeursvorm:
|
|
|
|
- nieuwe route, bijvoorbeeld `POST /api/files/remote-copy`
|
|
- request bevat:
|
|
- `source`: remote bestandspad onder `/Clients/...`
|
|
- `destination_dir`: host-directory pad
|
|
|
|
Nieuwe service, bijvoorbeeld:
|
|
|
|
- `RemoteCopyToHostService`
|
|
|
|
Verantwoordelijkheden:
|
|
|
|
1. valideer dat `source` een remote `/Clients/...` file is
|
|
2. valideer dat `destination_dir` een host-directory is via bestaande lokale `PathGuard`
|
|
3. haal remote metadata op of resolve remote naam via bestaande `RemoteFileService`
|
|
4. bouw destination pad als `destination_dir/<remote-filename>`
|
|
5. faal op bestaand doelbestand in eerste versie
|
|
6. open remote download-stream via aparte interne helper op `RemoteFileService`
|
|
7. schrijf gestreamd naar host met een aparte interne host-write helper
|
|
8. map fouten strikt:
|
|
- remote unavailable blijft lokale actie-fout
|
|
- host permission/path-conflict blijft gewone host-fout
|
|
|
|
### Aanbevolen interne hergebruikslijn
|
|
|
|
- laat `RemoteFileService` een interne streaming primitive aanbieden, bijvoorbeeld een variant op de huidige remote download-open logica zonder HTTP-response voor browser-download
|
|
- laat `FilesystemAdapter` een aparte stream-write helper aanbieden voor generieke inkomende streams
|
|
- laat upload zijn bestaande publieke route en flow behouden
|
|
|
|
### Frontendontwerp
|
|
|
|
Geen wijziging aan upload-UI.
|
|
|
|
Kleine aparte UI-feature:
|
|
|
|
- toon een aparte actie alleen als:
|
|
- bronpane een remote file-selectie heeft van exact 1 bestand
|
|
- doelpane op een host/local directory staat
|
|
- de actie roept de nieuwe backend-route aan
|
|
- na succes:
|
|
- refresh beide panes
|
|
- toon lokale foutmelding bij falen
|
|
|
|
Voorkeur:
|
|
|
|
- aparte actie of expliciete source-aware branch voor "Copy remote file to host"
|
|
- niet de bestaande upload-flow hergebruiken
|
|
|
|
### Agentontwerp
|
|
|
|
Geen nieuwe agent-endpoints nodig in deze scope.
|
|
|
|
De bestaande `GET /api/download` is voldoende als read-only bron voor streaming.
|
|
|
|
## Acceptance criteria
|
|
|
|
- een enkel bestand onder `/Clients/...` kan naar een host-directory worden gekopieerd
|
|
- de destination moet een host/local directory zijn
|
|
- mappen als remote bron worden geweigerd
|
|
- remote -> remote wordt geweigerd
|
|
- host -> remote wordt geweigerd
|
|
- overwrite gebeurt niet impliciet; bestaand doelbestand geeft een nette fout
|
|
- bestaande upload-route, upload-contract en upload-UI blijven ongewijzigd
|
|
- bestaande lokale copy-flow blijft ongewijzigd
|
|
- remote fouten blijven lokaal tot deze actie
|
|
- host-write blijft onder bestaande lokale `PathGuard`-regels vallen
|
|
- data wordt gestreamd; geen volledige file-buffer in memory
|
|
|
|
## Klein plan
|
|
|
|
1. Voeg een research-backed change request toe voor een aparte route `POST /api/files/remote-copy`.
|
|
2. Voeg een kleine service toe die alleen remote single-file source + local destination_dir ondersteunt.
|
|
3. Voeg een interne streaming helper toe in `RemoteFileService` voor remote bestand-inname door backend.
|
|
4. Voeg een aparte interne host-write helper toe in `FilesystemAdapter` voor generieke stream-naar-bestand writes, zonder upload-API te wijzigen.
|
|
5. Voeg minimale frontend wiring toe voor een aparte "Copy remote file to host"-actie.
|
|
6. Test stapsgewijs:
|
|
- success path remote file -> local dir
|
|
- bestaand doelbestand
|
|
- remote directory rejected
|
|
- remote failure stays local
|
|
- upload-regressie: bestaande `/api/files/upload` blijft ongewijzigd
|
|
|
|
## Expliciete lijst van wat buiten scope blijft
|
|
|
|
- remote mappen kopiëren
|
|
- remote write-acties
|
|
- remote -> remote
|
|
- host -> remote
|
|
- aanpassing van bestaande upload-routes
|
|
- aanpassing van upload-requestcontract
|
|
- aanpassing van upload-UI
|
|
- brede refactor van copy/upload/task-infrastructuur
|
|
- bookmarks/startup paths
|
|
- remote task-runner verbreding buiten deze ene actie
|