discovery

package
v0.0.0-...-b3d1fce Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 12, 2026 License: BSD-2-Clause Imports: 14 Imported by: 0

README

Device discovery

import "github.com/OpenPrinting/go-mfp/discovery"

This package provides device discovery for printers and scanners.

Documentation

Index

Constants

View Source
const (
	// Warm-up after the cold start.
	WarmUpTime = 5 * time.Second

	// Warm-up time after refresh.
	RefreshTime = 5 * time.Second

	// Stabilization time after discovery of new data.
	StabilizationTime = 1 * time.Second

	// Fast and not so reliable discovery for interactive purposes,
	// like discovery-based command-line auto completion.
	FastDiscoveryTime = 2500 * time.Millisecond
)

Discovery parameters:

View Source
const (
	// Normally, discovery system warms up cache after initialization
	// or refresh command, and then keeps cache up to date.
	//
	// In this mode, if cache is not yet warmed up, discovery system
	// will wait until it happens. Otherwise, it will return cached
	// data immediately.
	ModeNormal = iota

	// Due to the nature of most discovery protocols, when a new device
	// joins the network, the information describing the device arrives
	// in parts, and these parts do not necessarily arrive at the same
	// time.
	//
	// For example, the IPv6 address of a device may be discovered
	// significantly later than its IPv4 address.
	//
	// As a result, newly discovered (or changed) devices may remain in
	// an "incomplete" state for some time.
	//
	// In the ModeNormal mode, the discovery system will not wait for
	// these incomplete devices to stabilize and will simply return
	// the previous stable state in the output. In the ModeWaitIncomplete
	// mode, if incomplete devices exist in the cache, the discovery
	// system will wait for a period, allowing them the opportunity
	// to stabilize.
	ModeWaitIncomplete

	// ModeSnapshot returns content of discovery cache immediately
	// and doesn't wait for cache warm-up.
	ModeSnapshot
)

Mode values

View Source
const (
	ScanOther  = 1 << iota // Other input
	ScanPlaten             // Platen source
	ScanADF                // Automatic Document Feeder
)

ScanSource bits:

Variables

This section is empty.

Functions

This section is empty.

Types

type AuthMode

type AuthMode int

AuthMode defines the type of authentication information, required by printer or scanner

const (
	AuthNone        AuthMode = 1 << iota // No authentication
	AuthCertificate                      // TLS certificate
	AuthKerberos                         // Kerberos (RFC4559)
	AuthOAuth2                           // OAuth 2.0 (RFC6749)
	AuthPasswd                           // User name+password
	AuthOther                            // Other (unknown) mode
)

AuthMode values:

func (AuthMode) String

func (auth AuthMode) String() string

String formats AuthMode as string, for printing and logging

type Backend

type Backend interface {
	// Name returns backend name.
	Name() string

	// Start starts Backend operations.
	Start(*Eventqueue)

	// Close closes the Backend and releases resources it holds.
	Close()
}

Backend scans/monitors its search [Realm] and reports discovered devices by sending series of Event into the provided Eventqueue.

The following model of operation is assumed:

  • The search realm, where Backend operates (local network, for example) contains some connected devices.
  • Each device contains one or more units, and each unit may be either print unit or scan unit
  • Device may expose multiple interfaces to the same physical unit. For example, printer may support multiple protocols (say, IPP and LPD). Different interfaces to the same physical unit needs to be reported as different units.
  • Even the same interface may be visible to Backend as one or more distinct units. For example, the same printer may be visible via WiFi and via the Ethernet connection. This is up to Backend, either to merge these "virtual units" together, by reporting them as a single unit with combined endpoints, or report them separately. At the later case, Backend should use UnitID.SubRealm to distinguish between these virtual units.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client implements a client side of devices discovery.

func NewClient

func NewClient(ctx context.Context) *Client

NewClient creates a new discovery Client.

The provided context.Context is used for two purposes:

  • For logging
  • Client will terminate its operations, if context is canceled.

