Skip to content

Fix truncated upload of size-changed (SMFix) G-code — Content-Length mismatch - #35

Open
VGottselig wants to merge 1 commit into
macdylan:masterfrom
VGottselig:fix-fixed-gcode-filesize
Open

Fix truncated upload of size-changed (SMFix) G-code — Content-Length mismatch#35
VGottselig wants to merge 1 commit into
macdylan:masterfrom
VGottselig:fix-fixed-gcode-filesize

Conversation

@VGottselig

Copy link
Copy Markdown

Problem

When SMFix post-processing changes a G-code file's size and no fixed file was pre-saved to disk (the default — no -o / OutputDir), HTTPConnector.Upload streams the fixed content but announces the original (pre-fix) size as the multipart FileSize / Content-Length.

req.FileUpload.FileSize is read when the struct is built, but StreamContent only updates payload.Size asynchronously, inside its pipe goroutine (connector.go):

pr, pw := io.Pipe()
go func() {
    cont, err := postProcess(p.File)
    ...
    p.Size = int64(len(cont)) // too late — FileSize was already captured
    pw.Write(cont)
    pw.Close()
}()
return pr, nil

So the request advertises the wrong length. The Snapmaker receives a size-mismatched multipart body, silently discards it (the HTTP call still returns OK to sm2uploader) and keeps the previously loaded job — a following print start then prints the old file. The effect scales with size; large fixed uploads are hit hardest (progress stalls near ~99–100 %, printer keeps the previous file, no error surfaced).

Fix

For the post-processed-without-FixedFile path, materialize the fixed content up front via GetContent and set FileSize to its exact length.

Non-fixed uploads and OutputDir / FixedFile uploads keep streaming unchanged — their payload.Size is already correct before Upload runs, so no behavior change there. The pipe path already buffered the whole fixed file in memory (postProcess returns a full []byte), so there is no added memory cost for the fixed path either.

Testing

  • go build ./... clean.
  • 65+ MB OrcaSlicer uploads now land on the printer and start the correct file (previously the printer silently kept the prior job).

When SMFix post-processing changes a G-Code file's size and no fixed file
was pre-saved to disk (the default -- no -o/OutputDir), Upload() streamed
the fixed content but announced the *original*, pre-fix size as the
multipart FileSize/Content-Length: StreamContent only updates payload.Size
asynchronously inside its pipe goroutine, whereas req.FileUpload.FileSize
is read when the struct is built.

The printer then received a size-mismatched multipart body, silently
discarded it (HTTP still returned OK to sm2uploader) and kept the
previously loaded job -- so a following start printed the *old* file. The
effect scaled with size; large fixed uploads were hit the hardest.

Fix: for the post-processed-without-FixedFile path, materialize the fixed
content up front via GetContent and set FileSize to its exact length.
Non-fixed uploads and OutputDir/FixedFile uploads keep streaming unchanged
(their payload.Size is already correct).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018zWUoJhzouLTnkrpZE7rkJ
VGottselig added a commit to VGottselig/sm2uploader that referenced this pull request Jul 30, 2026
The README still only described upstream, so nothing in this fork was
documented: the web GUI, starting prints after upload, the token that
survives restarts, and the Spoolman filament bookings.

Everything upstream wrote stays as it was; the fork material sits below a
divider, with a pointer at the top so a visitor knows which repo they are
in and which two changes go upstream (macdylan#35, macdylan#36).

Documents the parts that are easy to get wrong when using it: bookings are
deltas so a correction is not a double booking, remaining weight is
computed instead of read because Spoolman clamps it at 0, and uploads.yaml
is the only record of what was booked -- deleting it orphans bookings
Spoolman still holds. Flags are tabled with their env fallbacks, plus the
compose snippet, because the container needs to share a network with
Spoolman before the hostname resolves.

Claims were checked against the code (poll intervals, row limits, net
weight, tail windows, make targets). The G-code section says what was
actually verified -- Snapmaker Orca 2.3.4 -- rather than implying
PrusaSlicer was tested too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QHt1eWHFiSbJaNjKVhU38N
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant