@cryptotaxi247 / kubo / commits / b10fc2cc5

turned req + res into interfaces

Juan Batiz-Benet committed Oct 20, 2014 at 11:49 UTC b10fc2cc50f5cc05271b11b10ac41df0883f8d3c
6 files changed +124 -71
commands/cli/parse.go
+1 -1
@@ -9,7 +9,7 @@ import (
9
10 // Parse parses the input commandline string (cmd, flags, and args).
11 // returns the corresponding command Request object.
12 -func Parse(input []string, root *commands.Command) (*commands.Request, error) {
12 +func Parse(input []string, root *commands.Command) (commands.Request, error) {
13 path, input := parsePath(input, root)
14 opts, args, err := parseOptions(input)
15 if err != nil {
commands/command.go
+10 -6
@@ -4,11 +4,15 @@ import (
4 "errors"
5 "fmt"
6 "strings"
7 +
8 + u "github.com/jbenet/go-ipfs/util"
9 )
10
11 +var log = u.Logger("command")
12 +
13 // Function is the type of function that Commands use.
14 // It reads from the Request, and writes results to the Response.
11 -type Function func(*Request, *Response)
15 +type Function func(Request, Response)
16
17 // Command is a runnable command, with input arguments and options (flags).
18 // 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 {
47 }
48
49 // Call invokes the command at the given subcommand path
46 -func (c *Command) Call(req *Request) *Response {
47 - res := &Response{req: req}
50 +func (c *Command) Call(req Request) Response {
51 + res := NewResponse(req)
52
49 - cmds, err := c.Resolve(req.path)
53 + cmds, err := c.Resolve(req.Path())
54 if err != nil {
55 res.SetError(err, ErrClient)
56 return res
@@ -58,13 +62,13 @@ func (c *Command) Call(req *Request) *Response {
62 return res
63 }
64
61 - options, err := c.GetOptions(req.path)
65 + options, err := c.GetOptions(req.Path())
66 if err != nil {
67 res.SetError(err, ErrClient)
68 return res
69 }
70
67 - err = req.convertOptions(options)
71 + err = req.ConvertOptions(options)
72 if err != nil {
73 res.SetError(err, ErrClient)
74 return res
commands/command_test.go
+28 -27
@@ -8,70 +8,70 @@ func TestOptionValidation(t *testing.T) {
8 Option{[]string{"b", "beep"}, Int},
9 Option{[]string{"B", "boop"}, String},
10 },
11 - run: func(req *Request, res *Response) {},
11 + run: func(req Request, res Response) {},
12 }
13
14 req := NewEmptyRequest()
15 - req.options["foo"] = 5
15 + req.SetOption("foo", 5)
16 res := cmd.Call(req)
17 - if res.Error == nil {
17 + if res.Error() == nil {
18 t.Error("Should have failed (unrecognized option)")
19 }
20
21 req = NewEmptyRequest()
22 - req.options["beep"] = 5
23 - req.options["b"] = 10
22 + req.SetOption("beep", 5)
23 + req.SetOption("b", 10)
24 res = cmd.Call(req)
25 - if res.Error == nil {
25 + if res.Error() == nil {
26 t.Error("Should have failed (duplicate options)")
27 }
28
29 req = NewEmptyRequest()
30 - req.options["beep"] = "foo"
30 + req.SetOption("beep", "foo")
31 res = cmd.Call(req)
32 - if res.Error == nil {
32 + if res.Error() == nil {
33 t.Error("Should have failed (incorrect type)")
34 }
35
36 req = NewEmptyRequest()
37 - req.options["beep"] = 5
37 + req.SetOption("beep", 5)
38 res = cmd.Call(req)
39 - if res.Error != nil {
40 - t.Error(res.Error, "Should have passed")
39 + if res.Error() != nil {
40 + t.Error(res.Error(), "Should have passed")
41 }
42
43 req = NewEmptyRequest()
44 - req.options["beep"] = 5
45 - req.options["boop"] = "test"
44 + req.SetOption("beep", 5)
45 + req.SetOption("boop", "test")
46 res = cmd.Call(req)
47 - if res.Error != nil {
47 + if res.Error() != nil {
48 t.Error("Should have passed")
49 }
50
51 req = NewEmptyRequest()
52 - req.options["b"] = 5
53 - req.options["B"] = "test"
52 + req.SetOption("b", 5)
53 + req.SetOption("B", "test")
54 res = cmd.Call(req)
55 - if res.Error != nil {
55 + if res.Error() != nil {
56 t.Error("Should have passed")
57 }
58
59 req = NewEmptyRequest()
60 - req.options[EncShort] = "json"
60 + req.SetOption(EncShort, "json")
61 res = cmd.Call(req)
62 - if res.Error != nil {
62 + if res.Error() != nil {
63 t.Error("Should have passed")
64 }
65
66 req = NewEmptyRequest()
67 - req.options["b"] = "100"
67 + req.SetOption("b", "100")
68 res = cmd.Call(req)
69 - if res.Error != nil {
69 + if res.Error() != nil {
70 t.Error("Should have passed")
71 }
72
73 req = NewEmptyRequest()
74 - req.options["b"] = ":)"
74 + req.SetOption("b", ":)")
75 res = cmd.Call(req)
76 if res.Error == nil {
77 t.Error(res.Error, "Should have failed (string value not convertible to int)")
@@ -79,40 +79,41 @@ func TestOptionValidation(t *testing.T) {
79 }
80
81 func TestRegistration(t *testing.T) {
82 + noop := func(req Request, res Response) {}
83 cmds := []*Command{
84 &Command{
85 Options: []Option{
86 Option{[]string{"beep"}, Int},
87 },
87 - run: func(req *Request, res *Response) {},
88 + run: noop,
89 },
90
91 &Command{
92 Options: []Option{
93 Option{[]string{"boop"}, Int},
94 },
94 - run: func(req *Request, res *Response) {},
95 + run: noop,
96 },
97
98 &Command{
99 Options: []Option{
100 Option{[]string{"boop"}, String},
101 },
101 - run: func(req *Request, res *Response) {},
102 + run: noop,
103 },
104
105 &Command{
106 Options: []Option{
107 Option{[]string{"bop"}, String},
108 },
108 - run: func(req *Request, res *Response) {},
109 + run: noop,
110 },
111
112 &Command{
113 Options: []Option{
114 Option{[]string{EncShort}, String},
115 },
115 - run: func(req *Request, res *Response) {},
116 + run: noop,
117 },
118 }
119
commands/request.go
+31 -18
@@ -6,37 +6,48 @@ import (
6 "strconv"
7 )
8
9 +type optMap map[string]interface{}
10 +
11 // Request represents a call to a command from a consumer
10 -type Request struct {
12 +type Request interface {
13 + Path() []string
14 + Option(name string) (interface{}, bool)
15 + SetOption(name string, val interface{})
16 + Arguments() []string
17 +
18 + ConvertOptions(options map[string]Option) error
19 +}
20 +
21 +type request struct {
22 path []string
12 - options map[string]interface{}
23 + options optMap
24 arguments []string
25 }
26
16 -func (r *Request) Path() []string {
27 +// Path returns the command path of this request
28 +func (r *request) Path() []string {
29 return r.path
30 }
31
20 -func (r *Request) SetPath(path []string) {
21 - r.path = path
22 -}
23 -
24 -func (r *Request) Option(name string) (interface{}, bool) {
25 - val, ok := r.options[name]
26 - return val, ok
32 +// Option returns the value of the option for given name.
33 +func (r *request) Option(name string) (interface{}, bool) {
34 + val, err := r.options[name]
35 + return val, err
36 }
37
29 -func (r *Request) SetOption(name string, value interface{}) {
30 - r.options[name] = value
38 +// SetOption sets the value of the option for given name.
39 +func (r *request) SetOption(name string, val interface{}) {
40 + r.options[name] = val
41 }
42
33 -func (r *Request) Arguments() []string {
43 +// Arguments returns the arguments slice
44 +func (r *request) Arguments() []string {
45 return r.arguments
46 }
47
48 type converter func(string) (interface{}, error)
49
39 -var converters map[reflect.Kind]converter = map[reflect.Kind]converter{
50 +var converters = map[reflect.Kind]converter{
51 Bool: func(v string) (interface{}, error) {
52 if v == "" {
53 return true, nil
@@ -54,7 +65,7 @@ var converters map[reflect.Kind]converter = map[reflect.Kind]converter{
65 },
66 }
67
57 -func (r *Request) convertOptions(options map[string]Option) error {
68 +func (r *request) ConvertOptions(options map[string]Option) error {
69 converted := make(map[string]interface{})
70
71 for k, v := range r.options {
@@ -98,11 +109,13 @@ func (r *Request) convertOptions(options map[string]Option) error {
109 return nil
110 }
111
101 -func NewEmptyRequest() *Request {
112 +// NewEmptyRequest initializes an empty request
113 +func NewEmptyRequest() Request {
114 return NewRequest(nil, nil, nil)
115 }
116
105 -func NewRequest(path []string, opts map[string]interface{}, args []string) *Request {
117 +// NewRequest returns a request initialized with given arguments
118 +func NewRequest(path []string, opts optMap, args []string) Request {
119 if path == nil {
120 path = make([]string, 0)
121 }
@@ -112,5 +125,5 @@ func NewRequest(path []string, opts map[string]interface{}, args []string) *Requ
125 if args == nil {
126 args = make([]string, 0)
127 }
115 - return &Request{path, opts, args}
128 + return &request{path, opts, args}
129 }
commands/response.go
+51 -14
@@ -48,21 +48,53 @@ var marshallers = map[EncodingType]Marshaller{
48
49 // Response is the result of a command request. Handlers write to the response,
50 // setting Error or Value. Response is returned to the client.
51 -type Response struct {
52 - req *Request
53 - Error *Error
54 - Value interface{}
51 +type Response interface {
52 + Request() Request
53 +
54 + // Set/Return the response Error
55 + SetError(err error, code ErrorType)
56 + Error() error
57 +
58 + // Sets/Returns the response value
59 + SetValue(interface{})
60 + Value() interface{}
61 +
62 + // Marshal marshals out the response into a buffer. It uses the EncodingType
63 + // on the Request to chose a Marshaller (Codec).
64 + Marshal() ([]byte, error)
65 +}
66 +
67 +type response struct {
68 + req Request
69 + err *Error
70 + value interface{}
71 +}
72 +
73 +func (r *response) Request() Request {
74 + return r.req
75 +}
76 +
77 +func (r *response) Value() interface{} {
78 + return r.value
79 +}
80 +
81 +func (r *response) SetValue(v interface{}) {
82 + r.value = v
83 +}
84 +
85 +func (r *response) Error() error {
86 + if r.err == nil {
87 + return nil
88 + }
89 + return r.err
90 }
91
57 -// SetError updates the response Error.
58 -func (r *Response) SetError(err error, code ErrorType) {
59 - r.Error = &Error{Message: err.Error(), Code: code}
92 +func (r *response) SetError(err error, code ErrorType) {
93 + r.err = &Error{Message: err.Error(), Code: code}
94 }
95
62 -// Marshal marshals out the response into a buffer. It uses the EncodingType
63 -// on the Request to chose a Marshaller (Codec).
64 -func (r *Response) Marshal() ([]byte, error) {
65 - if r.Error == nil && r.Value == nil {
96 +func (r *response) Marshal() ([]byte, error) {
97 + if r.err == nil && r.value == nil {
98 return nil, fmt.Errorf("No error or value set, there is nothing to marshal")
99 }
100
@@ -77,8 +109,13 @@ func (r *Response) Marshal() ([]byte, error) {
109 return nil, fmt.Errorf("No marshaller found for encoding type '%s'", enc)
110 }
111
80 - if r.Error != nil {
81 - return marshaller(r.Error)
112 + if r.err != nil {
113 + return marshaller(r.err)
114 }
83 - return marshaller(r.Value)
115 + return marshaller(r.value)
116 +}
117 +
118 +// NewResponse returns a response to match given Request
119 +func NewResponse(req Request) Response {
120 + return &response{req: req}
121 }
commands/response_test.go
+3 -5
@@ -13,10 +13,8 @@ type TestOutput struct {
13 func TestMarshalling(t *testing.T) {
14 req := NewEmptyRequest()
15
16 - res := Response{
17 - req: req,
18 - Value: TestOutput{"beep", "boop", 1337},
19 - }
16 + res := NewResponse(req)
17 + res.SetValue(TestOutput{"beep", "boop", 1337})
18
19 // get command global options so we can set the encoding option
20 cmd := Command{}
@@ -31,7 +29,7 @@ func TestMarshalling(t *testing.T) {
29 }
30
31 req.SetOption(EncShort, JSON)
34 - req.convertOptions(options)
32 + req.ConvertOptions(options)
33
34 bytes, err := res.Marshal()
35 if err != nil {