Skip to content

Commit

Permalink
added more code comments for docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Fabian committed Mar 27, 2020
1 parent a88a2fa commit edb3dbf
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 41 deletions.
32 changes: 14 additions & 18 deletions attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,17 @@ const (
sizeBoolean = int16(1)
)

// ipp attribute encoder
// encodes attribute to a io.Writer
// AttributeEncoder encodes attribute to a io.Writer
type AttributeEncoder struct {
writer io.Writer
}

// create a new attribute encoder from a writer
// NewAttributeEncoder returns a new encoder that writes to w
func NewAttributeEncoder(w io.Writer) *AttributeEncoder {
return &AttributeEncoder{w}
}

// encodes a attribute and its value to a io.Writer
// Encode encodes a attribute and its value to a io.Writer
// the tag is determined by the AttributeTagMapping map
func (e *AttributeEncoder) Encode(attribute string, value interface{}) error {
tag, ok := AttributeTagMapping[attribute]
Expand Down Expand Up @@ -343,27 +342,31 @@ func (e *AttributeEncoder) writeNullByte() error {
return binary.Write(e.writer, binary.BigEndian, int16(0))
}

// representation of a ipp attribute
// a attribute contains a tag, witch identifies the type, the name of the attribute a the value
// Attribute defines an ipp attribute
type Attribute struct {
Tag int8
Name string
Value interface{}
}

// ipp attribute decoder
// reads from a io.Reader an decode the data into an attribute struct
// Resolution defines the resolution attribute
type Resolution struct {
Height int
Width int
Depth int8
}

// AttributeDecoder reads and decodes ipp from an input stream
type AttributeDecoder struct {
reader io.Reader
}

// create a new attribute decoder from a reader
// NewAttributeDecoder returns a new decoder that reads from r
func NewAttributeDecoder(r io.Reader) *AttributeDecoder {
return &AttributeDecoder{r}
}

// reads from a io.Reader and decode the attribute
// the type is identified by a tag passed as an argument
// Decode reads the next ipp attribute into a attribute struct. the type is identified by a tag passed as an argument
func (d *AttributeDecoder) Decode(tag int8) (*Attribute, error) {
attr := Attribute{Tag: tag}

Expand Down Expand Up @@ -498,13 +501,6 @@ func (d *AttributeDecoder) decodeRange() ([]int, error) {
return r, nil
}

// represents the data of the resolution attribute
type Resolution struct {
Height int
Width int
Depth int8
}

func (d *AttributeDecoder) decodeResolution() (res Resolution, err error) {
_, err = d.readValueLength()
if err != nil {
Expand Down
20 changes: 20 additions & 0 deletions constants.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ipp

// ipp status codes
const (
StatusCupsInvalid int16 = -1
StatusOk int16 = 0x0000
Expand Down Expand Up @@ -66,6 +67,7 @@ const (
StatusErrorCupsUpgradeRequired int16 = 0x1002
)

// ipp operations
const (
OperationCupsInvalid int16 = -0x0001
OperationCupsNone int16 = 0x0000
Expand Down Expand Up @@ -186,6 +188,7 @@ const (
OperationCupsCreateLocalPrinter int16 = 0x4028
)

// ipp tags
const (
TagCupsInvalid int8 = -1
TagZero int8 = 0x00
Expand Down Expand Up @@ -230,6 +233,7 @@ const (
TagExtension int8 = 0x7f
)

// job states
const (
JobStatePending int8 = 0x03
JobStateHeld int8 = 0x04
Expand All @@ -240,6 +244,7 @@ const (
JobStateCompleted int8 = 0x09
)

// document states
const (
DocumentStatePending int8 = 0x03
DocumentStateProcessing int8 = 0x05
Expand All @@ -248,39 +253,50 @@ const (
DocumentStateCompleted int8 = 0x08
)

// printer states
const (
PrinterStateIdle int8 = 0x0003
PrinterStateProcessing int8 = 0x0004
PrinterStateStopped int8 = 0x0005
)

// job state filter
const (
JobStateFilterNotCompleted = "not-completed"
JobStateFilterCompleted = "completed"
JobStateFilterAll = "all"
)

// error policies
const (
ErrorPolicyRetryJob = "retry-job"
ErrorPolicyAbortJob = "abort-job"
ErrorPolicyRetryCurrentJob = "retry-current-job"
ErrorPolicyStopPrinter = "stop-printer"
)

// ipp defaults
const (
CharsetLanguage = "en-US"
Charset = "utf-8"
ProtocolVersionMajor = int8(2)
ProtocolVersionMinor = int8(0)

DefaultJobPriority = 50
)

// useful mime types for ipp
const (
MimeTypePostscript = "application/postscript"
MimeTypeOctetStream = "application/octet-stream"
)

// ipp content types
const (
ContentTypeIPP = "application/ipp"
)

// known ipp attributes
const (
AttributeCopies = "copies"
AttributeDocumentFormat = "document-format"
Expand Down Expand Up @@ -337,6 +353,7 @@ const (
AttributeJobOriginatingUserName = "job-originating-user-name"
)

// Default attributes
var (
DefaultClassAttributes = []string{AttributePrinterName, AttributeMemberNames}
DefaultPrinterAttributes = []string{AttributePrinterName, AttributePrinterType, AttributePrinterLocation, AttributePrinterInfo,
Expand All @@ -345,7 +362,10 @@ var (
DefaultJobAttributes = []string{AttributeJobID, AttributeJobName, AttributePrinterURI, AttributeJobState, AttributeJobStateReason,
AttributeJobHoldUntil, AttributeJobMediaProgress, AttributeJobKilobyteOctets, AttributeNumberOfDocuments, AttributeCopies,
AttributeJobOriginatingUserName}
)

// Attribute to tag mapping
var (
AttributeTagMapping = map[string]int8{
AttributeCharset: TagCharset,
AttributeNaturalLanguage: TagLanguage,
Expand Down
6 changes: 3 additions & 3 deletions error.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package ipp

import "fmt"

// check a given error whether a printer or class does not exist
// IsNotExistsError checks a given error whether a printer or class does not exist
func IsNotExistsError(err error) bool {
if err == nil {
return false
Expand All @@ -11,7 +11,7 @@ func IsNotExistsError(err error) bool {
return err.Error() == "The printer or class does not exist."
}

//non ok ipp status codes
// IPPError used for non ok ipp status codes
type IPPError struct {
Status int16
Message string
Expand All @@ -21,7 +21,7 @@ func (e IPPError) Error() string {
return fmt.Sprintf("ipp status: %d, message: %s", e.Status, e.Message)
}

// non 200 http codes
// HTTPError used for non 200 http codes
type HTTPError struct {
Code int
}
Expand Down
36 changes: 18 additions & 18 deletions ipp-client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ import (
"strconv"
)

// Document wraps an io.Reader with more information, needed for encoding
type Document struct {
Document io.Reader
Size int
Name string
MimeType string
}

// IPPClient implements a generic ipp client
type IPPClient struct {
host string
port int
Expand All @@ -30,6 +32,7 @@ type IPPClient struct {
client *http.Client
}

// NewIPPClient creates a new generic ipp client
func NewIPPClient(host string, port int, username, password string, useTLS bool) *IPPClient {
httpClient := http.Client{
Transport: &http.Transport{
Expand Down Expand Up @@ -73,6 +76,7 @@ func (c *IPPClient) getClassUri(printer string) string {
return fmt.Sprintf("ipp://localhost/classes/%s", printer)
}

// SendRequest sends a request to a remote uri end returns the response
func (c *IPPClient) SendRequest(url string, req *Request, additionalResponseData io.Writer) (*Response, error) {
payload, err := req.Encode()
if err != nil {
Expand Down Expand Up @@ -123,7 +127,7 @@ func (c *IPPClient) SendRequest(url string, req *Request, additionalResponseData
return resp, err
}

// Print one or more `Document`s using IPP `Create-Job` followed by `Send-Document` request(s).
// PrintDocuments prints one or more documents using a Create-Job operation followed by one or more Send-Document operation(s). custom job settings can be specified via the jobAttributes parameter
func (c *IPPClient) PrintDocuments(docs []Document, printer string, jobAttributes map[string]interface{}) (int, error) {
printerURI := c.getPrinterUri(printer)

Expand Down Expand Up @@ -173,23 +177,7 @@ func (c *IPPClient) PrintDocuments(docs []Document, printer string, jobAttribute
return jobID, nil
}

// Print a `Document` using an IPP `Print-Job` request.
//
// `jobAttributes` can contain arbitrary key/value pairs to control the way in which the
// document is printed. [RFC 2911 § 4.2](https://tools.ietf.org/html/rfc2911#section-4.2)
// defines some useful attributes:
//
// * [`job-priority`](https://tools.ietf.org/html/rfc2911#section-4.2.1): an integer between 1-100
// * [`copies`](https://tools.ietf.org/html/rfc2911#section-4.2.5): a positive integer
// * [`finishings`](https://tools.ietf.org/html/rfc2911#section-4.2.6): an enumeration
// * [`number-up`](https://tools.ietf.org/html/rfc2911#section-4.2.9): a positive integer
// * [`orientation-requested`](https://tools.ietf.org/html/rfc2911#section-4.2.10): an enumeration
// * [`media`](https://tools.ietf.org/html/rfc2911#section-4.2.11): a string
// * [`printer-resolution`](https://tools.ietf.org/html/rfc2911#section-4.2.12): a `Resolution`
// * [`print-quality`](https://tools.ietf.org/html/rfc2911#section-4.2.13): an enumeration
//
// Your print system may provide other attributes. Define custom attributes as needed in
// `AttributeTagMapping` and provide values here.
// PrintJob prints a document using a Print-Job operation. custom job settings can be specified via the jobAttributes parameter
func (c *IPPClient) PrintJob(doc Document, printer string, jobAttributes map[string]interface{}) (int, error) {
printerURI := c.getPrinterUri(printer)

Expand Down Expand Up @@ -224,6 +212,7 @@ func (c *IPPClient) PrintJob(doc Document, printer string, jobAttributes map[str
return jobID, nil
}

// PrintFile prints a local file on the file system. custom job settings can be specified via the jobAttributes parameter
func (c *IPPClient) PrintFile(filePath, printer string, jobAttributes map[string]interface{}) (int, error) {
fileStats, err := os.Stat(filePath)
if os.IsNotExist(err) {
Expand All @@ -250,6 +239,7 @@ func (c *IPPClient) PrintFile(filePath, printer string, jobAttributes map[string
}, printer, jobAttributes)
}

// GetPrinterAttributes returns the requested attributes for the specified printer, if attributes is nil the default attributes will be used
func (c *IPPClient) GetPrinterAttributes(printer string, attributes []string) (Attributes, error) {
req := NewRequest(OperationGetPrinterAttributes, 1)
req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
Expand All @@ -273,6 +263,7 @@ func (c *IPPClient) GetPrinterAttributes(printer string, attributes []string) (A
return resp.PrinterAttributes[0], nil
}

// ResumePrinter resumes a printer
func (c *IPPClient) ResumePrinter(printer string) error {
req := NewRequest(OperationResumePrinter, 1)
req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
Expand All @@ -281,6 +272,7 @@ func (c *IPPClient) ResumePrinter(printer string) error {
return err
}

// PausePrinter pauses a printer
func (c *IPPClient) PausePrinter(printer string) error {
req := NewRequest(OperationPausePrinter, 1)
req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
Expand All @@ -289,6 +281,7 @@ func (c *IPPClient) PausePrinter(printer string) error {
return err
}

// GetJobAttributes returns the requested attributes for the specified job, if attributes is nil the default job will be used
func (c *IPPClient) GetJobAttributes(jobID int, attributes []string) (Attributes, error) {
req := NewRequest(OperationGetJobAttributes, 1)
req.OperationAttributes[AttributeJobURI] = c.getJobUri(jobID)
Expand All @@ -311,6 +304,7 @@ func (c *IPPClient) GetJobAttributes(jobID int, attributes []string) (Attributes
return resp.PrinterAttributes[0], nil
}

// GetJobs returns jobs from a printer or class
func (c *IPPClient) GetJobs(printer, class string, whichJobs string, myJobs bool, firstJobId, limit int, attributes []string) (map[int]Attributes, error) {
req := NewRequest(OperationGetJobs, 1)
req.OperationAttributes[AttributeWhichJobs] = string(whichJobs)
Expand Down Expand Up @@ -356,6 +350,7 @@ func (c *IPPClient) GetJobs(printer, class string, whichJobs string, myJobs bool
return jobIDMap, nil
}

// CancelJob cancels a job. if purge is true, the job will also be removed
func (c *IPPClient) CancelJob(jobID int, purge bool) error {
req := NewRequest(OperationCancelJob, 1)
req.OperationAttributes[AttributeJobURI] = c.getJobUri(jobID)
Expand All @@ -365,6 +360,7 @@ func (c *IPPClient) CancelJob(jobID int, purge bool) error {
return err
}

// CancelJob cancels all jobs for a specified printer. if purge is true, the jobs will also be removed
func (c *IPPClient) CancelAllJob(printer string, purge bool) error {
req := NewRequest(OperationCancelJobs, 1)
req.OperationAttributes[AttributePrinterURI] = c.getPrinterUri(printer)
Expand All @@ -374,6 +370,7 @@ func (c *IPPClient) CancelAllJob(printer string, purge bool) error {
return err
}

// RestartJob restarts a job
func (c *IPPClient) RestartJob(jobID int) error {
req := NewRequest(OperationRestartJob, 1)
req.OperationAttributes[AttributeJobURI] = c.getJobUri(jobID)
Expand All @@ -382,6 +379,7 @@ func (c *IPPClient) RestartJob(jobID int) error {
return err
}

// RestartJob holds a job
func (c *IPPClient) HoldJobUntil(jobID int, holdUntil string) error {
req := NewRequest(OperationRestartJob, 1)
req.OperationAttributes[AttributeJobURI] = c.getJobUri(jobID)
Expand All @@ -391,6 +389,7 @@ func (c *IPPClient) HoldJobUntil(jobID int, holdUntil string) error {
return err
}

// PrintTestPage prints a test page of type application/vnd.cups-pdf-banner
func (c *IPPClient) PrintTestPage(printer string) (int, error) {
testPage := new(bytes.Buffer)
testPage.WriteString("#PDF-BANNER\n")
Expand All @@ -411,6 +410,7 @@ func (c *IPPClient) PrintTestPage(printer string) (int, error) {
})
}

// TestConnection tests if a tcp connection to the remote server is possible
func (c *IPPClient) TestConnection() error {
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", c.host, c.port))
if err != nil {
Expand Down
Loading

0 comments on commit edb3dbf

Please sign in to comment.