func NewClientTm

func NewClientTm(ctx context.Context,
	warmUpTime, stabilizationTime time.Duration) *Client

NewClientTm creates a new discovery Client with the warm-up time and stabilization time explicitly set.

This interface is primary intended for testing but exported due to its general usability in some cases.

Think carefully when choosing the time intervals, or use the simplified NewClient if not sure.

func (*Client) AddBackend

func (clnt *Client) AddBackend(bk Backend)

AddBackend adds a discovery Backend to the Client.

func (*Client) Close

func (clnt *Client) Close()

Close closes all attached backends and then closes the Client and releases all resources it holds.

func (*Client) GetDevices

func (clnt *Client) GetDevices(ctx context.Context, m Mode) ([]Device, error)

GetDevices returns a list of discovered devices.

Depending on Mode parameter and present discovery state, it may wait for some time or return immediately.

If GetDevices decides to wait, expiration of either Context, given to this function as argument, or Context, using as NewClient argument during the Client creation will cause this function to return immediately with the appropriate error. And this is the only case when error is returned.

func (*Client) Refresh

func (clnt *Client) Refresh()

Refresh causes Client to forcibly refresh its vision of discovered devices.

The Refresh call returns immediately, but the subsequent call to the Client.GetDevices may wait until refresh completion, depending on mode.

type Device

type Device struct {
	// Device metadata
	MakeModel      string    // Device make and model
	Location       string    // E.g., "2nd Floor Computer Lab"
	DNSSDName      string    // DNS-SD name, "" if none
	DNSSDUUID      uuid.UUID // DNS-SD UUID, uuid.NilUUID if n/a
	PrintAdminURL  string    // Admin URL for printer
	ScanAdminURL   string    // Admin URL for scanner
	FaxoutAdminURL string    // Admin URL for faxout
	IconURL        string    // Device icon URL

	// PPDManufacturer and PPDModel are matched against Manufacturer
	// and Model parameters in the PPD file when searching for the
	// appropriate driver for the legacy printer.
	//
	// Please notice, it is not necessary true that MakeModel
	// is the exact concatenation of these two strings.
	PPDManufacturer string // Manufacturer name
	PPDModel        string // Model name

	// USBSerial may be available for the ipp-usb devices too.
	USBSerial string // USB serial number, "" if n/a
	USBHWID   string // USB hardware ID, "" if n/a

	// Connectivity
	Addrs []netip.Addr // Device's IP addresses

	// Device units
	PrintUnits  []PrintUnit  // Print units
	ScanUnits   []ScanUnit   // Scan units
	FaxoutUnits []FaxoutUnit // Faxout units
}

Device consist of the multiple functional units. There are three types of units:

Multiple units of each type may exist, and depending on the device, they may have different parameters.

Each unit has its unique UnitID, the combination of parameters, that uniquely identifies the unit.

type Event

type Event interface {
	// Name returns the Event name.
	Name() string

	// GetID returns UnitID this Event related to.
	GetID() UnitID
}

Event is the common interface for all events

type EventAddEndpoint

type EventAddEndpoint struct {
	ID       UnitID // Unit identity
	Endpoint string // URLs of added endpoints
}

EventAddEndpoint is generated to report each discovered endpoint.

Backend responsibilities:

  • Unit MUST exist
  • The same endpoint MUST NOT be added multiple times.

func (*EventAddEndpoint) GetID

func (evnt *EventAddEndpoint) GetID() UnitID

GetID returns the UnitID this event related to.

func (*EventAddEndpoint) Name

func (*EventAddEndpoint) Name() string

Name returns the Event name.

type EventAddUnit

type EventAddUnit struct {
	ID UnitID // Unit identity
}

EventAddUnit generated when new print or scan unit is discovered.

Note, if printer has multiple print queues, each queue must be announced as a separate unit with the separate ID. Backend may use UnitID.SubRealm to make IDs of these unit distinguishable.

func (*EventAddUnit) GetID

