package cli import ( "encoding/json" "errors" "fmt" "git.nspix.com/golang/micro/utils/helper" "reflect" "strconv" "sync" ) var ( ErrInvalidStruct = errors.New("invalid struct") ErrInvalidArgument = errors.New("invalid argument") ) type Context struct { ID int32 CmdStr string Args []string //所有参数 locker sync.RWMutex Values map[string]interface{} response *Response } func (ctx *Context) reset(s string) { ctx.response = &Response{} ctx.Args = nil ctx.CmdStr = s } func (ctx *Context) Get(s string) interface{} { ctx.locker.RLock() defer ctx.locker.RUnlock() if ctx.Values == nil { return "" } return ctx.Values[s] } func (ctx *Context) Set(key string, value interface{}) { ctx.locker.Lock() defer ctx.locker.Unlock() if ctx.Values == nil { ctx.Values = make(map[string]interface{}) } ctx.Values[key] = value } func (ctx *Context) Bind(i interface{}) (err error) { refVal := reflect.Indirect(reflect.ValueOf(i)) refType := refVal.Type() if refVal.Kind() != reflect.Struct { return ErrInvalidStruct } numOfField := refVal.Type().NumField() if numOfField != len(ctx.Args) { var usage string usage = "Usage: " + ctx.CmdStr + " " for i := 0; i < numOfField; i++ { usage += "{" + helper.LowerFirst(refType.Field(i).Name) + "|" + refVal.Field(i).Type().Kind().String() + "} " } ctx.Set("usage", usage) return ErrInvalidArgument } for i := 0; i < numOfField; i++ { switch refVal.Field(i).Kind() { case reflect.String: refVal.Field(i).SetString(ctx.Args[i]) case reflect.Int, reflect.Int32, reflect.Int64: n, _ := strconv.ParseInt(ctx.Args[i], 10, 64) refVal.Field(i).SetInt(n) case reflect.Float32, reflect.Float64: n, _ := strconv.ParseFloat(ctx.Args[i], 64) refVal.Field(i).SetFloat(n) default: err = fmt.Errorf("unsupported argument %d kind %s", i, refVal.Field(i).Kind()) return } } return } func (ctx *Context) Error(code int, msg string) (err error) { ctx.response.Code = code ctx.response.Error = msg return } func (ctx *Context) Success(i interface{}) (err error) { refVal := reflect.Indirect(reflect.ValueOf(i)) switch refVal.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: ctx.response.Data = []byte(strconv.FormatInt(refVal.Int(), 10)) case reflect.Float32, reflect.Float64: ctx.response.Data = []byte(strconv.FormatFloat(refVal.Float(), 'f', -1, 64)) case reflect.String: ctx.response.Data = []byte(refVal.String()) case reflect.Slice: if refVal.Type().Elem().Kind() == reflect.Uint8 { ctx.response.Data = refVal.Bytes() } else { ctx.response.Data, err = json.MarshalIndent(refVal.Interface(), "", "\t") } case reflect.Struct, reflect.Map: ctx.response.Data, err = json.MarshalIndent(refVal.Interface(), "", "\t") default: ctx.response.Data, err = json.MarshalIndent(refVal.Interface(), "", "\t") } return }