6.6 KiB
Example image route architecture
The example image routing stack mirrors the layered model route stack described in
docs/architecture/model_routes.md. HTTP wiring, controller setup,
handler orchestration, and long-running workflows now live in clearly separated modules so
we can extend download/import behaviour without touching the entire feature surface.
graph TD
subgraph HTTP
A[ExampleImagesRouteRegistrar] -->|binds| B[ExampleImagesRoutes controller]
end
subgraph Application
B --> C[ExampleImagesHandlerSet]
C --> D1[Handlers]
D1 --> E1[Use cases]
E1 --> F1[Download manager / processor / file manager]
end
subgraph Side Effects
F1 --> G1[Filesystem]
F1 --> G2[Model metadata]
F1 --> G3[WebSocket progress]
end
Layer responsibilities
| Layer | Module(s) | Responsibility |
|---|---|---|
| Registrar | py/routes/example_images_route_registrar.py |
Declarative catalogue of every example image endpoint plus helpers that bind them to an aiohttp router. Keeps HTTP concerns symmetrical with the model registrar. |
| Controller | py/routes/example_images_routes.py |
Lazily constructs ExampleImagesHandlerSet, injects defaults for the download manager, processor, and file manager, and exposes the registrar-ready mapping just like BaseModelRoutes. |
| Handler set | py/routes/handlers/example_images_handlers.py |
Groups HTTP adapters by concern (downloads, imports/deletes, filesystem access). Each handler translates domain errors into HTTP responses and defers to a use case or utility service. |
| Use cases | py/services/use_cases/example_images/*.py |
Encapsulate orchestration for downloads and imports. They validate input, translate concurrency/configuration errors, and keep handler logic declarative. |
| Supporting services | py/utils/example_images_download_manager.py, py/utils/example_images_processor.py, py/utils/example_images_file_manager.py |
Execute long-running work: pull assets from Civitai, persist uploads, clean metadata, expose filesystem actions with guardrails, and broadcast progress snapshots. |
Handler responsibilities & invariants
ExampleImagesHandlerSet flattens the handler objects into the {"handler_name": coroutine}
mapping consumed by the registrar. The table below outlines how each handler collaborates
with the use cases and utilities.
| Handler | Key endpoints | Collaborators | Contracts |
|---|---|---|---|
ExampleImagesDownloadHandler |
/api/lm/download-example-images, /api/lm/example-images-status, /api/lm/pause-example-images, /api/lm/resume-example-images, /api/lm/force-download-example-images |
DownloadExampleImagesUseCase, DownloadManager |
Delegates payload validation and concurrency checks to the use case; progress/status endpoints expose the same snapshot used for WebSocket broadcasts; pause/resume surface DownloadNotRunningError as HTTP 400 instead of 500. |
ExampleImagesManagementHandler |
/api/lm/import-example-images, /api/lm/delete-example-image |
ImportExampleImagesUseCase, ExampleImagesProcessor |
Multipart uploads are streamed to disk via the use case; validation failures return HTTP 400 with no filesystem side effects; deletion funnels through the processor to prune metadata and cached images consistently. |
ExampleImagesFileHandler |
/api/lm/open-example-images-folder, /api/lm/example-image-files, /api/lm/has-example-images |
ExampleImagesFileManager |
Centralises filesystem access, enforcing settings-based root paths and returning HTTP 400/404 for missing configuration or folders; responses always include success/has_images booleans for UI consumption. |
Use case boundaries
| Use case | Entry point | Dependencies | Guarantees |
|---|---|---|---|
DownloadExampleImagesUseCase |
execute(payload) |
DownloadManager.start_download, download configuration errors |
Raises DownloadExampleImagesInProgressError when the manager reports an active job, rewraps configuration errors into DownloadExampleImagesConfigurationError, and lets ExampleImagesDownloadError bubble as 500s so handlers do not duplicate logging. |
ImportExampleImagesUseCase |
execute(request) |
ExampleImagesProcessor.import_images, temporary file helpers |
Supports multipart or JSON payloads, normalises file paths into a single list, cleans up temp files even on failure, and maps validation issues to ImportExampleImagesValidationError for HTTP 400 responses. |
Maintaining critical invariants
- Shared progress snapshots - The download handler returns the same snapshot built by
DownloadManager, guaranteeing parity between HTTP polling endpoints and WebSocket progress events. - Safe filesystem access - All folder/file actions flow through
ExampleImagesFileManager, which validates the configured example image root and ensures responses never leak absolute paths outside the allowed directory. - Metadata hygiene - Import/delete operations run through
ExampleImagesProcessor, which updates model metadata viaMetadataManagerand notifies the relevant scanners so cache state stays in sync.
Migration notes
The refactor brings the example image stack in line with the model/recipe stacks:
ExampleImagesRouteRegistrarnow owns the declarative route list. Downstream projects should rely onExampleImagesRoutes.to_route_mapping()instead of manually wiring handler callables.ExampleImagesRoutescaches itsExampleImagesHandlerSetjust likeBaseModelRoutes. If you previously instantiated handlers directly, inject custom collaborators via the controller constructor (download_manager,processor,file_manager) to keep test seams predictable.- Tests that mocked
ExampleImagesRoutes.setup_routesshould switch to patchingDownloadExampleImagesUseCase/ImportExampleImagesUseCaseat import time. The handlers expect those abstractions to surface validation/concurrency errors, and bypassing them will skip the HTTP-friendly error mapping.
Extending the stack
- Add the endpoint to
ROUTE_DEFINITIONSwith a uniquehandler_name. - Expose the coroutine on an existing handler class (or create a new handler and extend
ExampleImagesHandlerSet). - Wire additional services or factories inside
_build_handler_setonExampleImagesRoutes, mirroring how the model stack introduces new use cases.
tests/routes/test_example_images_routes.py exercises registrar binding, download pause
flows, and import validations. Use it as a template when introducing new handler
collaborators or error mappings.