Documentation
¶
Index ¶
- Constants
- Variables
- func CanonicalFieldsKey(key string) string
- func GetFieldName(field reflect.StructField) string
- func ScanMessages(data []byte, atEOF bool) (advance int, token []byte, err error)
- func StatusText(code int) string
- func UnmarshalFields(fields Fields, destination any) error
- func UnmarshalMessage(message *Message, destination any) error
- type AuthorizationCredentials
- type AuthorizationRequired
- type AuxRequest
- type Capabilities
- type Configuration
- type FieldMarshaler
- type FieldMarshalerError
- type FieldType
- type FieldUnmarshaler
- type Fields
- func (fields Fields) Add(key, value string)
- func (fields Fields) Del(key string)
- func (fields Fields) Get(key string) string
- func (fields Fields) MarshalBinary() ([]byte, error)
- func (fields Fields) Set(key, value string)
- func (fields Fields) UnmarshalBinary(data []byte) error
- func (fields Fields) Values(key string) []string
- func (fields Fields) Write(writer io.Writer) error
- type GeneralFailure
- type Handler
- type HandlerFunc
- type Log
- type MediaChanged
- type MediaFailure
- type Message
- type MessageMarshaler
- type MessageMarshalerError
- type MessageScanner
- type MessageUnmarshaler
- type MessageWriter
- func (writer *MessageWriter) Configuration() Configuration
- func (writer *MessageWriter) Debug(message string)
- func (writer *MessageWriter) Debugf(format string, args ...any)
- func (writer *MessageWriter) Log(message string)
- func (writer *MessageWriter) Logf(format string, args ...any)
- func (writer *MessageWriter) Print(message string)
- func (writer *MessageWriter) Printf(format string, args ...any)
- func (writer *MessageWriter) Status(message string)
- func (writer *MessageWriter) Statusf(format string, args ...any)
- func (writer *MessageWriter) Warning(message string)
- func (writer *MessageWriter) Warningf(format string, args ...any)
- func (writer *MessageWriter) Write(message *Message) error
- type Method
- type MethodOption
- type Redirect
- type Request
- type Status
- type Stream
- type URIAcquire
- type URIDone
- type URIFailure
- type URIStart
- type Warning
- Bugs
Examples ¶
Constants ¶
const ( StatusCodeCapabilities = 100 StatusCodeLog = 101 StatusCodeStatus = 102 StatusCodeRedirect = 103 StatusCodeWarning = 104 StatusCodeURIStart = 200 StatusCodeURIDone = 201 StatusCodeAuxRequest = 351 StatusCodeURIFailure = 400 StatusCodeGeneralFailure = 401 StatusCodeAuthorizationRequired = 402 StatusCodeMediaFailure = 403 StatusCodeURIAcquire = 600 StatusCodeConfiguration = 601 StatusCodeAuthorizationCredentials = 602 StatusCodeMediaChanged = 603 )
Variables ¶
var ( ErrDestinationNotPointer = errors.New("destination for value is not a pointer") ErrDestinationNotStruct = errors.New("destination for value is not a struct") ErrDestinationIsNil = errors.New("destination for value is nil") ErrSourceNotPointer = errors.New("source for value is not a pointer") ErrSourceNotStruct = errors.New("source for value is not a struct") ErrSourceIsNil = errors.New("source for value is nil") ErrMessageScannerNoData = errors.New("message scanner has not data") ErrMessageHeaderNotFound = errors.New("message header not found") ErrMessageHeaderMalformed = errors.New("message header malformed") ErrFieldEntryInvalid = errors.New("header field entry is invalid") ErrFieldsEmpty = errors.New("header fields are empty") ErrInvalidConfigurationItem = errors.New("configuration item is invalid") ErrEmptyInformationalMessage = errors.New("informational message is empty") ErrNotImplemented = errors.New("not implemented") )
Functions ¶
func CanonicalFieldsKey ¶
CanonicalFieldsKey returns the canonical format of the field key. The canonicalization conversts the first letter of each word in the string to upper case. All other letters are lowercased. For example, the canonical key for "send-config" is "Send-Config". If the key contains a space or invalid bytes, it is returned without modifications.
func GetFieldName ¶
func GetFieldName(field reflect.StructField) string
GetFieldName returns either the name of the given struct field or the value of the struct tag "transport"
func ScanMessages ¶
ScanMessages is a SplitFunc function for bufio.Scanner that returns the entire set of data starting with a status code and ending in a double newline.
Unlike bufio.ScanLines, this function will error if the last line of input is not a newline.
func StatusText ¶
StatusText returns a text for the APT status code. It returns the empty string if the code is unknown.
func UnmarshalFields ¶
UnmarshalFields unmarshals the provided Fields object into the destination provided.
MarshalFields traverses the value of the provided object recursively. If an encountered value implements the FieldUnmarshaler interface (and is not nil or empty), UnmarshalFields calls its UnmarshalFields method to deserialize the Fields object.
Some field representations can be represented with a simple string or map, and thus these two types are permitted without being passed by pointer. Slices are never permitted by this function, unless they implement the FieldMarshaler interface.
The encoding of each field in a struct can be cutomized by the format string stored under the "transport" key in the struct field's tag. The format string gives the name of the field. This is intended to allow for aliasing field names as well as field names that conflict with variable naming requirements in Go.
func UnmarshalMessage ¶
Types ¶
type AuthorizationCredentials ¶
AuthorizationCredentials (status code 602) is sent in response to a 402 Authorization Required.
When received, it will contain the entered username and password.
type AuthorizationRequired ¶
type AuthorizationRequired struct {
Site string
}
AuthorizationRequired (status code 402) is sent to APT to request credentials.
The transport method requires a User and Password pair to continue. After sending this message, a Method will expect APT to send a 602 Authorization Credentials message with the required information. It is possible for a transport method to send this message to APT multiple times (both for multiple credential steps as well as retries and timeouts)
type AuxRequest ¶
type AuxRequest struct { MaximumSize int64 `transport:"MaximumSize"` ShortDesc string `transport:"Aux-ShortDesc"` Description string `transport:"Aux-Description"` URI string `transport:"Aux-URI"` }
AuxRequest (status code 351) indicates a request for an auxiliary file to be downloaded by the acquire system (via another method) and made available for the requesting method.
The requester will get a 600 URI Acquire with the URI it requested and the filename will either be an existing file if the request was a success or if the acquire failed for the some reason the file will not exist.
type Capabilities ¶
type Capabilities struct { SingleInstance bool `transport:"Single-Instance"` NeedsCleanup bool `transport:"Needs-Cleanup"` Pipeline bool SendURIEncoded bool `transport:"Send-URI-Encoded"` SendConfig bool `transport:"Send-Config"` Removable bool AuxRequests bool PreScan string `transport:"Pre-Scan"` Version string }
Capabilities (status code 100) messages are used to inform APT of a transport method's feature set.
Displays the capabilities of the transport method. Methods should set the pipeline bit if their underlying protocol supports pipelining. The only known built-in method that does support pipelining is http(s).
type Configuration ¶
Configuration (status code 601) indicates the configuration was sent to the method.
APT will send the configuration 'space' to the transport method. A series of Config-Items fields are sent, each containing an entry from the APT configuration. Each item is placed verbatim into the map directly. No canonicalization occurs, as these values come in directly from the APT configuration space, and not as field headers.
While files found in `/etc/apt.conf.d/*.conf` will sometimes have several settings:
APT { Install-Recommends "false"; Get { Assume-Yes "true"; }; }
Apt will then convert these into their full namespaced form before the transport receives them:
APT::Install-Recommends "false"; APT::Get::Assume-Yes "true";
This is the format that the transport method will receive, and is what users should expect to look for. No parsing is done for the user as the content of a setting can be, quite literally, anything.
func (Configuration) Section ¶
func (cfg Configuration) Section(prefix string) Configuration
Section returns a subsection of the configuration, based on the given prefix. All keys in the returned subsection will have the prefix trimmed. Multiple section lookups can be performed by combining sections together with "::" (e.g., "APT::Get") This allows taking all parts of a configuration and putting it into a smaller lookup:
confg := cfg.Section("APT::Get") fmt.Println(confg["Assume-Yes"])
This reduces the amount of work and lookup required when a method has its own configuration section
func (Configuration) UnmarshalFields ¶
func (cfg Configuration) UnmarshalFields(fields Fields) error
type FieldMarshaler ¶
type FieldMarshalerError ¶
type FieldMarshalerError struct { Type reflect.Type Err error // contains filtered or unexported fields }
FieldMarshalerError is used when performing automatic reflection-based marshaling into a field.
func (*FieldMarshalerError) Error ¶
func (err *FieldMarshalerError) Error() string
func (*FieldMarshalerError) Unwrap ¶
func (err *FieldMarshalerError) Unwrap() error
type FieldType ¶
type FieldType int
func GetFieldType ¶
GetFieldType returns the FieldType for the given value.
If the FieldType returned is UnknownFieldType, the value cannot be automatically deserialized from a field value into a Go type.
type FieldUnmarshaler ¶
type FieldUnmarshaler interface { // UnmarshalFields decodes the Fields provided into the receiver. UnmarshalFields(Fields) error }
FieldUnmarshaler is the interface implemented by any object that can unmarshal a Fields instance into itself.
type Fields ¶
Fields represents the key-value pairs in a Message.
The keys should use a canonical form, as returned by transport.CanonicalFieldKey.
This type closely matches the textproto.MIMEfields and net/http.Header types.
func MarshalFields ¶
MarshalFields returns the Fields representation of the value provided.
MarshalFields traverses the value of the provided object recursively. If an encountered value implements the FieldMarshaler interface (and is not nil or empty), MarshalFields will use it to produce the Fields object.
Some message representations can be represented with a simple string or map, and thus these two types are permitted without being passed by pointer. Slices are never permitted by this function, unless they implement FieldMarshaler.
The encoding of each field in a struct can be customized by the format string stored under the "transport" key in the struct field's tag. The format string gives the name of the field. This is intended to allow for aliasing field names as well as field names that conflict with variable naming requirements in Go.
func (Fields) Add ¶
Add adds the key, value pair to the fields.
It appends to any existing values associated with key. The key is case-insensitive; it is canonicalized by transport.CanonicalFieldsKey.
func (Fields) Del ¶
Del deletes the value associated with key. The key is case insensitive. It is canonicalized by transport.CanonicalFieldsKey.
func (Fields) Get ¶
Get gets the first value associated with the given key. If there are no values associated with the key, Get returns "".
The key is case insensitive; it is canonicalized by transport.CanonicalFieldsKey. To use non-canonical keys, use the Fields instance directly.
func (Fields) MarshalBinary ¶
MarshalBinary turns the Fields into the correct binary representation.
This is primarily called by Fields.Write.
This function will error if the fields is empty or nil.
func (Fields) Set ¶
Set sets the field entries associated with key to the single element value. It replaces any existing values associated with key. The key is case insensitive. It is canonicalized by transport.CanonicalFieldsKey. To use non-canonical keys, assign to the Fields instance directly.
func (Fields) UnmarshalBinary ¶
UnmarshalBinary parses the fields fields from the provided byte slice.
This function does not perform validation for the contents of the fields fields. It also does not validate that a fields field is not empty, as this is technically allowed.
BUG(bruxisma): This function does not currently handle multi-line fields.
func (Fields) Values ¶
Values returns all values associated with the given key.
It is case insensitive; it is canonicalized by transport.CanonicalFieldsKey. To use non-canonical keys, access the map directly.
The slice returned is NOT a copy.
type GeneralFailure ¶
type GeneralFailure string
GeneralFailure (status code 401) indicates that some unspecific failure has occurred.
This is used when the transport method is no longer able to continue. Shortly after sending this, the transport method SHOULD terminate. It is intended to for invalid configuration options or other severe conditions.
When using the transport.Method.SendAndReceive method, this is automatically sent if the transport.Method.Handler returns an error.
func (GeneralFailure) Error ¶
func (failure GeneralFailure) Error() string
func (GeneralFailure) Is ¶
func (failure GeneralFailure) Is(target error) bool
func (GeneralFailure) MarshalFields ¶
func (failure GeneralFailure) MarshalFields() (Fields, error)
func (GeneralFailure) MarshalMessage ¶
func (failure GeneralFailure) MarshalMessage() (*Message, error)
type Handler ¶
type Handler interface {
AcquireResource(*MessageWriter, *Request) error
}
A Handler responds to a URI Acquire message.
type HandlerFunc ¶
type HandlerFunc func(*MessageWriter, *Request) error
func (HandlerFunc) AcquireResource ¶
func (handler HandlerFunc) AcquireResource(writer *MessageWriter, request *Request) error
type Log ¶
type Log string
Log (status code 101) messages are used when debugging is enabled.
These messages are ONLY used for debugging.
func (Log) MarshalFields ¶
func (Log) MarshalMessage ¶
type MediaChanged ¶
MediaChanged (status code 603) is sent in response to a 403 Media Failure message.
This message is sent in response to a 403 Media Failure message. It indicates the user has changed media and it is safe to proceed.
type MediaFailure ¶
MediaFailure (status code 403) indicates new media must be inserted.
This method is executed primarily when the transport method deals with multiple media to install packages. This can include resources like disks that mounted, FUSE mounts, or any other transparent "media".
type Message ¶
type Message struct { StatusCode int // e.g., 100 Summary string // e.g., Capabilities Fields Fields // e.g., {"Send-Config": "true"} }
Message represents the low level data either sent or received via the APT transport method.
Messages are very close to the same messages found in HTTP and other text protocols that are based off of RFC822. However, no attempt is made to enforce a carriage return ("\r").
A raw Message makes no attempt to validate the StatusCode, Summary, or Fields. This is instead handled by higher level APIs within this library, and users are encouraged to use them over raw Messages.
Messages can be marshaled to and from Binary data, as they have a well-formed "wire format".
func MarshalMessage ¶
todo: support passing in an `error` and converting it to a Message
func (*Message) IsInformational ¶
func (*Message) IsResponse ¶
func (*Message) IsSuccessful ¶
func (*Message) MarshalBinary ¶
MarshalBinary serializes the receiving Message into a byte slice.
func (*Message) UnmarshalBinary ¶
UnmarshalBinary deserializes the receiving byte slice into a Message.
This function does not perform any validation on the message's contents, only that it meets the correct layout.
This means it is possible to receive correctly formatted but ultimately invalid messages.
This function is dependent on the behavior of Unmarshalling a Fields object.
type MessageMarshaler ¶
type MessageMarshalerError ¶
type MessageMarshalerError struct { Type reflect.Type Err error // contains filtered or unexported fields }
MessageMarshalerError is used when performing automatic reflection-based marhsalling into a message.
func (*MessageMarshalerError) Error ¶
func (err *MessageMarshalerError) Error() string
func (*MessageMarshalerError) Unwrap ¶
func (err *MessageMarshalerError) Unwrap() error
type MessageScanner ¶
type MessageScanner struct {
// contains filtered or unexported fields
}
MessageScanner provides a convenient interface for reading messages from any io.Reader. Successive calls to Scan() will step through the the reader, skipping the empty newline between messages. The internal function used to split these messages up is ScanMessages. This internal split function cannot be overridden at this time.
Scanning stops unrecoverably at EOF, the first I/O error encountered, or when data is too large to fit into the internal buffer. Much like bufio.Scanner, if more control over scanning messages is required (however unlikely), it is recommended that users utilize a bufio.Reader in conjunction with ScanMessages.
NOTE(bruxisma): It is unlikely that more granular control scanning is required by users, as the input for messages comes from os.Stdin. Additionally, rescanning os.Stdin is out of scope for this library, and indicates that "something wacky" has gone awry with the APT transport method protocol.
func NewMessageScanner ¶
func NewMessageScanner(reader io.Reader) *MessageScanner
NewMessageScanner will initialize a bufio.Scanner internally, call bufio.Scanner.Split with ScanMessages and then return. This ensures that the order of operations does not result in a panic when scanning.
func (*MessageScanner) Err ¶
func (scanner *MessageScanner) Err() error
Err returns the first non-EOF error that was encountered by the MessageScanner.
func (*MessageScanner) Message ¶
func (scanner *MessageScanner) Message() (*Message, error)
Message returns the most recent Message when scanning, or an error. The value returned will NOT be overwritten by subsequent calls to Scan. However, this is done at the cost of an allocation, as the internal bytes buffer is unmarshalled into the returned Message.
If MessageScanner.Scan has not been called, an error is returned.
func (*MessageScanner) Scan ¶
func (scanner *MessageScanner) Scan() bool
Scan advances the MessageScanner to the next message, which will then be available through the Message method. It returns false when the scan has stopped, either by reaching the end of the input or an error. After Scan returns false, the Err method will return any error that occurred during scanning, unless it was io.EOF.
NOTE(bruxisma): Scan panics if the split function returns empty slices without advancing the input. This is a side effect of uing bufio.Scanner internally.
Example ¶
// note the extra newline at the end of the message data := heredoc.Doc(` 100 Capabilities Single-Instance: true Needs-Cleanup: true Send-URI-Encoded: true Removable: false Send-Config: true `) scanner := NewMessageScanner(strings.NewReader(data)) for scanner.Scan() { _, err := scanner.Message() if err != nil { log.Fatal(err) } // do something with the message }
Output:
type MessageUnmarshaler ¶
type MessageWriter ¶
type MessageWriter struct {
// contains filtered or unexported fields
}
MessageWriter is used to send additional messages back to the consumer.
These messages are sent immediately once called, and can result in a handler being cancelled if an error is sent.
func NewMessageWriter ¶
func NewMessageWriter(writer io.Writer) *MessageWriter
func (*MessageWriter) Configuration ¶
func (writer *MessageWriter) Configuration() Configuration
Configuration returns a copy of configuration sent to the Method from APT.
func (*MessageWriter) Debug ¶
func (writer *MessageWriter) Debug(message string)
Debug is an alias for MessageWriter.Log
func (*MessageWriter) Debugf ¶
func (writer *MessageWriter) Debugf(format string, args ...any)
Debugf is an alias for MessageWriter.Logf
func (*MessageWriter) Log ¶
func (writer *MessageWriter) Log(message string)
Writes a transport.Log message to the communication stream.
func (*MessageWriter) Logf ¶
func (writer *MessageWriter) Logf(format string, args ...any)
Logf writes a transport.Log message to the communication stream, using the provided format specifier.
func (*MessageWriter) Print ¶
func (writer *MessageWriter) Print(message string)
Print is an alias for MessageWriter.Log
func (*MessageWriter) Printf ¶
func (writer *MessageWriter) Printf(format string, args ...any)
Printf is an alias for MessageWriter.Logf
func (*MessageWriter) Status ¶
func (writer *MessageWriter) Status(message string)
Writes a transport.Status message to the communication stream.
func (*MessageWriter) Statusf ¶
func (writer *MessageWriter) Statusf(format string, args ...any)
Statusf writes a transport.Status message to the communication stream, using the provided format specifier.
func (*MessageWriter) Warning ¶
func (writer *MessageWriter) Warning(message string)
Writes a transport.Warning message to the communication stream.
func (*MessageWriter) Warningf ¶
func (writer *MessageWriter) Warningf(format string, args ...any)
Warningf writes a transport.Warning message to the communication stream, using the provided format specifier.
func (*MessageWriter) Write ¶
func (writer *MessageWriter) Write(message *Message) error
Write attempts to marshal the provided message into a binary wire format, and then write it all at once to the underlying writer.
type Method ¶
type Method struct { Handler Handler // contains filtered or unexported fields }
func (*Method) SendAndReceive ¶
SendAndReceive is the Method's main loop, and can be considered equivalent to net/http.Server.ListenAndServe.
This function will perform the initial handshake, launch an event queue, and then block on stdin, until it is closed, cannot be read from any longer, or the context is cancelled.
NOTE(bruxisma): The use of context.Context is currently barebones, and will most likely improve over time.
type MethodOption ¶
func WithCapabilities ¶
func WithCapabilities(capabilities Capabilities) MethodOption
WithCapabilities sets the transport.Capabilities of the Method.
NOTE: transport.Capabilities.SendConfig is always over-written to be true, and transport.Capabilities.Version is always over-written with the version that was passed in to the call to NewMethod.
func WithHandler ¶
func WithHandler(handler Handler) MethodOption
WithHandler sets the transport.Method.Handler
func WithHandlerFunction ¶
func WithHandlerFunction(function func(*MessageWriter, *Request) error) MethodOption
WithHandlerFunction sets the transport.Method.Handler to the provided function
func WithStream ¶
func WithStream(stream *Stream) MethodOption
WithStream allows overwriting the default IO stream for the Method.
type Redirect ¶
type Redirect struct { URI *url.URL NewURI *url.URL `transport:"New-URI"` AltURIs *url.URL `transport:"Alt-URIs"` UsedMirror bool `transport:"Used-Mirror"` }
Redirect (status code 103) is currently undocumented by the APT transport method protocol.
type Status ¶
type Status string
Status (status code 102) messages are used regarding transportation progress.
Status gives a progress indication for the transportation method. It can be used to show pre-transfer status for internet enabled transport methods.
func (Status) MarshalFields ¶
func (Status) MarshalMessage ¶
type Stream ¶
type Stream struct {
// contains filtered or unexported fields
}
Stream acts as an io.ReadWriteCloser, that operates on stdin (for reading), and stdout (for writing). There are several ways to open a stream, the simplest of which is to use the default os.Stdin and os.Stdout pointers.
This type is only thread-safe if the underlying io.Writer and io.Reader are thread-safe.
Users must call close on the underlying io.Writer or io.Reader.
func NewStream ¶
func NewStream() *Stream
NewStream initializes a new Stream with os.Stdin and os.Stdout.
This function does *not* check if the files are actually open and valid.
func NewStreamWith ¶
NewStreamWith initializes a new Stream with the given input and output.
This function does *not* check if the provided interfaces are not nil.
type URIAcquire ¶
type URIAcquire struct { LastModified *time.Time `transport:"Last-Modified"` URI string Filename string }
URIAcquire (status code 600) indicates that APT is requesting a new URI be added to the acquire list.
The deserialized transport.URIAcquire.LastModified field has the time stamp of the current cache file if applicable. transport.URIAcquire.Filename is the name of the file that the acquired URI should be written to. It is safe for the method to assume it has correct write permissions.
NOTE(bruxisma): This message is effectively "repeated" by the transport.Request type passed to Method's Handler.
type URIDone ¶
type URIDone struct { URI string LastModified string `transport:"Last-Modified"` IMSHit string `transport:"IMS-Hit"` Filename string MD5Hash string `transport:"MD5-Hash"` Size int64 }
URIDone (status code 201) indicates that a URI has completed transferrence.
It is possible to specify a 201 URI Done without a URI Start which would mean no data was transferred, but the file is now available. A transport.URIDone.Filename field is specified when the URI is directly available in the local pathname space. APT will either directly use that file or copy it into another location. It is possible to return fields prefix with Alt- to indicate that another possible for the URI has been found in the local pathname space. This is done if a decompressed version of a gunzip file is found.
BUG(bruxisma): We do not currently support the Alt- prefixed fields.
type URIFailure ¶
URIFailure (status code 400) indicates the URI is not retrievable from this source.
Indicates a fatal URI failure. As with 201 URI Done, 200 URI start is not required to precede this message.
func (*URIFailure) Error ¶
func (failure *URIFailure) Error() string
func (*URIFailure) Is ¶
func (failure *URIFailure) Is(target error) bool
type URIStart ¶
type URIStart struct { LastModified string `transport:"Last-Modified"` ResumePoint string `transport:"Resume-Point"` URI string Size int64 }
URIStart (status code 200) indicates that the resource located at the given URI is to begin transferring.
The URI is specified along with stats regarding the file itself.
type Warning ¶
type Warning string
Warning (status code 104) messages are used to indicate a warning.
Warnings can be used to alert users to possibly problematic conditions.
func (Warning) MarshalFields ¶
func (Warning) MarshalMessage ¶
Notes ¶
Bugs ¶
This function does not currently handle multi-line fields.
We do not currently support the Alt- prefixed fields.