Documentation ¶
Overview ¶
Package cmds helps building both standalone and client-server applications.
Semantics ¶
The basic building blocks are requests, commands, emitters and responses. A command consists of a description of the parameters and a function. The function is passed the request as well as an emitter as arguments. It does operations on the inputs and sends the results to the user by emitting them.
There are a number of emitters in this package and subpackages, but the user is free to create their own.
Commands ¶
A command is a struct containing the commands help text, a description of the arguments and options, the command's processing function and a type to let the caller know what type will be emitted. Optionally one of the functions PostRun and Encoder may be defined that consumes the function's emitted values and generates a visual representation for e.g. the terminal. Encoders work on a value-by-value basis, while PostRun operates on the value stream.
Emitters ¶
An emitter has the Emit method, that takes the command's function's output as an argument and passes it to the user.
type ResponseEmitter interface { io.Closer SetLength(length uint64) SetError(err interface{}, code cmdkit.ErrorType) Emit(value interface{}) error }
The command's function does not know what kind of emitter it works with, so the same function may run locally or on a server, using an rpc interface. Emitters can also send errors using the SetError method.
The user-facing emitter usually is the cli emitter. Values emitter here will be printed to the terminal using either the Encoders or the PostRun function.
Responses ¶
A response is a value that the user can read emitted values from.
type Response interface { Request() Request Error() *cmdkit.Error Length() uint64 Next() (interface{}, error) }
Responses have a method Next() that returns the next emitted value and an error value. If the last element has been received, the returned error value is io.EOF. If the application code has sent an error using SetError, the error ErrRcvdError is returned on next, indicating that the caller should call Error(). Depending on the reponse type, other errors may also occur.
Pipes ¶
Pipes are pairs (emitter, response), such that a value emitted on the emitter can be received in the response value. Most builtin emitters are "pipe" emitters. The most prominent examples are the channel pipe and the http pipe.
The channel pipe is backed by a channel. The only error value returned by the response is io.EOF, which happens when the channel is closed.
The http pipe is backed by an http connection. The response can also return other errors, e.g. if there are errors on the network.
Examples ¶
To get a better idea of what's going on, take a look at the examples at https://github.com/ipfs/go-ipfs-cmds/tree/master/examples.
Index ¶
- Constants
- Variables
- func ClientError(msg string) error
- func Copy(re ResponseEmitter, res Response) error
- func EmitOnce(re ResponseEmitter, v interface{}) error
- func HandleError(err error, res Response, re ResponseEmitter) bool
- func MakeEncoder(f func(Request, io.Writer, interface{}) error) func(Request) func(io.Writer) Encoder
- func NewChanResponsePair(req Request) (ResponseEmitter, Response)
- func OldCommand(cmd *Command) *oldcmds.Command
- func OldContext(ctx Context) oldcmds.Context
- func OldReqLog(newrl *ReqLog) *oldcmds.ReqLog
- type Any
- type Command
- func (c *Command) Call(req Request, re ResponseEmitter) (err error)
- func (c *Command) CheckArguments(req Request) error
- func (c *Command) Get(path []string) (*Command, error)
- func (c *Command) GetOptions(path []string) (map[string]cmdkit.Option, error)
- func (c *Command) ProcessHelp()
- func (c *Command) Resolve(pth []string) ([]*Command, error)
- func (c *Command) Subcommand(id string) *Command
- func (c *Command) Walk(visitor CommandVisitor)
- type CommandVisitor
- type Context
- type Decoder
- type Encoder
- type EncoderFunc
- type EncoderMap
- type EncodingEmitter
- type EncodingType
- type Flusher
- type Function
- type Head
- type Header
- type MarshalerEncoder
- type OptMap
- type PostRunMap
- type ReqLog
- type ReqLogEntry
- type Request
- type Response
- type ResponseEmitter
- type Single
- type TeeError
- type TextEncoder
- type WriterResponseEmitter
- func (re *WriterResponseEmitter) Close() error
- func (re *WriterResponseEmitter) Emit(v interface{}) error
- func (re *WriterResponseEmitter) Head() Head
- func (re *WriterResponseEmitter) SetEncoder(mkEnc func(io.Writer) Encoder)
- func (re *WriterResponseEmitter) SetError(v interface{}, errType cmdkit.ErrorType)
- func (re *WriterResponseEmitter) SetLength(length uint64)
Constants ¶
const ( Undefined = "" JSON = "json" XML = "xml" Protobuf = "protobuf" Text = "text" TextNewline = "textnl" CLI = "cli" )
Supported EncodingType constants.
const DefaultOutputEncoding = JSON
Variables ¶
var Decoders = map[EncodingType]func(w io.Reader) Decoder{ XML: func(r io.Reader) Decoder { return xml.NewDecoder(r) }, JSON: func(r io.Reader) Decoder { return json.NewDecoder(r) }, }
var Encoders = EncoderMap{ XML: func(req Request) func(io.Writer) Encoder { return func(w io.Writer) Encoder { return xml.NewEncoder(w) } }, JSON: func(req Request) func(io.Writer) Encoder { return func(w io.Writer) Encoder { return json.NewEncoder(w) } }, Text: func(req Request) func(io.Writer) Encoder { return func(w io.Writer) Encoder { return TextEncoder{w: w} } }, TextNewline: func(req Request) func(io.Writer) Encoder { return func(w io.Writer) Encoder { return TextEncoder{w: w, suffix: "\n"} } }, }
var ErrIncorrectType = errors.New("The command returned a value with a different type than expected")
var ErrNoFormatter = ClientError("This command cannot be formatted to plain text")
var ErrNotCallable = ClientError("This command can't be called directly. Try one of its subcommands.")
ErrNotCallable signals a command that cannot be called.
var (
ErrRcvdError = fmt.Errorf("received command error")
)
Functions ¶
func ClientError ¶
func Copy ¶
func Copy(re ResponseEmitter, res Response) error
Copy sends all values received on res to re. If res is closed, it closes re.
func EmitOnce ¶ added in v0.4.7
func EmitOnce(re ResponseEmitter, v interface{}) error
EmitOnce is a helper that emits a value wrapped in Single, to signal that this will be the only value sent.
func HandleError ¶ added in v0.4.4
func HandleError(err error, res Response, re ResponseEmitter) bool
HandleError handles the error from cmds.Response.Next(), it returns true if Next() should be called again
func MakeEncoder ¶
func NewChanResponsePair ¶
func NewChanResponsePair(req Request) (ResponseEmitter, Response)
func OldCommand ¶
OldCommand returns an oldcmds.Command from a Command.
func OldContext ¶
OldContext returns an oldcmds.Context from a Context
Types ¶
type Any ¶
type Any struct {
// contains filtered or unexported fields
}
func (*Any) UnmarshalJSON ¶
type Command ¶
type Command struct { Options []cmdkit.Option Arguments []cmdkit.Argument PreRun func(req Request) error // Run is the function that processes the request to generate a response. // Note that when executing the command over the HTTP API you can only read // after writing when using multipart requests. The request body will not be // available for reading after the HTTP connection has been written to. Run Function PostRun PostRunMap Encoders EncoderMap Helptext cmdkit.HelpText // External denotes that a command is actually an external binary. // fewer checks and validations will be performed on such commands. External bool // Type describes the type of the output of the Command's Run Function. // In precise terms, the value of Type is an instance of the return type of // the Run Function. // // ie. If command Run returns &Block{}, then Command.Type == &Block{} Type interface{} Subcommands map[string]*Command OldSubcommands map[string]*oldcmds.Command }
Command is a runnable command, with input arguments and options (flags). It can also have Subcommands, to group units of work into sets.
func NewCommand ¶
NewCommand returns a Command from an oldcmds.Command
func (*Command) Call ¶
func (c *Command) Call(req Request, re ResponseEmitter) (err error)
Call invokes the command for the given Request
func (*Command) CheckArguments ¶
func (*Command) GetOptions ¶
GetOptions returns the options in the given path of commands
func (*Command) ProcessHelp ¶
func (c *Command) ProcessHelp()
func (*Command) Subcommand ¶
Subcommand returns the subcommand with the given id
func (*Command) Walk ¶
func (c *Command) Walk(visitor CommandVisitor)
Walks tree of all subcommands (including this one)
type CommandVisitor ¶
type CommandVisitor func(*Command)
type Context ¶
type Context struct { Online bool ConfigRoot string ReqLog *ReqLog LoadConfig func(path string) (*config.Config, error) ConstructNode func() (*core.IpfsNode, error) // contains filtered or unexported fields }
func NewContext ¶
NewContext returns a Context from an oldcmds.Context
func (*Context) GetConfig ¶
GetConfig returns the config of the current Command exection context. It may load it with the providied function.
func (*Context) GetNode ¶
GetNode returns the node of the current Command exection context. It may construct it with the provided function.
func (*Context) NodeWithoutConstructing ¶
NodeWithoutConstructing returns the underlying node variable so that clients may close it.
type Decoder ¶
type Decoder interface {
Decode(value interface{}) error
}
Decoder decodes values into value (which should be a pointer).
type Encoder ¶
type Encoder interface {
Encode(value interface{}) error
}
Encoder encodes values onto e.g. an io.Writer. Examples are json.Encoder and xml.Encoder.
type EncoderMap ¶ added in v0.3.0
type EncoderMap map[EncodingType]EncoderFunc
type EncodingEmitter ¶
type EncodingEmitter interface { ResponseEmitter SetEncoder(func(io.Writer) Encoder) }
type EncodingType ¶
type EncodingType string
EncodingType defines a supported encoding
func GetEncoding ¶
func GetEncoding(req Request) EncodingType
GetEncoding returns the EncodingType set in a request, falling back to JSON
type Function ¶
type Function func(Request, ResponseEmitter)
Function is the type of function that Commands use. It reads from the Request, and writes results to the ResponseEmitter.
type MarshalerEncoder ¶
type MarshalerEncoder struct {
// contains filtered or unexported fields
}
MarshalerEncoder implements Encoder from a Marshaler
func NewMarshalerEncoder ¶
NewMarshalerEncoder returns a new MarshalerEncoder
func (*MarshalerEncoder) Encode ¶
func (me *MarshalerEncoder) Encode(v interface{}) error
Encode encodes v onto the io.Writer w using Marshaler m, with both m and w passed in NewMarshalerEncoder
type PostRunMap ¶
type PostRunMap map[EncodingType]func(Request, ResponseEmitter) ResponseEmitter
PostRunMap is the map used in Command.PostRun.
type ReqLog ¶
type ReqLog struct { Requests []*ReqLogEntry // contains filtered or unexported fields }
func (*ReqLog) Add ¶
func (rl *ReqLog) Add(req Request) *ReqLogEntry
func (*ReqLog) AddEntry ¶
func (rl *ReqLog) AddEntry(rle *ReqLogEntry)
func (*ReqLog) ClearInactive ¶
func (rl *ReqLog) ClearInactive()
func (*ReqLog) Finish ¶
func (rl *ReqLog) Finish(rle *ReqLogEntry)
func (*ReqLog) Report ¶
func (rl *ReqLog) Report() []*ReqLogEntry
Report generates a copy of all the entries in the requestlog
func (*ReqLog) SetKeepTime ¶
type ReqLogEntry ¶
type ReqLogEntry struct { StartTime time.Time EndTime time.Time Active bool Command string Options map[string]interface{} Args []string ID int }
func (*ReqLogEntry) Copy ¶
func (r *ReqLogEntry) Copy() *ReqLogEntry
type Request ¶
type Request interface { Path() []string Option(name string) *cmdkit.OptionValue Options() cmdkit.OptMap SetOption(name string, val interface{}) SetOptions(opts cmdkit.OptMap) error Arguments() []string StringArguments() []string SetArguments([]string) Files() files.File SetFiles(files.File) Context() context.Context SetRootContext(context.Context) error InvocContext() *Context SetInvocContext(Context) Command() *Command Values() map[string]interface{} Stdin() io.Reader VarArgs(func(string) error) error ConvertOptions() error }
Request represents a call to a command from a consumer
func NewEmptyRequest ¶
NewEmptyRequest initializes an empty request
func NewRequest ¶
func NewRequest(path []string, opts cmdkit.OptMap, args []string, file files.File, cmd *Command, optDefs map[string]cmdkit.Option) (Request, error)
NewRequest returns a request initialized with given arguments An non-nil error will be returned if the provided option values are invalid
func WrapOldRequest ¶
WrapOldRequest returns a faked Request from an oldcmds.Request.
type Response ¶
type Response interface { Request() Request Error() *cmdkit.Error Length() uint64 // Next returns the next emitted value. // The returned error can be a network or decoding error. // The error can also be ErrRcvdError if an error has been emitted. // In this case the emitted error can be accessed using the Error() method. Next() (interface{}, error) RawNext() (interface{}, error) }
Response is the result of a command request. Response is returned to the client.
func NewReaderResponse ¶
func NewReaderResponse(r io.Reader, encType EncodingType, req Request) Response
type ResponseEmitter ¶
type ResponseEmitter interface { // closes http conn or channel io.Closer // SetLength sets the length of the output // err is an interface{} so we don't have to manually convert to error. SetLength(length uint64) // SetError sets the response error // err is an interface{} so we don't have to manually convert to error. SetError(err interface{}, code cmdkit.ErrorType) // Emit sends a value // if value is io.Reader we just copy that to the connection // other values are marshalled Emit(value interface{}) error }
ResponseEmitter encodes and sends the command code's output to the client. It is all a command can write to.
func NewFlushForwarder ¶
func NewFlushForwarder(re ResponseEmitter, f Flusher) ResponseEmitter
func NewTeeEmitter ¶
func NewTeeEmitter(re1, re2 ResponseEmitter) ResponseEmitter
NewTeeEmitter creates a new ResponseEmitter. Writing to it will write to both the passed ResponseEmitters.
type Single ¶ added in v0.4.7
type Single struct {
Value interface{}
}
Single can be used to signal to any ResponseEmitter that only one value will be emitted. This is important e.g. for the http.ResponseEmitter so it can set the HTTP headers appropriately.
type TextEncoder ¶
type TextEncoder struct {
// contains filtered or unexported fields
}
func (TextEncoder) Encode ¶
func (e TextEncoder) Encode(v interface{}) error
type WriterResponseEmitter ¶
type WriterResponseEmitter struct {
// contains filtered or unexported fields
}
func NewWriterResponseEmitter ¶
func NewWriterResponseEmitter(w io.WriteCloser, req Request, enc func(Request) func(io.Writer) Encoder) *WriterResponseEmitter
func (*WriterResponseEmitter) Close ¶
func (re *WriterResponseEmitter) Close() error
func (*WriterResponseEmitter) Emit ¶
func (re *WriterResponseEmitter) Emit(v interface{}) error
func (*WriterResponseEmitter) Head ¶
func (re *WriterResponseEmitter) Head() Head
func (*WriterResponseEmitter) SetEncoder ¶ added in v0.2.3
func (re *WriterResponseEmitter) SetEncoder(mkEnc func(io.Writer) Encoder)
func (*WriterResponseEmitter) SetError ¶
func (re *WriterResponseEmitter) SetError(v interface{}, errType cmdkit.ErrorType)
func (*WriterResponseEmitter) SetLength ¶
func (re *WriterResponseEmitter) SetLength(length uint64)