Files
golib/nutsdb/entryKv.go
nabbar 854c2fa6e7 Package Status:
- Fix text formatting

Package HTTPServer:
  - fix TLS check, config & loading for server

Bump dependancies
  - change nutsdb owner repos
2023-02-28 15:00:34 +01:00

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
}
}