Skip to content

phase-1: document capture hook complete#68

Open
ArmxG wants to merge 2 commits into
OpenPrinting:masterfrom
ArmxG:master
Open

phase-1: document capture hook complete#68
ArmxG wants to merge 2 commits into
OpenPrinting:masterfrom
ArmxG:master

Conversation

@ArmxG

@ArmxG ArmxG commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

I have completed phase 1 work of GSoC with this PR. Earlier, when the virtual printer received a document via Send-Document, it simply threw away the bytes : io.Copy(io.Discard, rq.Body).

There was no way to get those bytes out of the printer, which made it impossible to build an automated testing pipeline. So I fixed that with this pr by:-

  1. Created proto/ipp/capture.go
    The Printer had no way to hand documents to the outside world. So I created a new file with:
    i DocumentReceiver :- a function type that anyone can implement to receive documents.
    ii SetDocumentReceiver() :- a method to install the callback on the printer.
    iii receiver field added to the Printer struct.

2.Fixed proto/ipp/printer.go
Replaced the stub in handleSendDocument:
i. io.Copy(io.Discard, rq.Body) :- io.ReadAll to actually read the bytes.
ii. Added the DocumentReceiver callback invocation after reading.

3.Added tests in proto/ipp/capture_test.go
Three tests to verify the capture hook works correctly:
i. TestDocumentReceiverCalled :- sends a document and verifies the receiver gets the correct job ID, format and exact bytes.
ii. TestDocumentReceiverNilNoPanic :- verifies no crash when receiver is nil.
iii. TestDocumentReceiverLargeDoc :- sends a 1MB document and verifies every single byte arrives correctly.

  1. Bugs found and fixed while writing tests
    i. In proto/ipp/createjob.go, senddocument.go, validatejob.go Job attributes were read from msg.Printer but the encoder stores them in msg.Job. This caused JobID to always decode as 0, making every Send-Document silently fail with "job not found".So fixed it by reading from msg.Job in all three files (createjob.go, senddocument.go and validatejob.go.)

ii. In proto/ipp/server.go trace. OnResponse was called before query.WriteHeader, so DumpResponse read a status of 0 and panicked with invalid WriteHeader code 0. Fixed by moving trace.OnResponse to after query.WriteHeader.

@alexpevzner

Copy link
Copy Markdown
Member

Hi!

I think, document completion hook should be common for proto/ipp and proto/ieee1284

So looks it should be an interface, similar to abstract.Scanner, and should be defined in the abstract package. Logically, this is the printing backend, which received and handles documents to be printed at the protocol-independent manner (like abstract.Scanner does the similar work for scanning)

Obviously, document completion hook needs not only the document body, but negotiated parameters as well

I would also prefer to avoid prefetching the entire document into the large buffer and prefer some streaming interface

P.S. My access to Telegram temporary doesn't work (I think I will be able to recover it within 1-2 days), so lets temporary communicate here

@ArmxG

ArmxG commented Jun 5, 2026 via email

Copy link
Copy Markdown
Contributor Author

Replace DocumentReceiver function type with PrintBackend interface in
abstract package, shared by both proto/ipp and proto/ieee1284.

- abstract/printer.go: new PrintBackend interface + PrintJobParams struct
- proto/ipp: SetPrintBackend(), streaming rq.Body, builds PrintJobParams
- proto/ieee1284: MIME() on DocFormat, emitDocument calls PrintBackend
- all tests updated to use testBackend implementing PrintBackend
@ArmxG

ArmxG commented Jun 7, 2026

Copy link
Copy Markdown
Contributor Author

Hey Alex.
I have implemented all the changes that you requested:

1.I created a new abstract/printer.go file with the PrintBackend interface and PrintJobParams struct, similar to how abstract.Scanner works on the scanning side. This way both proto/ipp and proto/ieee1284 share the same common interface.

2.For the IPP side, I updated it to pass rq.Body directly as a stream so there is no large buffer or io.ReadAll anymore.

3..For the IEEE1284 side, it still needs to buffer internally because the protocol requires scanning the byte stream to detect document boundaries (UEL markers, Ctrl-D). Once the document is complete, it wraps the buffer in bytes.NewReader and passes it to the backend.

@ArmxG

ArmxG commented Jun 7, 2026 via email

Copy link
Copy Markdown
Contributor Author

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.

2 participants