mirror of
https://github.com/nabbar/golib.git
synced 2025-10-13 19:43:45 +08:00

- Fix text formatting Package HTTPServer: - fix TLS check, config & loading for server Bump dependancies - change nutsdb owner repos
272 lines
7.2 KiB
Go
272 lines
7.2 KiB
Go
//go:build !386 && !arm && !mips && !mipsle
|
|
// +build !386,!arm,!mips,!mipsle
|
|
|
|
/***********************************************************************************************************************
|
|
*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2021 Nicolas JUHEL
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
*
|
|
**********************************************************************************************************************/
|
|
|
|
package nutsdb
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/fxamacker/cbor/v2"
|
|
liberr "github.com/nabbar/golib/errors"
|
|
liblog "github.com/nabbar/golib/logger"
|
|
"github.com/nutsdb/nutsdb"
|
|
)
|
|
|
|
const (
|
|
_MinSkipCaller = 2
|
|
)
|
|
|
|
type CommandRequest struct {
|
|
l liblog.FuncLog
|
|
Cmd CmdCode `mapstructure:"cmd" json:"cmd" yaml:"cmd" toml:"cmd" cbor:"cmd"`
|
|
Params []interface{} `mapstructure:"params" json:"params" yaml:"params" toml:"params" cbor:"params"`
|
|
}
|
|
|
|
type CommandResponse struct {
|
|
Error error `mapstructure:"error" json:"error" yaml:"error" toml:"error" cbor:"error"`
|
|
Value []interface{} `mapstructure:"value" json:"value" yaml:"value" toml:"value" cbor:"value"`
|
|
}
|
|
|
|
func NewCommand() *CommandRequest {
|
|
return &CommandRequest{
|
|
Cmd: CmdUnknown,
|
|
Params: make([]interface{}, 0),
|
|
}
|
|
}
|
|
|
|
func NewCommandByDecode(l liblog.FuncLog, p []byte) (*CommandRequest, liberr.Error) {
|
|
d := NewCommand()
|
|
|
|
if e := cbor.Unmarshal(p, d); e != nil {
|
|
return nil, ErrorCommandUnmarshal.ErrorParent(e)
|
|
}
|
|
|
|
d.SetLogger(l)
|
|
|
|
return d, nil
|
|
}
|
|
|
|
func NewCommandByCaller(params ...interface{}) *CommandRequest {
|
|
pc := make([]uintptr, 10) // at least 1 entry needed
|
|
runtime.Callers(_MinSkipCaller, pc)
|
|
f := runtime.FuncForPC(pc[0])
|
|
|
|
d := NewCommand()
|
|
fn := strings.Split(f.Name(), ".")
|
|
d.Cmd = CmdCodeFromName(fn[len(fn)-1])
|
|
|
|
if len(params) > 0 {
|
|
d.Params = params
|
|
}
|
|
|
|
return d
|
|
}
|
|
|
|
func (c *CommandRequest) SetLogger(l liblog.FuncLog) {
|
|
if l != nil {
|
|
c.l = l
|
|
}
|
|
}
|
|
|
|
func (c *CommandRequest) GetLogger() liblog.Logger {
|
|
if c.l != nil {
|
|
return c.l()
|
|
}
|
|
|
|
return liblog.GetDefault()
|
|
}
|
|
|
|
func (c *CommandRequest) InitParams(num int) {
|
|
c.Params = make([]interface{}, num)
|
|
}
|
|
|
|
func (c *CommandRequest) InitParamsCounter(num int) int {
|
|
c.InitParams(num)
|
|
return 0
|
|
}
|
|
|
|
func (c *CommandRequest) SetParams(num int, val interface{}) {
|
|
if num < len(c.Params) {
|
|
c.Params[num] = val
|
|
return
|
|
}
|
|
|
|
tmp := c.Params
|
|
c.Params = make([]interface{}, len(c.Params)+1)
|
|
|
|
if len(tmp) > 0 {
|
|
for i := 0; i < len(tmp); i++ {
|
|
c.Params[i] = tmp[i]
|
|
}
|
|
}
|
|
|
|
c.Params[num] = val
|
|
}
|
|
|
|
func (c *CommandRequest) SetParamsInc(num int, val interface{}) int {
|
|
c.SetParams(num, val)
|
|
num++
|
|
return num
|
|
}
|
|
|
|
func (c *CommandRequest) EncodeRequest() ([]byte, liberr.Error) {
|
|
if p, e := cbor.Marshal(c); e != nil {
|
|
return nil, ErrorCommandMarshal.ErrorParent(e)
|
|
} else {
|
|
return p, nil
|
|
}
|
|
}
|
|
|
|
func (c *CommandRequest) DecodeResult(p []byte) (*CommandResponse, liberr.Error) {
|
|
res := CommandResponse{}
|
|
|
|
if e := cbor.Unmarshal(p, &res); e != nil {
|
|
return nil, ErrorCommandResultUnmarshal.ErrorParent(e)
|
|
} else {
|
|
return &res, nil
|
|
}
|
|
}
|
|
|
|
func (c *CommandRequest) RunLocal(tx *nutsdb.Tx) (*CommandResponse, liberr.Error) {
|
|
if tx == nil {
|
|
return nil, ErrorTransactionClosed.Error(nil)
|
|
}
|
|
|
|
if c.Cmd == CmdUnknown {
|
|
return nil, ErrorClientCommandInvalid.Error(nil)
|
|
}
|
|
|
|
valTx := reflect.ValueOf(tx)
|
|
mtName := c.Cmd.Name()
|
|
method := valTx.MethodByName(mtName)
|
|
nbPrm := method.Type().NumIn()
|
|
|
|
if len(c.Params) != nbPrm {
|
|
//nolint #goerr113
|
|
return nil, ErrorClientCommandParamsBadNumber.ErrorParent(fmt.Errorf("%s need %d parameters", c.Cmd.Name(), nbPrm))
|
|
}
|
|
|
|
params := make([]reflect.Value, nbPrm)
|
|
for i := 0; i < nbPrm; i++ {
|
|
v := reflect.ValueOf(c.Params[i])
|
|
liblog.DebugLevel.Logf("Param %d : type %s - Val %v", i, v.Type().Name(), v.Interface())
|
|
|
|
if v.Type().Kind() == method.Type().In(i).Kind() {
|
|
params[i] = v
|
|
continue
|
|
}
|
|
|
|
if !v.Type().ConvertibleTo(method.Type().In(i)) {
|
|
//nolint #goerr113
|
|
return nil, ErrorClientCommandParamsMismatching.ErrorParent(fmt.Errorf("cmd: %s", mtName), fmt.Errorf("param num: %d", i), fmt.Errorf("param type: %s, avaitting type: %s", v.Type().Kind(), method.Type().In(i).Kind()))
|
|
}
|
|
|
|
//nolint #exhaustive
|
|
switch method.Type().In(i).Kind() {
|
|
case reflect.Bool:
|
|
params[i] = reflect.ValueOf(v.Bool())
|
|
case reflect.Int:
|
|
params[i] = reflect.ValueOf(int(v.Int()))
|
|
case reflect.Int8:
|
|
params[i] = reflect.ValueOf(int8(v.Int()))
|
|
case reflect.Int16:
|
|
params[i] = reflect.ValueOf(int8(v.Int()))
|
|
case reflect.Int32:
|
|
params[i] = reflect.ValueOf(int16(v.Int()))
|
|
case reflect.Int64:
|
|
params[i] = reflect.ValueOf(v.Int())
|
|
case reflect.Uintptr:
|
|
params[i] = reflect.ValueOf(v.UnsafeAddr())
|
|
case reflect.Uint:
|
|
params[i] = reflect.ValueOf(uint(v.Uint()))
|
|
case reflect.Uint8:
|
|
params[i] = reflect.ValueOf(uint8(v.Uint()))
|
|
case reflect.Uint16:
|
|
params[i] = reflect.ValueOf(uint16(v.Uint()))
|
|
case reflect.Uint32:
|
|
params[i] = reflect.ValueOf(uint32(v.Uint()))
|
|
case reflect.Uint64:
|
|
params[i] = reflect.ValueOf(v.Uint())
|
|
case reflect.Float32:
|
|
params[i] = reflect.ValueOf(float32(v.Float()))
|
|
case reflect.Float64:
|
|
params[i] = reflect.ValueOf(v.Float())
|
|
case reflect.Complex64:
|
|
params[i] = reflect.ValueOf(complex64(v.Complex()))
|
|
case reflect.Complex128:
|
|
params[i] = reflect.ValueOf(v.Complex())
|
|
case reflect.Interface:
|
|
params[i] = reflect.ValueOf(v.Interface())
|
|
case reflect.String:
|
|
params[i] = reflect.ValueOf(v.String())
|
|
}
|
|
|
|
liblog.DebugLevel.Logf("Change Param %d : type %s to %v", i, v.Type().Name(), params[i].Type().Name())
|
|
}
|
|
|
|
resp := method.Call(params)
|
|
ret := CommandResponse{
|
|
Error: nil,
|
|
Value: make([]interface{}, 0),
|
|
}
|
|
|
|
for i := 0; i < len(resp); i++ {
|
|
v := resp[i].Interface()
|
|
if e, ok := v.(error); ok {
|
|
ret.Error = e
|
|
} else {
|
|
ret.Value = append(ret.Value, v)
|
|
}
|
|
}
|
|
|
|
if ret.Error == nil && len(ret.Value) < 1 {
|
|
return nil, nil
|
|
}
|
|
|
|
return &ret, nil
|
|
}
|
|
|
|
func (c *CommandRequest) Run(tx *nutsdb.Tx) ([]byte, liberr.Error) {
|
|
if c.Cmd == CmdUnknown {
|
|
return nil, ErrorClientCommandInvalid.Error(nil)
|
|
}
|
|
|
|
if r, err := c.RunLocal(tx); err != nil {
|
|
return nil, err
|
|
} else if p, e := cbor.Marshal(r); e != nil {
|
|
return nil, ErrorCommandResultMarshal.ErrorParent(e)
|
|
} else {
|
|
return p, nil
|
|
}
|
|
}
|