mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-29 18:51:43 +02:00
docs(slicer-api): switch sidecar to pre-built images on GHCR + Docker Hub (#1657)
Local build via Docker git context required `git` in the BuildKit worker,
which QNAP Container Station and Synology DSM don't provide. Both sidecar
images are now published to ghcr.io/maziggy/{orca-slicer-api,bambu-studio-api}
and docker.io/maziggy/{orca-slicer-api,bambu-studio-api}; compose pulls
:latest by default, SIDECAR_TAG=bambuddy-X.Y.Z pins per release.
Wiki, slicer-api README, .env.example, and CHANGELOG aligned. Build-from-source
path kept under "Building from source (advanced)" for forks / dev work.
Both images are linux/amd64 only — OrcaSlicer ARM64 on hold pending upstream
fix; BambuStudio doesn't publish ARM64.
This commit is contained in:
@@ -4,6 +4,9 @@ All notable changes to Bambuddy will be documented in this file.
|
||||
|
||||
## [0.2.5b1] - Unreleased
|
||||
|
||||
### Changed
|
||||
- **Slicer sidecar now ships as pre-built images on GHCR + Docker Hub — install works on QNAP / Synology / Container Station (#1657, reported by @d3nn3s08)** — Reporter on QNAP QTS 5.2.9 hit three install failures in sequence: the official `slicer-api/docker-compose.yml` used `build: { context: https://github.com/maziggy/orca-slicer-api.git#bambuddy/profile-resolver }`, which requires `git` in the Docker BuildKit worker — Container Station and Synology DSM don't ship git there, so the build fails immediately with `exec: "git": executable file not found`. Manual ZIP-as-local-context workaround tripped a QNAP filesystem quirk in the systemd post-install (`Failed to copy permissions from /etc/group`). Fallback to `ghcr.io/afkfelix/orca-slicer-api:latest-orca2.3.0` ran but couldn't slice — that image lacks the `bambuddy/profile-resolver` patches (the `inherits:` chain resolver, the `from: "User"` → `"system"` rewrite, the `# ` clone-prefix strip, and the sentinel-value strip), so `/profiles/bundled` returned 400 and `/slice` returned `Invalid parameter value(s) included in the 3mf file`. **The fix removes the build-from-source requirement entirely.** Both sidecar images are now built locally on Martin's box and pushed to two registries (`ghcr.io/maziggy/orca-slicer-api`, `docker.io/maziggy/orca-slicer-api`, and the same two for `bambu-studio-api`) via a new `docker-publish-sidecars.sh` helper in the `orca-slicer-api` repo; the stable Bambuddy publish script auto-invokes it after each release, and the beta script too. Daily-beta opts in only via `--include-sidecars` (slicer rebuilds are expensive). The helper has hard safety guards: aborts unless the orca-slicer-api repo is on `bambuddy/profile-resolver` AND the working tree is clean, and never executes `git checkout` / `pull` / `fetch` / `reset` itself. `slicer-api/docker-compose.yml` switches from `build:` to `image: ghcr.io/maziggy/orca-slicer-api:${SIDECAR_TAG:-latest}`. New `SIDECAR_TAG` env var in `.env.example` defaults to `latest`; set `SIDECAR_TAG=bambuddy-X.Y.Z` to pin to the sidecar image that shipped with a specific Bambuddy release. **Scope limitation**: both images are `linux/amd64` only. The OrcaSlicer multi-arch path stays on hold pending an upstream extraction fix — the kldzj/orca-slicer-arm64 AppImage's `--appimage-extract` silently fails under QEMU build emulation; the Dockerfile's `;`-chained RUN block masked the failure until the final `COPY squashfs-root` tripped. ARM64 hosts (Pi 4/5, Apple Silicon Linux) should run the sidecar on a separate x86_64 box and point Bambuddy at it via the **Sidecar URL** field — the sidecar doesn't need to live next to Bambuddy. **Docs aligned**: `slicer-api/README.md` and `wiki/features/slicer-api.md` rewrote the Quick start, Updating, and Sidecar source sections — `docker compose up -d` now pulls instead of building, and `docker compose pull && docker compose up -d` is the new update path (no `--no-cache --pull` dance because Compose only ever sees `image:` references). The build-from-source path stays documented as an advanced option under "Building from source (advanced)" for forks / dev work.
|
||||
|
||||
### Changed
|
||||
- **VP access code is now auto-derived from the target printer in non-proxy modes (Discord report)** — A user on Discord set up a Queue-mode VP with a different access code than the real target printer and couldn't get the slicer to connect, even after the cert-trust path was sorted. Root cause: the live target-printer mirror that landed earlier in the 0.2.5 cycle forwards the slicer's MQTT/RTSPS auth bytes through to the real printer — the slicer holds **one** code in its profile (the one it bound the VP with), and that code has to pass two checks (VP listener, then real printer). If the codes diverge the bridge silently fails at the second hop and the slicer abandons the connection (e.g. opens 8883, FINs before sending a ClientHello). The wiki *did* document a code-match requirement but framed it as a camera-only concern (`MQTT and FTP work either way; only the camera path needs the match`) — wrong, all bridged protocols inherit. **The fix removes the foot-gun rather than re-document it.** When a target printer is selected on a non-proxy VP (Archive / Review / Queue), the access-code field in the VP card switches to a read-only display showing the target's code with an Eye-toggle reveal, and the backend auto-inherits the value on every `create` / `update` (any explicit `access_code` submitted alongside a target is silently overridden — belt-and-braces for non-UI clients). When no target is set, the field stays editable as before. The same `inheritsAccessCodeFromTarget` predicate gates a small "Inherited from target" badge in place of the existing `isSet` / `notSet` status pill. Changing the target after the slicer has already bound triggers an info toast ("Access code now matches the new target — re-add this device in your slicer") because the slicer's stored code is now stale. **One-shot startup migration** in `core/database.py` corrects any pre-existing mismatched VPs on first boot after the upgrade: SELECTs the diverged rows for an INFO log per VP (`VP 'Workshop Queue' (id=3) access code synced from target printer 'X1C #2'` — audit trail for anyone digging through logs), then UPDATEs via correlated subquery (idempotent — the WHERE clause excludes already-synced rows, so re-running is a no-op; portable across SQLite and Postgres). No user-facing banner because there's no action for the user to take — the fix is done, and a previously-stuck bridge now works. **Wiki**: `features/virtual-printer.md` line 1189 flipped from the wrong MQTT/FTP-work-either-way claim to "the bridge forwards slicer auth bytes through; Bambuddy auto-derives so the codes can't diverge", the line-84 tip's "for camera" framing replaced with the broader rule, and the port-table row for RTSP `:322` annotated with "transparent passthrough to the real printer's `:322`, same end-to-end TLS as proxy mode" so the dedicated-bind-IP-vs-passthrough-to-printer apparent contradiction reads as one consistent model. **i18n**: 5 new keys (`accessCode.inheritedFromTarget`, `accessCode.derivedFromTargetHint`, `accessCode.reveal`, `accessCode.hide`, `toast.targetCodeChangedRebind`) translated in all 11 locales (de/en/es/fr/it/ja/ko/pt-BR/tr/zh-CN/zh-TW), no English fallbacks per the project's hard rule.
|
||||
|
||||
|
||||
@@ -43,11 +43,15 @@ NC='\033[0m' # No Color
|
||||
# Parse arguments
|
||||
VERSION=""
|
||||
PARALLEL=false
|
||||
SKIP_SIDECARS=false
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--parallel)
|
||||
PARALLEL=true
|
||||
;;
|
||||
--skip-sidecars)
|
||||
SKIP_SIDECARS=true
|
||||
;;
|
||||
*)
|
||||
if [ -z "$VERSION" ]; then
|
||||
VERSION="$arg"
|
||||
@@ -191,3 +195,23 @@ echo " docker pull ${GHCR_IMAGE}:${VERSION}"
|
||||
echo " docker pull ${GHCR_IMAGE}:beta"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Reminder: Set package to Private in GitHub → Packages → Settings${NC}"
|
||||
|
||||
# ============================================================
|
||||
# Sidecar images (orca-slicer-api + bambu-studio-api) — beta channel = GHCR private
|
||||
# ============================================================
|
||||
SIDECAR_SCRIPT="/opt/claude/projects/orca-slicer-api/docker-publish-sidecars.sh"
|
||||
if [ "$SKIP_SIDECARS" = true ]; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}Skipping sidecar images (--skip-sidecars).${NC}"
|
||||
elif [ ! -x "$SIDECAR_SCRIPT" ]; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}Sidecar helper not found at ${SIDECAR_SCRIPT} — skipping sidecar build.${NC}"
|
||||
else
|
||||
echo ""
|
||||
echo -e "${GREEN}================================================${NC}"
|
||||
echo -e "${GREEN} Publishing sidecar images (beta channel)${NC}"
|
||||
echo -e "${GREEN}================================================${NC}"
|
||||
SIDECAR_ARGS="--channel beta --version ${VERSION}"
|
||||
[ "$PARALLEL" = true ] && SIDECAR_ARGS="$SIDECAR_ARGS --parallel"
|
||||
"$SIDECAR_SCRIPT" $SIDECAR_ARGS
|
||||
fi
|
||||
|
||||
@@ -56,6 +56,7 @@ PARALLEL=false
|
||||
PUSH_GHCR=true
|
||||
PUSH_DOCKERHUB=true
|
||||
SKIP_RELEASE=false
|
||||
INCLUDE_SIDECARS=false
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--parallel)
|
||||
@@ -70,17 +71,22 @@ for arg in "$@"; do
|
||||
--skip-release)
|
||||
SKIP_RELEASE=true
|
||||
;;
|
||||
--include-sidecars)
|
||||
INCLUDE_SIDECARS=true
|
||||
;;
|
||||
--help|-h)
|
||||
echo "Usage: $0 [--parallel] [--ghcr-only] [--dockerhub-only] [--skip-release]"
|
||||
echo "Usage: $0 [--parallel] [--ghcr-only] [--dockerhub-only] [--skip-release] [--include-sidecars]"
|
||||
echo ""
|
||||
echo "Build and publish a daily beta Docker image using the APP_VERSION from config.py."
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --parallel Build both architectures simultaneously"
|
||||
echo " --ghcr-only Only push to GitHub Container Registry"
|
||||
echo " --dockerhub-only Only push to Docker Hub"
|
||||
echo " --skip-release Build+push without creating/updating GitHub release"
|
||||
echo " --help, -h Show this help"
|
||||
echo " --parallel Build both architectures simultaneously"
|
||||
echo " --ghcr-only Only push to GitHub Container Registry"
|
||||
echo " --dockerhub-only Only push to Docker Hub"
|
||||
echo " --skip-release Build+push without creating/updating GitHub release"
|
||||
echo " --include-sidecars Also rebuild + push orca-slicer-api and bambu-studio-api"
|
||||
echo " images (off by default — slicer rebuilds are expensive)"
|
||||
echo " --help, -h Show this help"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
@@ -419,3 +425,26 @@ if [ "$PUSH_DOCKERHUB" = true ]; then
|
||||
echo " docker pull ${DOCKERHUB_IMAGE}:daily"
|
||||
echo " docker pull ${IMAGE_NAME}:daily # shorthand"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# Sidecar images (orca-slicer-api + bambu-studio-api) — opt-in for daily
|
||||
# ============================================================
|
||||
SIDECAR_SCRIPT="/opt/claude/projects/orca-slicer-api/docker-publish-sidecars.sh"
|
||||
if [ "$INCLUDE_SIDECARS" != true ]; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}Sidecar images not rebuilt (daily default).${NC}"
|
||||
echo -e "${YELLOW}Pass --include-sidecars to also publish orca-slicer-api + bambu-studio-api.${NC}"
|
||||
elif [ ! -x "$SIDECAR_SCRIPT" ]; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}Sidecar helper not found at ${SIDECAR_SCRIPT} — skipping sidecar build.${NC}"
|
||||
else
|
||||
echo ""
|
||||
echo -e "${GREEN}================================================${NC}"
|
||||
echo -e "${GREEN} Publishing sidecar images (daily channel)${NC}"
|
||||
echo -e "${GREEN}================================================${NC}"
|
||||
SIDECAR_ARGS="--channel daily --version ${VERSION}"
|
||||
[ "$PARALLEL" = true ] && SIDECAR_ARGS="$SIDECAR_ARGS --parallel"
|
||||
[ "$PUSH_GHCR" = false ] && SIDECAR_ARGS="$SIDECAR_ARGS --dockerhub-only"
|
||||
[ "$PUSH_DOCKERHUB" = false ] && SIDECAR_ARGS="$SIDECAR_ARGS --ghcr-only"
|
||||
"$SIDECAR_SCRIPT" $SIDECAR_ARGS
|
||||
fi
|
||||
|
||||
@@ -49,6 +49,7 @@ VERSION=""
|
||||
PARALLEL=false
|
||||
PUSH_GHCR=true
|
||||
PUSH_DOCKERHUB=true
|
||||
SKIP_SIDECARS=false
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--parallel)
|
||||
@@ -60,6 +61,9 @@ for arg in "$@"; do
|
||||
--dockerhub-only)
|
||||
PUSH_GHCR=false
|
||||
;;
|
||||
--skip-sidecars)
|
||||
SKIP_SIDECARS=true
|
||||
;;
|
||||
*)
|
||||
if [ -z "$VERSION" ]; then
|
||||
VERSION="$arg"
|
||||
@@ -282,3 +286,25 @@ if [ "$PUSH_DOCKERHUB" = true ]; then
|
||||
echo " docker pull ${DOCKERHUB_IMAGE}:${VERSION}"
|
||||
echo " docker pull ${IMAGE_NAME}:${VERSION} # shorthand"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# Sidecar images (orca-slicer-api + bambu-studio-api)
|
||||
# ============================================================
|
||||
SIDECAR_SCRIPT="/opt/claude/projects/orca-slicer-api/docker-publish-sidecars.sh"
|
||||
if [ "$SKIP_SIDECARS" = true ]; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}Skipping sidecar images (--skip-sidecars).${NC}"
|
||||
elif [ ! -x "$SIDECAR_SCRIPT" ]; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}Sidecar helper not found at ${SIDECAR_SCRIPT} — skipping sidecar build.${NC}"
|
||||
else
|
||||
echo ""
|
||||
echo -e "${GREEN}================================================${NC}"
|
||||
echo -e "${GREEN} Publishing sidecar images (stable channel)${NC}"
|
||||
echo -e "${GREEN}================================================${NC}"
|
||||
SIDECAR_ARGS="--channel stable --version ${VERSION}"
|
||||
[ "$PARALLEL" = true ] && SIDECAR_ARGS="$SIDECAR_ARGS --parallel"
|
||||
[ "$PUSH_GHCR" = false ] && SIDECAR_ARGS="$SIDECAR_ARGS --dockerhub-only"
|
||||
[ "$PUSH_DOCKERHUB" = false ] && SIDECAR_ARGS="$SIDECAR_ARGS --ghcr-only"
|
||||
"$SIDECAR_SCRIPT" $SIDECAR_ARGS
|
||||
fi
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
ORCA_API_PORT=3003
|
||||
BAMBU_API_PORT=3001
|
||||
|
||||
# Slicer versions. Pinned for reproducibility — bump these when you want
|
||||
# a newer slicer and accept a fresh ~220 MB BambuStudio download.
|
||||
ORCA_VERSION=2.3.2
|
||||
BAMBU_VERSION=02.07.01.57
|
||||
# Sidecar image tag. Default is `latest` (current stable release).
|
||||
# Pinning options:
|
||||
# bambuddy-X.Y.Z pin to the sidecar image that shipped with Bambuddy X.Y.Z
|
||||
# (e.g. SIDECAR_TAG=bambuddy-0.2.5)
|
||||
# daily track the bambuddy:daily channel
|
||||
SIDECAR_TAG=latest
|
||||
|
||||
+35
-21
@@ -16,7 +16,7 @@ Enable the API path by:
|
||||
|
||||
```bash
|
||||
cd slicer-api/
|
||||
cp .env.example .env # edit ports / versions if you like
|
||||
cp .env.example .env # edit ports if you like
|
||||
|
||||
# OrcaSlicer only (default profile):
|
||||
docker compose up -d
|
||||
@@ -28,9 +28,15 @@ curl http://localhost:3001/health # bambu-studio-api
|
||||
curl http://localhost:3003/health # orca-slicer-api
|
||||
```
|
||||
|
||||
First build downloads the slicer's AppImage (~110 MB OrcaSlicer, ~220 MB
|
||||
BambuStudio) and compiles the Node wrapper. Takes 3–8 minutes per service.
|
||||
Subsequent runs reuse the local image — instant start.
|
||||
First start pulls pre-built images from GHCR (~110 MB OrcaSlicer,
|
||||
~220 MB BambuStudio). No local build, no git in the BuildKit worker,
|
||||
works on QNAP / Synology / Container Station out of the box.
|
||||
|
||||
Both images are `linux/amd64` only. OrcaSlicer's ARM64 build is on hold
|
||||
pending an upstream extraction fix; BambuStudio doesn't publish ARM64
|
||||
at all. For ARM64 hosts (Raspberry Pi 4/5, Apple Silicon Linux), run
|
||||
the sidecar on a separate x86_64 box and point Bambuddy at it via the
|
||||
**Sidecar URL** field — the sidecar doesn't need to live next to Bambuddy.
|
||||
|
||||
## Ports
|
||||
|
||||
@@ -55,32 +61,40 @@ In the Bambuddy UI: **Settings → Slicer**:
|
||||
Leaving the URL field blank uses the `SLICER_API_URL` /
|
||||
`BAMBU_STUDIO_API_URL` environment defaults from Bambuddy's config.
|
||||
|
||||
## Where the source lives
|
||||
## Where the images live
|
||||
|
||||
Both images build from the
|
||||
Pre-built images are published to two registries on every Bambuddy
|
||||
stable release:
|
||||
|
||||
- `ghcr.io/maziggy/orca-slicer-api:latest` / `docker.io/maziggy/orca-slicer-api:latest`
|
||||
- `ghcr.io/maziggy/bambu-studio-api:latest` / `docker.io/maziggy/bambu-studio-api:latest`
|
||||
|
||||
Each release also publishes a versioned tag (`:bambuddy-X.Y.Z`) so you
|
||||
can pin to the sidecar that shipped alongside a specific Bambuddy
|
||||
release — set `SIDECAR_TAG=bambuddy-0.2.5` in `.env`.
|
||||
|
||||
Both images are built from the
|
||||
[`maziggy/orca-slicer-api`](https://github.com/maziggy/orca-slicer-api)
|
||||
fork (`bambuddy/profile-resolver` branch). The Compose file uses
|
||||
Docker's git build context, so you don't need to clone it manually —
|
||||
Docker pulls the repo at build time.
|
||||
|
||||
The fork patches AFKFelix's upstream wrapper with the `inherits:`
|
||||
chain resolver, `from: "User"` → `"system"` rewrite, `# ` clone-prefix
|
||||
strip, and sentinel-value strip — all empirically required to slice
|
||||
real GUI exports without segfaulting the CLI. Once those land
|
||||
upstream, this Compose file can be flipped to pull from
|
||||
`ghcr.io/afkfelix/orca-slicer-api` directly.
|
||||
fork (`bambuddy/profile-resolver` branch). The fork patches AFKFelix's
|
||||
upstream wrapper with the `inherits:` chain resolver, `from: "User"`
|
||||
→ `"system"` rewrite, `# ` clone-prefix strip, and sentinel-value
|
||||
strip — all empirically required to slice real GUI exports without
|
||||
segfaulting the CLI. Once those land upstream, the compose file can be
|
||||
flipped back to `ghcr.io/afkfelix/orca-slicer-api`.
|
||||
|
||||
## Updating
|
||||
|
||||
Bump the versions in `.env`, then:
|
||||
|
||||
```bash
|
||||
docker compose --profile bambu build --no-cache
|
||||
docker compose pull
|
||||
docker compose --profile bambu up -d
|
||||
```
|
||||
|
||||
`--no-cache` is needed because the Dockerfile downloads the AppImage
|
||||
inline; Docker won't re-fetch it on a version change otherwise.
|
||||
That's it — Compose pulls the current `:latest` (or whatever
|
||||
`SIDECAR_TAG` you've pinned to) and recreates the containers.
|
||||
|
||||
To roll back to the sidecar that shipped with a previous Bambuddy
|
||||
release, set `SIDECAR_TAG=bambuddy-X.Y.Z` in `.env` and re-run the two
|
||||
commands above.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
||||
@@ -17,18 +17,17 @@
|
||||
# docker compose up -d # starts OrcaSlicer only
|
||||
# docker compose --profile bambu up -d # starts both
|
||||
#
|
||||
# First build pulls the source from the fork over git (~5 min — downloads
|
||||
# the BambuStudio AppImage, ~220 MB) and caches the image locally.
|
||||
# Subsequent runs reuse the cache. Pin the slicer versions via .env.
|
||||
# First start pulls pre-built images from GHCR (~110 MB OrcaSlicer,
|
||||
# ~220 MB BambuStudio). No local build, no git in the BuildKit worker,
|
||||
# works on QNAP / Synology / Container Station out of the box.
|
||||
#
|
||||
# Both images are linux/amd64 only. OrcaSlicer's ARM64 path is on hold
|
||||
# pending an upstream extraction fix; BambuStudio doesn't publish ARM64
|
||||
# at all.
|
||||
|
||||
services:
|
||||
orca-slicer-api:
|
||||
build:
|
||||
context: https://github.com/maziggy/orca-slicer-api.git#bambuddy/profile-resolver
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
ORCA_VERSION: "${ORCA_VERSION:-2.3.2}"
|
||||
image: bambuddy-orca-slicer-api:orca${ORCA_VERSION:-2.3.2}
|
||||
image: ghcr.io/maziggy/orca-slicer-api:${SIDECAR_TAG:-latest}
|
||||
container_name: orca-slicer-api
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
@@ -46,12 +45,7 @@ services:
|
||||
retries: 3
|
||||
|
||||
bambu-studio-api:
|
||||
build:
|
||||
context: https://github.com/maziggy/orca-slicer-api.git#bambuddy/profile-resolver
|
||||
dockerfile: Dockerfile.bambu-studio
|
||||
args:
|
||||
BAMBU_VERSION: "${BAMBU_VERSION:-02.07.01.57}"
|
||||
image: bambuddy-bambu-studio-api:bambu${BAMBU_VERSION:-02.07.01.57}
|
||||
image: ghcr.io/maziggy/bambu-studio-api:${SIDECAR_TAG:-latest}
|
||||
container_name: bambu-studio-api
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
|
||||
Reference in New Issue
Block a user