gf/os/gcmd/gcmd_command_object.go

168 lines
4.7 KiB
Go
Raw Normal View History

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
}