request.go 3.51 KB
Newer Older
Matt Bell's avatar
Matt Bell committed
1 2
package commands

3 4 5 6
import (
	"fmt"
	"reflect"
	"strconv"
7 8 9

	"github.com/jbenet/go-ipfs/config"
	"github.com/jbenet/go-ipfs/core"
10 11
)

12 13
type optMap map[string]interface{}

14 15 16 17 18 19
type Context struct {
	ConfigRoot string
	Config     *config.Config
	Node       *core.IpfsNode
}

Matt Bell's avatar
Matt Bell committed
20
// Request represents a call to a command from a consumer
21 22 23
type Request interface {
	Path() []string
	Option(name string) (interface{}, bool)
24
	Options() map[string]interface{}
25
	SetOption(name string, val interface{})
26
	Arguments() []interface{} // TODO: make argument value type instead of using interface{}
27
	Context() *Context
28
	SetContext(Context)
29
	Command() *Command
30 31 32 33 34

	ConvertOptions(options map[string]Option) error
}

type request struct {
Matt Bell's avatar
Matt Bell committed
35
	path      []string
36
	options   optMap
37
	arguments []interface{}
38
	cmd       *Command
39
	ctx       Context
Matt Bell's avatar
Matt Bell committed
40 41
}

42 43
// Path returns the command path of this request
func (r *request) Path() []string {
44 45 46
	return r.path
}

47 48 49 50
// 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
Matt Bell's avatar
Matt Bell committed
51 52
}

53 54 55 56 57 58 59 60 61
// Options returns a copy of the option map
func (r *request) Options() map[string]interface{} {
	output := make(optMap)
	for k, v := range r.options {
		output[k] = v
	}
	return output
}

62 63 64
// SetOption sets the value of the option for given name.
func (r *request) SetOption(name string, val interface{}) {
	r.options[name] = val
65 66
}

67
// Arguments returns the arguments slice
68
func (r *request) Arguments() []interface{} {
Matt Bell's avatar
Matt Bell committed
69
	return r.arguments
70
}
Matt Bell's avatar
Matt Bell committed
71

72 73 74 75
func (r *request) Context() *Context {
	return &r.ctx
}

76 77 78 79
func (r *request) SetContext(ctx Context) {
	r.ctx = ctx
}

80 81 82 83
func (r *request) Command() *Command {
	return r.cmd
}

Matt Bell's avatar
Matt Bell committed
84 85
type converter func(string) (interface{}, error)

86
var converters = map[reflect.Kind]converter{
Matt Bell's avatar
Matt Bell committed
87
	Bool: func(v string) (interface{}, error) {
88 89 90 91 92
		if v == "" {
			return true, nil
		}
		return strconv.ParseBool(v)
	},
Matt Bell's avatar
Matt Bell committed
93
	Int: func(v string) (interface{}, error) {
94 95
		return strconv.ParseInt(v, 0, 32)
	},
Matt Bell's avatar
Matt Bell committed
96
	Uint: func(v string) (interface{}, error) {
97 98
		return strconv.ParseInt(v, 0, 32)
	},
Matt Bell's avatar
Matt Bell committed
99
	Float: func(v string) (interface{}, error) {
100 101 102 103
		return strconv.ParseFloat(v, 64)
	},
}

104
func (r *request) ConvertOptions(options map[string]Option) error {
105 106 107 108 109
	converted := make(map[string]interface{})

	for k, v := range r.options {
		opt, ok := options[k]
		if !ok {
110
			continue
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
		}

		kind := reflect.TypeOf(v).Kind()
		var value interface{}

		if kind != opt.Type {
			if kind == String {
				convert := converters[opt.Type]
				val, err := convert(v.(string))
				if err != nil {
					return fmt.Errorf("Could not convert string value '%s' to type '%s'",
						v, opt.Type.String())
				}
				value = val

			} else {
				return fmt.Errorf("Option '%s' should be type '%s', but got type '%s'",
					k, opt.Type.String(), kind.String())
			}
		} else {
			value = v
		}

		for _, name := range opt.Names {
			if _, ok := r.options[name]; name != k && ok {
				return fmt.Errorf("Duplicate command options were provided ('%s' and '%s')",
					k, name)
			}

Matt Bell's avatar
Matt Bell committed
140
			converted[name] = value
141 142 143 144 145 146 147
		}
	}

	r.options = converted
	return nil
}

148 149
// NewEmptyRequest initializes an empty request
func NewEmptyRequest() Request {
150
	return NewRequest(nil, nil, nil, nil)
Matt Bell's avatar
Matt Bell committed
151 152
}

153
// NewRequest returns a request initialized with given arguments
154
func NewRequest(path []string, opts optMap, args []interface{}, cmd *Command) Request {
155
	if path == nil {
Matt Bell's avatar
Matt Bell committed
156
		path = make([]string, 0)
Matt Bell's avatar
Matt Bell committed
157
	}
158 159 160 161
	if opts == nil {
		opts = make(map[string]interface{})
	}
	if args == nil {
162
		args = make([]interface{}, 0)
163
	}
164
	return &request{path, opts, args, cmd, Context{}}
Matt Bell's avatar
Matt Bell committed
165
}