func (evnt *EventAddUnit) GetID() UnitID

GetID returns the UnitID this event related to.

func (*EventAddUnit) Name

func (*EventAddUnit) Name() string

Name returns the Event name.

type EventDelEndpoint

type EventDelEndpoint struct {
	ID       UnitID // Unit identity
	Endpoint string // URLs of removed endpoints
}

EventDelEndpoint is generated, when some of the previously reported endpoints is not longer available.

Backend responsibilities:

  • Unit MUST exist
  • The removed endpoints MUST exist.

func (*EventDelEndpoint) GetID

func (evnt *EventDelEndpoint) GetID() UnitID

GetID returns the UnitID this event related to.

func (*EventDelEndpoint) Name

func (*EventDelEndpoint) Name() string

Name returns the Event name.

type EventDelUnit

type EventDelUnit struct {
	ID UnitID // Unit identity
}

EventDelUnit generated when previously announced unit is not longer available.

func (*EventDelUnit) GetID

func (evnt *EventDelUnit) GetID() UnitID

GetID returns the UnitID this event related to.

func (*EventDelUnit) Name

func (*EventDelUnit) Name() string

Name returns the Event name.

type EventFaxoutParameters

type EventFaxoutParameters struct {
	ID              UnitID            // Unit identity
	MakeModel       string            // Manufacturer + Model
	Location        string            // E.g., E.g., "2nd Floor Lab"
	AdminURL        string            // Device administration URL
	IconURL         string            // Device icon URL
	PPDManufacturer string            // I.e., "Hewlett Packard" or "Canon"
	PPDModel        string            // Model name
	Faxout          PrinterParameters // Faxout parameters (the same as printer)
}

EventFaxoutParameters generated when faxout parameters become available or updated.

Backend responsibilities:

  • Unit MUST exist

func (*EventFaxoutParameters) GetID

func (evnt *EventFaxoutParameters) GetID() UnitID

GetID returns the UnitID this event related to.

func (*EventFaxoutParameters) Name

func (*EventFaxoutParameters) Name() string

Name returns the Event name.

type EventPrinterParameters

type EventPrinterParameters struct {
	ID              UnitID            // Unit identity
	MakeModel       string            // Manufacturer + Model
	Location        string            // E.g., E.g., "2nd Floor Lab"
	AdminURL        string            // Device administration URL
	IconURL         string            // Device icon URL
	PPDManufacturer string            // I.e., "Hewlett Packard" or "Canon"
	PPDModel        string            // Model name
	Printer         PrinterParameters // Printer parameters
}

EventPrinterParameters generated when printer parameters becomes available or updated.

Backend responsibilities:

  • Unit MUST exist (i.e., previously announced with the EventAddUnit event and not revoked with the EventDelUnit event)

func (*EventPrinterParameters) GetID

func (evnt *EventPrinterParameters) GetID() UnitID

GetID returns the UnitID this event related to.

func (*EventPrinterParameters) Name

Name returns the Event name.

type EventScannerParameters

type EventScannerParameters struct {
	ID        UnitID            // Unit identity
	MakeModel string            // Manufacturer + Model
	Location  string            // E.g., E.g., "2nd Floor Lab"
	AdminURL  string            // Device administration URL
	IconURL   string            // Device icon URL
	Scanner   ScannerParameters // Scanner parameters
}

EventScannerParameters generated when scanner parameters become available or updated.

Backend responsibilities:

  • Unit MUST exist

func (*EventScannerParameters) GetID

func (evnt *EventScannerParameters) GetID() UnitID

GetID returns the UnitID this event related to.

func (*EventScannerParameters) Name

Name returns the Event name.

type Eventqueue

type Eventqueue struct {
	// contains filtered or unexported fields
}

Eventqueue represents a queue of Event.

Backend communicates with discovery system by pushing events into the queue. The queue is created and owned by the discovery system and passed as parameter to the Backend constructor when Backend is being created.

See description of each particular Event for Backend's responsibility when generating this kind of Event.

