2021-11-22 11:23:46 +08:00
|
|
|
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
//
|
|
|
|
|
|
|
|
package gcmd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
|
|
|
|
"github.com/gogf/gf/v2/errors/gcode"
|
|
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
2021-11-23 14:08:37 +08:00
|
|
|
"github.com/gogf/gf/v2/internal/structs"
|
2021-11-22 11:23:46 +08:00
|
|
|
"github.com/gogf/gf/v2/internal/utils"
|
|
|
|
"github.com/gogf/gf/v2/text/gstr"
|
2021-11-23 14:08:37 +08:00
|
|
|
"github.com/gogf/gf/v2/util/gconv"
|
2021-11-22 11:23:46 +08:00
|
|
|
"github.com/gogf/gf/v2/util/gmeta"
|
2021-11-23 14:08:37 +08:00
|
|
|
"github.com/gogf/gf/v2/util/gutil"
|
2021-11-22 11:23:46 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2021-11-23 14:08:37 +08:00
|
|
|
tagNameDc = `dc`
|
|
|
|
tagNameAd = `ad`
|
2021-11-22 11:23:46 +08:00
|
|
|
)
|
|
|
|
|
2021-11-23 14:08:37 +08:00
|
|
|
func CommandsFromObject(object interface{}) (commands []Command, err error) {
|
2021-11-22 11:23:46 +08:00
|
|
|
originValueAndKind := utils.OriginValueAndKind(object)
|
|
|
|
if originValueAndKind.OriginKind != reflect.Struct {
|
2021-11-23 14:08:37 +08:00
|
|
|
return nil, gerror.Newf(
|
2021-11-22 11:23:46 +08:00
|
|
|
`input object should be type of struct, but got "%s"`,
|
|
|
|
originValueAndKind.InputValue.Type().String(),
|
|
|
|
)
|
|
|
|
}
|
2021-11-23 14:08:37 +08:00
|
|
|
//for i := 0; i < originValueAndKind.InputValue.NumMethod(); i++ {
|
|
|
|
// method := originValueAndKind.InputValue.Method(i)
|
|
|
|
//}
|
|
|
|
//for _, field := range fields {
|
|
|
|
//
|
|
|
|
//}
|
|
|
|
return
|
2021-11-22 11:23:46 +08:00
|
|
|
}
|
|
|
|
|
2021-11-23 14:08:37 +08:00
|
|
|
func newCommandFromMethod(object, method reflect.Value) (*Command, error) {
|
2021-11-22 11:23:46 +08:00
|
|
|
var (
|
2021-11-23 14:08:37 +08:00
|
|
|
err error
|
2021-11-22 11:23:46 +08:00
|
|
|
reflectType = method.Type()
|
|
|
|
)
|
2021-11-23 14:08:37 +08:00
|
|
|
// Necessary validation for input/output parameters and naming.
|
2021-11-22 11:23:46 +08:00
|
|
|
if reflectType.NumIn() != 2 || reflectType.NumOut() != 2 {
|
|
|
|
if reflectType.PkgPath() != "" {
|
|
|
|
err = gerror.NewCodef(
|
|
|
|
gcode.CodeInvalidParameter,
|
|
|
|
`invalid handler: %s.%s.%s defined as "%s", but "func(context.Context, Input)(Output, error)" is required`,
|
|
|
|
reflectType.PkgPath(), object.Type().Name(), reflectType.Name(), reflectType.String(),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
err = gerror.NewCodef(
|
|
|
|
gcode.CodeInvalidParameter,
|
|
|
|
`invalid handler: defined as "%s", but "func(context.Context, Input)(Output, error)" is required`,
|
|
|
|
reflectType.String(),
|
|
|
|
)
|
|
|
|
}
|
2021-11-23 14:08:37 +08:00
|
|
|
return nil, err
|
2021-11-22 11:23:46 +08:00
|
|
|
}
|
|
|
|
if reflectType.In(0).String() != "context.Context" {
|
|
|
|
err = gerror.NewCodef(
|
|
|
|
gcode.CodeInvalidParameter,
|
|
|
|
`invalid handler: defined as "%s", but the first input parameter should be type of "context.Context"`,
|
|
|
|
reflectType.String(),
|
|
|
|
)
|
2021-11-23 14:08:37 +08:00
|
|
|
return nil, err
|
2021-11-22 11:23:46 +08:00
|
|
|
}
|
|
|
|
if reflectType.Out(1).String() != "error" {
|
|
|
|
err = gerror.NewCodef(
|
|
|
|
gcode.CodeInvalidParameter,
|
|
|
|
`invalid handler: defined as "%s", but the last output parameter should be type of "error"`,
|
|
|
|
reflectType.String(),
|
|
|
|
)
|
2021-11-23 14:08:37 +08:00
|
|
|
return nil, err
|
2021-11-22 11:23:46 +08:00
|
|
|
}
|
|
|
|
// The input struct should be named as `xxxInput`.
|
|
|
|
if !gstr.HasSuffix(reflectType.In(1).String(), `Input`) {
|
|
|
|
err = gerror.NewCodef(
|
|
|
|
gcode.CodeInvalidParameter,
|
|
|
|
`invalid struct naming for input: defined as "%s", but it should be named with "Input" suffix like "xxxInput"`,
|
|
|
|
reflectType.In(1).String(),
|
|
|
|
)
|
2021-11-23 14:08:37 +08:00
|
|
|
return nil, err
|
2021-11-22 11:23:46 +08:00
|
|
|
}
|
|
|
|
// The output struct should be named as `xxxOutput`.
|
|
|
|
if !gstr.HasSuffix(reflectType.Out(0).String(), `Output`) {
|
|
|
|
err = gerror.NewCodef(
|
|
|
|
gcode.CodeInvalidParameter,
|
|
|
|
`invalid struct naming for output: defined as "%s", but it should be named with "Output" suffix like "xxxOutput"`,
|
|
|
|
reflectType.Out(0).String(),
|
|
|
|
)
|
2021-11-23 14:08:37 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
inputObject reflect.Value
|
|
|
|
outputObject reflect.Value
|
|
|
|
)
|
|
|
|
if method.Type().In(1).Kind() == reflect.Ptr {
|
|
|
|
inputObject = reflect.New(method.Type().In(1).Elem()).Elem()
|
|
|
|
} else {
|
|
|
|
inputObject = reflect.New(method.Type().In(1)).Elem()
|
|
|
|
}
|
|
|
|
|
|
|
|
if method.Type().Out(1).Kind() == reflect.Ptr {
|
|
|
|
outputObject = reflect.New(method.Type().Out(0).Elem()).Elem()
|
|
|
|
} else {
|
|
|
|
outputObject = reflect.New(method.Type().Out(0)).Elem()
|
|
|
|
}
|
|
|
|
// Command creating.
|
|
|
|
var (
|
|
|
|
cmd = Command{}
|
|
|
|
metaData = gmeta.Data(inputObject.Interface())
|
|
|
|
)
|
|
|
|
if err = gconv.Scan(metaData, &cmd); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// Name filed is necessary.
|
|
|
|
if cmd.Name == "" {
|
|
|
|
return nil, gerror.Newf(
|
|
|
|
`command name cannot be empty, "name" tag not found in struct "%s"`,
|
|
|
|
inputObject.Type().String(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if cmd.Description == "" {
|
|
|
|
cmd.Description = metaData[tagNameDc]
|
2021-11-22 11:23:46 +08:00
|
|
|
}
|
2021-11-23 14:08:37 +08:00
|
|
|
if cmd.Additional == "" {
|
|
|
|
cmd.Additional = metaData[tagNameAd]
|
|
|
|
}
|
|
|
|
|
|
|
|
if cmd.Options, err = newOptionsFromInput(inputObject.Interface()); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &cmd, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func newOptionsFromInput(object interface{}) (options []Option, err error) {
|
2021-11-22 11:23:46 +08:00
|
|
|
var (
|
2021-11-23 14:08:37 +08:00
|
|
|
fields []structs.Field
|
2021-11-22 11:23:46 +08:00
|
|
|
)
|
2021-11-23 14:08:37 +08:00
|
|
|
fields, err = structs.Fields(structs.FieldsInput{
|
|
|
|
Pointer: object,
|
|
|
|
RecursiveOption: structs.RecursiveOptionEmbeddedNoTag,
|
|
|
|
})
|
|
|
|
for _, field := range fields {
|
|
|
|
var (
|
|
|
|
option = Option{}
|
|
|
|
metaData = gmeta.Data(field.Value.Interface())
|
|
|
|
)
|
|
|
|
if err = gconv.Scan(metaData, &option); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if option.Name == "" {
|
|
|
|
option.Name = field.Name()
|
|
|
|
}
|
|
|
|
options = append(options, option)
|
|
|
|
}
|
|
|
|
return
|
2021-11-22 11:23:46 +08:00
|
|
|
}
|