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