func NewEventqueue

func NewEventqueue() *Eventqueue

NewEventqueue creates the new Eventqueue

func (*Eventqueue) Count

func (q *Eventqueue) Count() int

Count returns the current queue length.

func (*Eventqueue) Push

func (q *Eventqueue) Push(e Event)

Push pushes event into the queue.

type FaxoutUnit

type FaxoutUnit struct {
	Proto     ServiceProto      // Faxing protocol
	Params    PrinterParameters // Printer parameters
	Endpoints []string          // URLs of printer endpoints
}

FaxoutUnit represents a fax unit.

type MediaKind

type MediaKind int

MediaKind bits lists the categories of printing supported by the printer.

const (
	MediaOther       MediaKind = 1 << iota // Other kind
	MediaDisk                              // Prints on CD/DVD
	MediaDocument                          // Standard document printing
	MediaEnvelope                          // Prints on envelopes
	MediaLabel                             // Prints on cut labels
	MediaLargeFormat                       // Large format (>A3)
	MediaPhoto                             // Photo printer
	MediaPostcard                          // Prints on postcards
	MediaReceipt                           // Continuous rolls of receipts
	MediaRoll                              // Rolls of docs/photos
)

MediaKind values:

func (MediaKind) String

func (media MediaKind) String() string

String converts MediaKind to string.

type Mode

type Mode int

Mode represents discovery mode.

It mostly affects discovery system behavior when searching for network devices using some kind of multicast-based device discovery protocol (i.e., DNS-SD, WSD and so on).

type PaperSize

type PaperSize int

PaperSize roughly defines the maximum paper size supported by printer

const (
	PaperUnknown PaperSize = iota // Paper size is not known
	PaperA4Minus                  // Smaller that A4
	PaperA4                       // A4 (US Legal)
	PaperA3                       // A3 (IS Tabloid)
	PaperA2                       // A2 (ISO-C)
	PaperA2Plus                   // Large that A2
)

PaperSize values:

func (PaperSize) String

func (pps PaperSize) String() string

String converts PaperSize to string.

type PrintUnit

type PrintUnit struct {
	Proto     ServiceProto      // Printing protocol
	Params    PrinterParameters // Printer parameters
	Endpoints []string          // URLs of printer endpoints
}

PrintUnit represents a print unit.

type PrinterParameters

type PrinterParameters struct {
	// Printer description
	Auth  AuthMode  // Required authentication type
	Paper PaperSize // Max paper size
	Media MediaKind // Kind of output media

	// Printer capabilities
	Bind    optional.Val[bool] // Printer can bind output
	Collate optional.Val[bool] // Printer can collate copies
	Color   optional.Val[bool] // Printer can print in color
	Copies  optional.Val[bool] // Printer can make copies in hardware
	Duplex  optional.Val[bool] // Printer supports duplex printing
	Punch   optional.Val[bool] // Printer can punch output
	Sort    optional.Val[bool] // Printer can sort output
	Staple  optional.Val[bool] // Printer can staple output

	// Operational parameters
	PSProduct string   // PS Product name (helps PPD location)
	PDL       []string // Supported MIME types
	Queue     string   // Queue name
	Priority  int      // Queue priority, 0(highest)...99(lowest)
}

PrinterParameters represents the discoverable information about the printer.

It is defined in the IPP.Everywhere and Apple Bounjour Printing terms, but usable with other discovery protocols.

func (PrinterParameters) Flags

func (p PrinterParameters) Flags() string

Flags formats printer flags (Bind, Color, Collate etc) into a single string ("bind,color,collate,...").

type ScanSource

type ScanSource int

ScanSource defines input sources, supported by scanner

func (ScanSource) String

func (ss ScanSource) String() string

String formats ScanSource as string, for printing and logging

type ScanUnit

type ScanUnit struct {
	Proto     ServiceProto      // Scanning protocol
	Params    ScannerParameters // Scanner parameters
	Endpoints []string          // URLs of printer endpoints
}

