mirror of
https://github.com/ipfs/kubo.git
synced 2025-05-21 08:56:37 +08:00
turned req + res into interfaces
This commit is contained in:
@ -9,7 +9,7 @@ import (
|
||||
|
||||
// Parse parses the input commandline string (cmd, flags, and args).
|
||||
// returns the corresponding command Request object.
|
||||
func Parse(input []string, root *commands.Command) (*commands.Request, error) {
|
||||
func Parse(input []string, root *commands.Command) (commands.Request, error) {
|
||||
path, input := parsePath(input, root)
|
||||
opts, args, err := parseOptions(input)
|
||||
if err != nil {
|
||||
|
@ -4,11 +4,15 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
u "github.com/jbenet/go-ipfs/util"
|
||||
)
|
||||
|
||||
var log = u.Logger("command")
|
||||
|
||||
// Function is the type of function that Commands use.
|
||||
// It reads from the Request, and writes results to the Response.
|
||||
type Function func(*Request, *Response)
|
||||
type Function func(Request, Response)
|
||||
|
||||
// Command is a runnable command, with input arguments and options (flags).
|
||||
// It can also have subcommands, to group units of work into sets.
|
||||
@ -43,10 +47,10 @@ func (c *Command) Register(id string, sub *Command) error {
|
||||
}
|
||||
|
||||
// Call invokes the command at the given subcommand path
|
||||
func (c *Command) Call(req *Request) *Response {
|
||||
res := &Response{req: req}
|
||||
func (c *Command) Call(req Request) Response {
|
||||
res := NewResponse(req)
|
||||
|
||||
cmds, err := c.Resolve(req.path)
|
||||
cmds, err := c.Resolve(req.Path())
|
||||
if err != nil {
|
||||
res.SetError(err, ErrClient)
|
||||
return res
|
||||
@ -58,13 +62,13 @@ func (c *Command) Call(req *Request) *Response {
|
||||
return res
|
||||
}
|
||||
|
||||
options, err := c.GetOptions(req.path)
|
||||
options, err := c.GetOptions(req.Path())
|
||||
if err != nil {
|
||||
res.SetError(err, ErrClient)
|
||||
return res
|
||||
}
|
||||
|
||||
err = req.convertOptions(options)
|
||||
err = req.ConvertOptions(options)
|
||||
if err != nil {
|
||||
res.SetError(err, ErrClient)
|
||||
return res
|
||||
|
@ -8,70 +8,70 @@ func TestOptionValidation(t *testing.T) {
|
||||
Option{[]string{"b", "beep"}, Int},
|
||||
Option{[]string{"B", "boop"}, String},
|
||||
},
|
||||
run: func(req *Request, res *Response) {},
|
||||
run: func(req Request, res Response) {},
|
||||
}
|
||||
|
||||
req := NewEmptyRequest()
|
||||
req.options["foo"] = 5
|
||||
req.SetOption("foo", 5)
|
||||
res := cmd.Call(req)
|
||||
if res.Error == nil {
|
||||
if res.Error() == nil {
|
||||
t.Error("Should have failed (unrecognized option)")
|
||||
}
|
||||
|
||||
req = NewEmptyRequest()
|
||||
req.options["beep"] = 5
|
||||
req.options["b"] = 10
|
||||
req.SetOption("beep", 5)
|
||||
req.SetOption("b", 10)
|
||||
res = cmd.Call(req)
|
||||
if res.Error == nil {
|
||||
if res.Error() == nil {
|
||||
t.Error("Should have failed (duplicate options)")
|
||||
}
|
||||
|
||||
req = NewEmptyRequest()
|
||||
req.options["beep"] = "foo"
|
||||
req.SetOption("beep", "foo")
|
||||
res = cmd.Call(req)
|
||||
if res.Error == nil {
|
||||
if res.Error() == nil {
|
||||
t.Error("Should have failed (incorrect type)")
|
||||
}
|
||||
|
||||
req = NewEmptyRequest()
|
||||
req.options["beep"] = 5
|
||||
req.SetOption("beep", 5)
|
||||
res = cmd.Call(req)
|
||||
if res.Error != nil {
|
||||
t.Error(res.Error, "Should have passed")
|
||||
if res.Error() != nil {
|
||||
t.Error(res.Error(), "Should have passed")
|
||||
}
|
||||
|
||||
req = NewEmptyRequest()
|
||||
req.options["beep"] = 5
|
||||
req.options["boop"] = "test"
|
||||
req.SetOption("beep", 5)
|
||||
req.SetOption("boop", "test")
|
||||
res = cmd.Call(req)
|
||||
if res.Error != nil {
|
||||
if res.Error() != nil {
|
||||
t.Error("Should have passed")
|
||||
}
|
||||
|
||||
req = NewEmptyRequest()
|
||||
req.options["b"] = 5
|
||||
req.options["B"] = "test"
|
||||
req.SetOption("b", 5)
|
||||
req.SetOption("B", "test")
|
||||
res = cmd.Call(req)
|
||||
if res.Error != nil {
|
||||
if res.Error() != nil {
|
||||
t.Error("Should have passed")
|
||||
}
|
||||
|
||||
req = NewEmptyRequest()
|
||||
req.options[EncShort] = "json"
|
||||
req.SetOption(EncShort, "json")
|
||||
res = cmd.Call(req)
|
||||
if res.Error != nil {
|
||||
if res.Error() != nil {
|
||||
t.Error("Should have passed")
|
||||
}
|
||||
|
||||
req = NewEmptyRequest()
|
||||
req.options["b"] = "100"
|
||||
req.SetOption("b", "100")
|
||||
res = cmd.Call(req)
|
||||
if res.Error != nil {
|
||||
if res.Error() != nil {
|
||||
t.Error("Should have passed")
|
||||
}
|
||||
|
||||
req = NewEmptyRequest()
|
||||
req.options["b"] = ":)"
|
||||
req.SetOption("b", ":)")
|
||||
res = cmd.Call(req)
|
||||
if res.Error == nil {
|
||||
t.Error(res.Error, "Should have failed (string value not convertible to int)")
|
||||
@ -79,40 +79,41 @@ func TestOptionValidation(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRegistration(t *testing.T) {
|
||||
noop := func(req Request, res Response) {}
|
||||
cmds := []*Command{
|
||||
&Command{
|
||||
Options: []Option{
|
||||
Option{[]string{"beep"}, Int},
|
||||
},
|
||||
run: func(req *Request, res *Response) {},
|
||||
run: noop,
|
||||
},
|
||||
|
||||
&Command{
|
||||
Options: []Option{
|
||||
Option{[]string{"boop"}, Int},
|
||||
},
|
||||
run: func(req *Request, res *Response) {},
|
||||
run: noop,
|
||||
},
|
||||
|
||||
&Command{
|
||||
Options: []Option{
|
||||
Option{[]string{"boop"}, String},
|
||||
},
|
||||
run: func(req *Request, res *Response) {},
|
||||
run: noop,
|
||||
},
|
||||
|
||||
&Command{
|
||||
Options: []Option{
|
||||
Option{[]string{"bop"}, String},
|
||||
},
|
||||
run: func(req *Request, res *Response) {},
|
||||
run: noop,
|
||||
},
|
||||
|
||||
&Command{
|
||||
Options: []Option{
|
||||
Option{[]string{EncShort}, String},
|
||||
},
|
||||
run: func(req *Request, res *Response) {},
|
||||
run: noop,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -6,37 +6,48 @@ import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type optMap map[string]interface{}
|
||||
|
||||
// Request represents a call to a command from a consumer
|
||||
type Request struct {
|
||||
type Request interface {
|
||||
Path() []string
|
||||
Option(name string) (interface{}, bool)
|
||||
SetOption(name string, val interface{})
|
||||
Arguments() []string
|
||||
|
||||
ConvertOptions(options map[string]Option) error
|
||||
}
|
||||
|
||||
type request struct {
|
||||
path []string
|
||||
options map[string]interface{}
|
||||
options optMap
|
||||
arguments []string
|
||||
}
|
||||
|
||||
func (r *Request) Path() []string {
|
||||
// Path returns the command path of this request
|
||||
func (r *request) Path() []string {
|
||||
return r.path
|
||||
}
|
||||
|
||||
func (r *Request) SetPath(path []string) {
|
||||
r.path = path
|
||||
// Option returns the value of the option for given name.
|
||||
func (r *request) Option(name string) (interface{}, bool) {
|
||||
val, err := r.options[name]
|
||||
return val, err
|
||||
}
|
||||
|
||||
func (r *Request) Option(name string) (interface{}, bool) {
|
||||
val, ok := r.options[name]
|
||||
return val, ok
|
||||
// SetOption sets the value of the option for given name.
|
||||
func (r *request) SetOption(name string, val interface{}) {
|
||||
r.options[name] = val
|
||||
}
|
||||
|
||||
func (r *Request) SetOption(name string, value interface{}) {
|
||||
r.options[name] = value
|
||||
}
|
||||
|
||||
func (r *Request) Arguments() []string {
|
||||
// Arguments returns the arguments slice
|
||||
func (r *request) Arguments() []string {
|
||||
return r.arguments
|
||||
}
|
||||
|
||||
type converter func(string) (interface{}, error)
|
||||
|
||||
var converters map[reflect.Kind]converter = map[reflect.Kind]converter{
|
||||
var converters = map[reflect.Kind]converter{
|
||||
Bool: func(v string) (interface{}, error) {
|
||||
if v == "" {
|
||||
return true, nil
|
||||
@ -54,7 +65,7 @@ var converters map[reflect.Kind]converter = map[reflect.Kind]converter{
|
||||
},
|
||||
}
|
||||
|
||||
func (r *Request) convertOptions(options map[string]Option) error {
|
||||
func (r *request) ConvertOptions(options map[string]Option) error {
|
||||
converted := make(map[string]interface{})
|
||||
|
||||
for k, v := range r.options {
|
||||
@ -98,11 +109,13 @@ func (r *Request) convertOptions(options map[string]Option) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewEmptyRequest() *Request {
|
||||
// NewEmptyRequest initializes an empty request
|
||||
func NewEmptyRequest() Request {
|
||||
return NewRequest(nil, nil, nil)
|
||||
}
|
||||
|
||||
func NewRequest(path []string, opts map[string]interface{}, args []string) *Request {
|
||||
// NewRequest returns a request initialized with given arguments
|
||||
func NewRequest(path []string, opts optMap, args []string) Request {
|
||||
if path == nil {
|
||||
path = make([]string, 0)
|
||||
}
|
||||
@ -112,5 +125,5 @@ func NewRequest(path []string, opts map[string]interface{}, args []string) *Requ
|
||||
if args == nil {
|
||||
args = make([]string, 0)
|
||||
}
|
||||
return &Request{path, opts, args}
|
||||
return &request{path, opts, args}
|
||||
}
|
||||
|
@ -48,21 +48,53 @@ var marshallers = map[EncodingType]Marshaller{
|
||||
|
||||
// Response is the result of a command request. Handlers write to the response,
|
||||
// setting Error or Value. Response is returned to the client.
|
||||
type Response struct {
|
||||
req *Request
|
||||
Error *Error
|
||||
Value interface{}
|
||||
}
|
||||
type Response interface {
|
||||
Request() Request
|
||||
|
||||
// SetError updates the response Error.
|
||||
func (r *Response) SetError(err error, code ErrorType) {
|
||||
r.Error = &Error{Message: err.Error(), Code: code}
|
||||
}
|
||||
// Set/Return the response Error
|
||||
SetError(err error, code ErrorType)
|
||||
Error() error
|
||||
|
||||
// Sets/Returns the response value
|
||||
SetValue(interface{})
|
||||
Value() interface{}
|
||||
|
||||
// Marshal marshals out the response into a buffer. It uses the EncodingType
|
||||
// on the Request to chose a Marshaller (Codec).
|
||||
func (r *Response) Marshal() ([]byte, error) {
|
||||
if r.Error == nil && r.Value == nil {
|
||||
Marshal() ([]byte, error)
|
||||
}
|
||||
|
||||
type response struct {
|
||||
req Request
|
||||
err *Error
|
||||
value interface{}
|
||||
}
|
||||
|
||||
func (r *response) Request() Request {
|
||||
return r.req
|
||||
}
|
||||
|
||||
func (r *response) Value() interface{} {
|
||||
return r.value
|
||||
}
|
||||
|
||||
func (r *response) SetValue(v interface{}) {
|
||||
r.value = v
|
||||
}
|
||||
|
||||
func (r *response) Error() error {
|
||||
if r.err == nil {
|
||||
return nil
|
||||
}
|
||||
return r.err
|
||||
}
|
||||
|
||||
func (r *response) SetError(err error, code ErrorType) {
|
||||
r.err = &Error{Message: err.Error(), Code: code}
|
||||
}
|
||||
|
||||
func (r *response) Marshal() ([]byte, error) {
|
||||
if r.err == nil && r.value == nil {
|
||||
return nil, fmt.Errorf("No error or value set, there is nothing to marshal")
|
||||
}
|
||||
|
||||
@ -77,8 +109,13 @@ func (r *Response) Marshal() ([]byte, error) {
|
||||
return nil, fmt.Errorf("No marshaller found for encoding type '%s'", enc)
|
||||
}
|
||||
|
||||
if r.Error != nil {
|
||||
return marshaller(r.Error)
|
||||
if r.err != nil {
|
||||
return marshaller(r.err)
|
||||
}
|
||||
return marshaller(r.Value)
|
||||
return marshaller(r.value)
|
||||
}
|
||||
|
||||
// NewResponse returns a response to match given Request
|
||||
func NewResponse(req Request) Response {
|
||||
return &response{req: req}
|
||||
}
|
||||
|
@ -13,10 +13,8 @@ type TestOutput struct {
|
||||
func TestMarshalling(t *testing.T) {
|
||||
req := NewEmptyRequest()
|
||||
|
||||
res := Response{
|
||||
req: req,
|
||||
Value: TestOutput{"beep", "boop", 1337},
|
||||
}
|
||||
res := NewResponse(req)
|
||||
res.SetValue(TestOutput{"beep", "boop", 1337})
|
||||
|
||||
// get command global options so we can set the encoding option
|
||||
cmd := Command{}
|
||||
@ -31,7 +29,7 @@ func TestMarshalling(t *testing.T) {
|
||||
}
|
||||
|
||||
req.SetOption(EncShort, JSON)
|
||||
req.convertOptions(options)
|
||||
req.ConvertOptions(options)
|
||||
|
||||
bytes, err := res.Marshal()
|
||||
if err != nil {
|
||||
|
Reference in New Issue
Block a user