466 lines
14 KiB
Go
466 lines
14 KiB
Go
package gojs
|
||
|
||
import (
|
||
"fmt"
|
||
"reflect"
|
||
"runtime"
|
||
"unsafe"
|
||
|
||
"apigo.cc/gojs/common"
|
||
"apigo.cc/gojs/goja"
|
||
"github.com/ssgo/u"
|
||
)
|
||
|
||
func ToJS(in any) any {
|
||
return go2js(in, 0, nil)
|
||
}
|
||
|
||
func ToMap(in any) Map {
|
||
return toMap(in, nil)
|
||
}
|
||
|
||
func toMap(in any, vm *goja.Runtime) Map {
|
||
from := u.RealValue(reflect.ValueOf(in))
|
||
if from.Kind() == reflect.Struct {
|
||
in1 := MakeMap(in)
|
||
if from.CanAddr() && vm != nil {
|
||
ptr := u.String(from.UnsafeAddr())
|
||
vm.SetData(ptr, true)
|
||
in1["gojsObjectId"] = ptr
|
||
// fmt.Println(u.BMagenta(">>> save ptr"), ptr)
|
||
runtime.AddCleanup(&from, func(arg *string) {
|
||
// fmt.Println(u.BMagenta(">>> remove ptr"), ptr)
|
||
vm.RemoveData(ptr)
|
||
}, nil)
|
||
}
|
||
in = in1
|
||
}
|
||
jsValue := go2js(in, 0, vm)
|
||
if mapValue, ok := jsValue.(Map); ok {
|
||
return mapValue
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func go2js(in any, n int, vm *goja.Runtime) any {
|
||
if n > 100 {
|
||
return nil
|
||
}
|
||
|
||
var v reflect.Value
|
||
if inV, ok := in.(reflect.Value); ok {
|
||
v = inV
|
||
} else {
|
||
v = reflect.ValueOf(in)
|
||
}
|
||
for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
|
||
if v.IsNil() {
|
||
return nil
|
||
}
|
||
v = v.Elem()
|
||
}
|
||
if (v.Kind() == reflect.Slice || v.Kind() == reflect.Map || v.Kind() == reflect.Func) && v.IsNil() {
|
||
return nil
|
||
}
|
||
if v.Kind() == reflect.Struct {
|
||
v = reflect.ValueOf(toMap(in, vm))
|
||
}
|
||
switch v.Kind() {
|
||
case reflect.Slice:
|
||
if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 {
|
||
arr := make([]any, v.Len())
|
||
for i := 0; i < v.Len(); i++ {
|
||
o := go2js(v.Index(i).Interface(), n+1, vm)
|
||
arr[i] = o
|
||
}
|
||
return arr
|
||
} else {
|
||
return in
|
||
}
|
||
case reflect.Map:
|
||
o := map[string]any{}
|
||
for _, k2 := range v.MapKeys() {
|
||
k2s := u.String(u.FinalValue(k2).Interface())
|
||
if len(k2s) > 0 && k2s[0] != '_' {
|
||
v2 := go2js(v.MapIndex(k2).Interface(), n+1, vm)
|
||
o[k2s] = v2
|
||
}
|
||
}
|
||
return o
|
||
case reflect.Func:
|
||
// skip goja supported functions
|
||
switch v.Type().String() {
|
||
case "func(goja.FunctionCall) goja.Value":
|
||
return in
|
||
case "func(goja.FunctionCall, *goja.Runtime) goja.Value":
|
||
return in
|
||
case "func(goja.ConstructorCall) *goja.Object":
|
||
return in
|
||
case "func(goja.ConstructorCall, *goja.Runtime) *goja.Object":
|
||
return in
|
||
}
|
||
|
||
// 将go的函数转换为js的函数
|
||
t := v.Type()
|
||
return func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||
vm.SetData("_lastError", nil)
|
||
needArgs := make([]reflect.Type, 0)
|
||
realArgs := make([]reflect.Value, t.NumIn())
|
||
needArgsIndex := map[int]int{}
|
||
hasLastVariadicArg := false
|
||
|
||
// fmt.Println(t.NumIn(), t.String(), u.BYellow(u.JsonP(argsIn.Arguments)))
|
||
for i := 0; i < t.NumIn(); i++ {
|
||
inTypeString := t.In(i).String()
|
||
|
||
if inTypeString == "*goja.Runtime" {
|
||
realArgs[i] = reflect.ValueOf(vm)
|
||
continue
|
||
} else if inTypeString == "goja.Value" {
|
||
realArgs[i] = reflect.ValueOf(argsIn.This)
|
||
continue
|
||
}
|
||
if !realArgs[i].IsValid() {
|
||
needArgs = append(needArgs, t.In(i))
|
||
needArgsIndex[len(needArgsIndex)] = i
|
||
}
|
||
}
|
||
|
||
for i, needArgType := range needArgs {
|
||
var argValue reflect.Value
|
||
isLastVariadicArg := false
|
||
realNeedArgType := needArgType
|
||
if needArgType.Kind() == reflect.Ptr {
|
||
realNeedArgType = needArgType.Elem()
|
||
}
|
||
|
||
if v.Type().IsVariadic() && needArgsIndex[i] == len(realArgs)-1 {
|
||
// 可变参数函数的最后一个使用成员类型
|
||
isLastVariadicArg = true
|
||
hasLastVariadicArg = true
|
||
argValue = reflect.New(needArgType.Elem())
|
||
} else {
|
||
argValue = reflect.New(needArgType)
|
||
}
|
||
|
||
if i > len(argsIn.Arguments)-1 {
|
||
if !isLastVariadicArg && needArgType.Kind() != reflect.Interface && needArgType.Kind() != reflect.Ptr {
|
||
panic(vm.NewGoError(fmt.Errorf("no enough args, need %d, given %d", len(needArgs), len(argsIn.Arguments))))
|
||
}
|
||
realArgs[needArgsIndex[i]] = reflect.ValueOf(argValue.Interface()).Elem()
|
||
} else if realNeedArgType.Kind() == reflect.Func {
|
||
jsFunc, ok := goja.AssertFunction(argsIn.Arguments[i])
|
||
if !ok {
|
||
panic(vm.NewGoError(fmt.Errorf("%s not a function", argsIn.Arguments[i].ExportType().String())))
|
||
}
|
||
|
||
funcType := realNeedArgType
|
||
// 传入的参数是函数,自动转换为go函数
|
||
argValue = MakeFunc(vm, funcType, jsFunc, argsIn.This)
|
||
// argValue = reflect.MakeFunc(funcType, func(goArgs []reflect.Value) []reflect.Value {
|
||
// ins := make([]goja.Value, 0)
|
||
// j := 0
|
||
// for i := 0; i < len(goArgs); i++ {
|
||
// if j >= funcType.NumIn() {
|
||
// break
|
||
// }
|
||
// var jV any
|
||
// if funcType.IsVariadic() && j == funcType.NumIn()-1 && funcType.In(j).Kind() == reflect.Slice {
|
||
// jV = reflect.New(funcType.In(j).Elem()).Interface()
|
||
// } else {
|
||
// jV = reflect.New(funcType.In(j)).Interface()
|
||
// j++
|
||
// }
|
||
// u.Convert(goArgs[i].Interface(), jV)
|
||
// // ins = append(ins, MakeJsValue(vm, reflect.ValueOf(jV).Elem(), false))
|
||
// ins = append(ins, vm.ToValue(jV))
|
||
// }
|
||
|
||
// outs := make([]reflect.Value, 0)
|
||
// jsResult, err := jsFunc(argsIn.This, ins...)
|
||
|
||
// if funcType.NumOut() == 1 {
|
||
// // 只有一个返回值
|
||
// if funcType.Out(0).String() != "error" {
|
||
// out0P := reflect.New(funcType.Out(0)).Interface()
|
||
// if jsResult != nil {
|
||
// u.Convert(jsResult.Export(), out0P)
|
||
// }
|
||
// outs = append(outs, reflect.ValueOf(out0P).Elem())
|
||
// } else {
|
||
// if err == nil {
|
||
// outs = append(outs, reflect.New(funcType.Out(0)).Elem())
|
||
// } else {
|
||
// outs = append(outs, reflect.ValueOf(err))
|
||
// }
|
||
// }
|
||
// } else if funcType.NumOut() > 1 {
|
||
// // 以数组形式返回多个值
|
||
// rArr := make([]any, 0)
|
||
// if err == nil {
|
||
// if jsResult != nil && jsResult.ExportType().Kind() == reflect.Slice && jsResult.ExportType().Elem().Kind() != reflect.Uint8 {
|
||
// vm.ForOf(jsResult, func(v goja.Value) bool {
|
||
// rArr = append(rArr, v.Export())
|
||
// return true
|
||
// })
|
||
// }
|
||
// }
|
||
// k := 0
|
||
// for j := 0; j < funcType.NumOut(); j++ {
|
||
// if funcType.Out(j).String() != "error" {
|
||
// if k < len(rArr) {
|
||
// out0P := reflect.New(funcType.Out(j)).Interface()
|
||
// u.Convert(rArr[k], out0P)
|
||
// k++
|
||
// outs = append(outs, reflect.ValueOf(out0P).Elem())
|
||
// } else {
|
||
// outs = append(outs, reflect.New(funcType.Out(j)).Elem())
|
||
// }
|
||
// } else {
|
||
// if err == nil {
|
||
// outs = append(outs, reflect.New(funcType.Out(j)).Elem())
|
||
// } else {
|
||
// outs = append(outs, reflect.ValueOf(err))
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
// return outs
|
||
// })
|
||
if needArgType.Kind() == reflect.Ptr {
|
||
argValueP := reflect.New(realNeedArgType)
|
||
argValueP.Elem().Set(argValue)
|
||
realArgs[needArgsIndex[i]] = argValueP
|
||
} else {
|
||
realArgs[needArgsIndex[i]] = argValue
|
||
}
|
||
} else {
|
||
argValueP := argValue.Interface()
|
||
jsValue := argsIn.Arguments[i]
|
||
anyV := jsValue.Export()
|
||
recovered := false
|
||
et := jsValue.ExportType()
|
||
if et != nil && et.Kind() == reflect.Map {
|
||
mapV := reflect.ValueOf(anyV)
|
||
// 尝试使用传递的objId直接恢复对象
|
||
if mapV.IsValid() && !mapV.IsNil() {
|
||
objIdV := mapV.MapIndex(reflect.ValueOf("gojsObjectId"))
|
||
if objIdV.IsValid() && !objIdV.IsNil() {
|
||
objId := u.String(objIdV.Interface())
|
||
if vm.GetData(objId) == true {
|
||
// argValueP := reflect.New(realNeedArgType)
|
||
objIdI := u.Int64(objId)
|
||
if objIdI > 0 {
|
||
func() {
|
||
defer recover()
|
||
reObj := reflect.NewAt(realNeedArgType, unsafe.Pointer(uintptr(objIdI)))
|
||
if reObj.IsValid() && !reObj.IsNil() {
|
||
// fmt.Println(u.BCyan(">>>>>>2"), i, objId, vm.GetData(objId), argValue.Elem().Type().String(), reObj.Type().String())
|
||
if argValue.Type().Elem().String() == reObj.Type().String() {
|
||
argValue = reObj
|
||
recovered = true
|
||
}
|
||
}
|
||
}()
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if !recovered {
|
||
u.Convert(anyV, argValueP)
|
||
|
||
// 支持struct中包含函数
|
||
if realNeedArgType.Kind() == reflect.Struct {
|
||
// argValue = reflect.New(realNeedArgType)
|
||
for i := realNeedArgType.NumField() - 1; i >= 0; i-- {
|
||
f := realNeedArgType.Field(i)
|
||
if f.Type.Kind() == reflect.Func {
|
||
fnV := jsValue.ToObject(vm).Get(u.GetLowerName(f.Name))
|
||
if fn, ok := goja.AssertFunction(fnV); ok {
|
||
fn1 := MakeFunc(vm, f.Type, fn, argsIn.This)
|
||
argValueF := u.FinalValue(reflect.ValueOf(argValueP))
|
||
if argValueF.Kind() == reflect.Struct && argValueF.NumField() > i {
|
||
argValueF.Field(i).Set(fn1)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
argValue = reflect.ValueOf(argValueP).Elem()
|
||
}
|
||
realArgs[needArgsIndex[i]] = argValue
|
||
}
|
||
}
|
||
|
||
// 处理可变参数
|
||
if len(needArgs) > 0 {
|
||
if len(argsIn.Arguments) > len(needArgs) {
|
||
lastArgType := needArgs[len(needArgs)-1]
|
||
if lastArgType.Kind() == reflect.Slice && lastArgType.Elem().Kind() != reflect.Uint8 {
|
||
for i := len(needArgs); i < len(argsIn.Arguments); i++ {
|
||
argValue := reflect.New(lastArgType.Elem()).Interface()
|
||
u.Convert(argsIn.Arguments[i].Export(), argValue)
|
||
realArgs = append(realArgs, reflect.ValueOf(argValue).Elem())
|
||
}
|
||
}
|
||
} else if len(argsIn.Arguments) < len(needArgs) && hasLastVariadicArg {
|
||
realArgs = realArgs[:len(realArgs)-1]
|
||
}
|
||
}
|
||
outValues := v.Call(realArgs)
|
||
|
||
outs := make([]any, 0)
|
||
for _, outValue := range outValues {
|
||
outType := outValue.Type()
|
||
if outType.String() == "error" {
|
||
var retErr error
|
||
if !outValue.IsNil() {
|
||
// 抛出异常
|
||
if err, ok := outValue.Interface().(*common.GoErr); ok && err != nil {
|
||
// panic(vm.NewGoError(err))
|
||
retErr = err
|
||
} else if err, ok := outValue.Interface().(error); ok && err != nil {
|
||
if err1, ok1 := err.(*common.GoErr); ok1 {
|
||
if err1 != nil {
|
||
// panic(vm.NewGoError(err1))
|
||
retErr = err1
|
||
}
|
||
} else {
|
||
// panic(vm.NewGoError(err))
|
||
retErr = err
|
||
}
|
||
} else {
|
||
errStr := u.String(outValue.Interface())
|
||
if errStr != "" {
|
||
// panic(vm.NewGoError(errors.New(errStr)))
|
||
retErr = err
|
||
}
|
||
}
|
||
}
|
||
if retErr != nil {
|
||
GetLogger(vm).Error(retErr.Error())
|
||
vm.SetData("_lastError", retErr)
|
||
}
|
||
|
||
// 忽略error参数
|
||
continue
|
||
}
|
||
// 如果返回Struct,自动转换为Map(首字母小写)
|
||
if outType.Kind() == reflect.Struct || (outType.Kind() == reflect.Ptr && outType.Elem().Kind() == reflect.Struct) {
|
||
outs = append(outs, toMap(outValue.Interface(), vm))
|
||
} else if outType.Kind() == reflect.Slice && (outType.Elem().Kind() == reflect.Struct || (outType.Elem().Kind() == reflect.Ptr && outType.Elem().Elem().Kind() == reflect.Struct)) {
|
||
// 如果返回[]Struct,自动转换为[]Map(首字母小写)
|
||
sliceMap := make([]map[string]any, 0)
|
||
for i := 0; i < outValue.Len(); i++ {
|
||
sliceMap = append(sliceMap, toMap(outValue.Index(i).Interface(), vm))
|
||
}
|
||
outs = append(outs, sliceMap)
|
||
} else if outType.Kind() == reflect.Map && (outType.Elem().Kind() == reflect.Struct || (outType.Elem().Kind() == reflect.Ptr && outType.Elem().Elem().Kind() == reflect.Struct)) {
|
||
// 如果返回map[string]Struct,自动转换为map[string]Map(首字母小写)
|
||
mapMap := make(map[string]map[string]any)
|
||
for _, key := range outValue.MapKeys() {
|
||
mapMap[key.String()] = toMap(outValue.MapIndex(key).Interface(), vm)
|
||
}
|
||
outs = append(outs, mapMap)
|
||
} else {
|
||
// 其他返回内容转换JS(主要是Func自动转换)
|
||
outs = append(outs, ToJS(outValue.Interface()))
|
||
}
|
||
}
|
||
if len(outs) == 1 {
|
||
return vm.ToValue(outs[0])
|
||
} else if len(outs) > 1 {
|
||
return vm.ToValue(outs)
|
||
} else {
|
||
return vm.ToValue(nil)
|
||
}
|
||
}
|
||
case reflect.Invalid:
|
||
return nil
|
||
default:
|
||
return in
|
||
}
|
||
}
|
||
|
||
func MakeFunc(vm *goja.Runtime, funcType reflect.Type, jsFunc goja.Callable, thisArg goja.Value) reflect.Value {
|
||
return reflect.MakeFunc(funcType, func(goArgs []reflect.Value) []reflect.Value {
|
||
ins := make([]goja.Value, 0)
|
||
j := 0
|
||
for i := 0; i < len(goArgs); i++ {
|
||
if j >= funcType.NumIn() {
|
||
break
|
||
}
|
||
var jV any
|
||
var t reflect.Type
|
||
if funcType.IsVariadic() && j == funcType.NumIn()-1 && funcType.In(j).Kind() == reflect.Slice {
|
||
t = funcType.In(j).Elem()
|
||
} else {
|
||
t = funcType.In(j)
|
||
j++
|
||
}
|
||
if t.Kind() != reflect.Interface {
|
||
jV = reflect.New(t).Interface()
|
||
u.Convert(goArgs[i].Interface(), jV)
|
||
} else {
|
||
jV = goArgs[i].Interface()
|
||
}
|
||
|
||
// ins = append(ins, MakeJsValue(vm, reflect.ValueOf(jV).Elem(), false))
|
||
ins = append(ins, vm.ToValue(go2js(jV, 0, vm)))
|
||
}
|
||
|
||
outs := make([]reflect.Value, 0)
|
||
jsResult, err := jsFunc(thisArg, ins...)
|
||
|
||
if funcType.NumOut() == 1 {
|
||
// 只有一个返回值
|
||
if funcType.Out(0).String() != "error" {
|
||
out0P := reflect.New(funcType.Out(0)).Interface()
|
||
if jsResult != nil {
|
||
u.Convert(jsResult.Export(), out0P)
|
||
}
|
||
outs = append(outs, reflect.ValueOf(out0P).Elem())
|
||
} else {
|
||
if err == nil {
|
||
outs = append(outs, reflect.New(funcType.Out(0)).Elem())
|
||
} else {
|
||
outs = append(outs, reflect.ValueOf(err))
|
||
}
|
||
}
|
||
} else if funcType.NumOut() > 1 {
|
||
// 以数组形式返回多个值
|
||
rArr := make([]any, 0)
|
||
if err == nil {
|
||
if jsResult != nil && jsResult.ExportType().Kind() == reflect.Slice && jsResult.ExportType().Elem().Kind() != reflect.Uint8 {
|
||
vm.ForOf(jsResult, func(v goja.Value) bool {
|
||
rArr = append(rArr, v.Export())
|
||
return true
|
||
})
|
||
}
|
||
}
|
||
k := 0
|
||
for j := 0; j < funcType.NumOut(); j++ {
|
||
if funcType.Out(j).String() != "error" {
|
||
if k < len(rArr) {
|
||
out0P := reflect.New(funcType.Out(j)).Interface()
|
||
u.Convert(rArr[k], out0P)
|
||
k++
|
||
outs = append(outs, reflect.ValueOf(out0P).Elem())
|
||
} else {
|
||
outs = append(outs, reflect.New(funcType.Out(j)).Elem())
|
||
}
|
||
} else {
|
||
if err == nil {
|
||
outs = append(outs, reflect.New(funcType.Out(j)).Elem())
|
||
} else {
|
||
outs = append(outs, reflect.ValueOf(err))
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return outs
|
||
})
|
||
}
|