ScanUnit represents a scan unit.

type ScannerParameters

type ScannerParameters struct {
	// Scanner capabilities
	Duplex  optional.Val[bool]                 // Duplex mode supported
	Sources ScanSource                         // Supported sources
	Colors  generic.Bitset[abstract.ColorMode] // Supported color modes
	PDL     []string                           // Supported MIME types
}

ScannerParameters represents the discoverable information about the scanner.

type SearchRealm

type SearchRealm int

SearchRealm identifies a search realm (search domain) where device is found.

const (
	RealmInvalid SearchRealm = iota

	RealmDNSSD // DNS-SD search
	RealmWSD   // Microsoft WS-Discovery
	RealmUSB   // USB
)

SearchRealm values:

func (SearchRealm) String

func (realm SearchRealm) String() string

String returns SearchRealm name.

type ServiceProto

type ServiceProto int

ServiceProto represents service protocol

const (
	ServiceIPP       ServiceProto = iota // IPP/IPPS printer or scanner
	ServiceESCL                          // ESCL scanner
	ServiceLPD                           // LPD printer
	ServiceAppSocket                     // AppSocket (JetDirect) printer
	ServiceWSD                           // WSD printer or scanner
	ServiceUSB                           // USB printer
)

ServiceProto constants:

func (ServiceProto) String

func (p ServiceProto) String() string

String returns ServiceProto name, for debugging

type ServiceType

type ServiceType int

ServiceType represents a service type

const (
	ServicePrinter ServiceType = iota // Printer
	ServiceScanner                    // Scanner
	ServiceFaxout                     // Fax
)

ServiceType constants:

func (ServiceType) String

func (t ServiceType) String() string

String returns ServiceType name, for debugging

type UnitID

type UnitID struct {
	DNSSDName string       // DNS-SD name, "" if not available
	UUID      uuid.UUID    // uuid.NilUUID if not available
	Queue     string       // Logical unit within a device
	Realm     SearchRealm  // Search realm
	Zone      string       // Namespace zone within the Realm
	Variant   string       // Finding variant of the same unit
	SvcType   ServiceType  // Service type
	SvcProto  ServiceProto // Service protocol
	USBSerial string       // "" if not avaliable
	USBHWID   string       // "" if not avaliable
}

UnitID contains combination of parameters that identifies a device.

Please note, depending on a discovery protocol being used, not all the fields of the following structure will have any sense.

Note also, that device UUID is not necessary the same between protocols. Some Canon devices known to use different UUID for DNS-SD and WS-Discovery.

The intended fields usage is the following:

DeviceName - realm-unique device name, in the DNS-SD sense.
             E.g., "Kyocera ECOSYS M2040dn",
UUID       - device UUID
Queue      - Job queue name for units with logical sub-units,
             like LPD server with multiple queues
Realm      - search realm. Different realms are treated as
             independent namespaces.
Zone       - allows backend to further divide its namespace
             (for example, to split it between network interfaces)
Variant    - used to distinguish between logically equivalent
             variants of discovered units, that backend sees as
             independent instances (for example IP4/IP6, HTTP/HTTPS)
SvcType    - service type, printer/scanner/faxout
SvcProto   - service protocol, i.e., IPP, LPD, eSCL etc
Serial     - device serial number, if appropriate (i.e., for USB)

func (UnitID) MarshalLog

func (id UnitID) MarshalLog() []byte

MarshalLog dumps UnitID as text, for log.Object. It implements log.Marshaler.

func (UnitID) SameDevice

func (id UnitID) SameDevice(id2 UnitID) bool

SameDevice reports if two [UnitID]s belong to the same device.

func (UnitID) SameService

func (id UnitID) SameService(id2 UnitID) bool

SameService reports if two [UnitID]s belong to the same service of the same device.

func (UnitID) SameUnit

func (id UnitID) SameUnit(id2 UnitID) bool

SameUnit reports if two [UnitID]s belong to the same unit of the same device.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL