energy/cef/cef-v8-js-bind-object.go
2022-12-05 10:44:24 +08:00

301 lines
9.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// Licensed under GNU General Public License v3.0
//
//----------------------------------------
package cef
import (
"bytes"
"fmt"
"github.com/energye/energy/common"
. "github.com/energye/energy/consts"
"github.com/energye/energy/logger"
"github.com/energye/golcl/lcl/api"
"reflect"
"strconv"
"unsafe"
)
var objectSti = new(structTypeInfo)
//函数详情 1.参数个数 2.每个参数类型 3.返回参数类型
type funcInfo struct {
InNum int32 `json:"inNum"`
InParam []*vt `json:"inParam"`
OutNum int32 `json:"outNum"`
OutParam []*vt `json:"outParam"`
OutParamErrIdx int32 `json:"outParamErrIdx"`
OutParamIdx int32 `json:"outParamIdx"`
FnType FN_TYPE `json:"fnType"`
}
type vt struct {
Jsv V8_JS_VALUE_TYPE `json:"jsv"`
Gov GO_VALUE_TYPE `json:"gov"`
}
//结构类型信息,结构的字段信息和方法函数信息
type structTypeInfo struct {
StructsObject map[string]*structObjectInfo //分析后的 有关系的结构信息
//v8Value *ICEFv8Value
}
//分析后的 结构信息
type structObjectInfo struct {
Instance uintptr `json:"instance"`
ParentInstance uintptr `json:"parentInstance"`
Parent *structObjectInfo `json:"-"`
Ptr unsafe.Pointer `json:"-"`
ObjName string `json:"objName"` //对象名称
FullObjName string `json:"fullObjName"`
FieldsInfo map[string]*structFieldInfo `json:"fieldsInfo"` //字段信息 key=字段名 value=字段类型
FuncsInfo map[string]*structFuncInfo `json:"funcsInfo"`
SubStructObjectInfo map[string]*structObjectInfo `json:"subStructObjectInfo"` //子对象信息
}
//结构的字段信息
type structFieldInfo struct {
EventId uintptr `json:"event_id"`
ValueType *vt `json:"valueType"` //字段类型go 和 js
FieldValue *reflect.Value `json:"-"` //用于字段值修改和获取
}
type structFuncInfo struct {
EventId uintptr `json:"event_id"`
*funcInfo
Method reflect.Value `json:"-"`
}
type cefObject struct {
Id uintptr
ParentId uintptr
Name uintptr //string
FullObjName uintptr //string
FieldLen uintptr
Fields uintptr //array
FuncLen uintptr
Funcs uintptr //array
}
func (m *vt) ToValueTypeString() string {
govs := common.FuncParamGoTypeStr(m.Gov)
jsvs := common.FuncParamJsTypeStr(m.Jsv)
return fmt.Sprintf("GO=%s,JS:=%s", govs, jsvs)
}
func (m *vt) IsGoIntAuto() bool {
switch m.Gov {
case GO_VALUE_INT, GO_VALUE_INT8, GO_VALUE_INT16, GO_VALUE_INT32, GO_VALUE_INT64, GO_VALUE_UINT, GO_VALUE_UINT8, GO_VALUE_UINT16, GO_VALUE_UINT32, GO_VALUE_UINT64:
return true
}
return false
}
func (m *vt) IsGoFloatAuto() bool {
switch m.Gov {
case GO_VALUE_FLOAT32, GO_VALUE_FLOAT64:
return true
}
return false
}
//ICefV8Context BindObject
//对应Golang不支持字段的类型修改包括对象类型,不支持删除和增加字段变更,支持字段值修改。和获取。
func bindObject(objects ...interface{}) {
objectSti.StructsObject = make(map[string]*structObjectInfo, len(objects))
for i := 0; i < len(objects); i++ {
object := objects[i]
typ := reflect.TypeOf(object)
if typ.Kind() == reflect.Ptr {
var value = reflect.ValueOf(object)
var objTyp = reflect.ValueOf(object).Type().Elem()
objectSti.StructsObject[objTyp.Name()] = &structObjectInfo{FieldsInfo: make(map[string]*structFieldInfo), SubStructObjectInfo: make(map[string]*structObjectInfo)}
objectSti.StructsObject[objTyp.Name()].analysisObjectField(objTyp, typ, value)
} else {
logger.Error("结构对象非指针类型:", typ.Name())
}
}
objectSti._objectToCefObject()
}
//对象字段和函数统计
//对象转换 go to cef
func (m *structTypeInfo) _objectToCefObject() {
for _, info := range m.StructsObject {
m._subInfoToCefObject(info)
}
}
func (m *structTypeInfo) _subInfoToCefObject(info *structObjectInfo) {
m._infoTo(info)
if len(info.SubStructObjectInfo) > 0 {
for _, subInfo := range info.SubStructObjectInfo {
m._subInfoToCefObject(subInfo)
}
}
}
func (m *structTypeInfo) _infoTo(info *structObjectInfo) {
var (
fieldLen = len(info.FieldsInfo)
fieldPtr uintptr
funcLen = len(info.FuncsInfo)
funcPtr uintptr
cofs []*valueBindInfo
fns []*valueBindInfo
i = 0
)
if fieldLen > 0 {
//字段
cofs = make([]*valueBindInfo, fieldLen, fieldLen)
for fieldName, fi := range info.FieldsInfo {
cofs[i] = &valueBindInfo{
Name: api.PascalStr(fieldName),
EventId: fi.EventId,
BindType: uintptr(fi.ValueType.Jsv),
}
i++
m.createObjectFieldVariable(info.FullObjName, fieldName, fi)
}
fieldPtr = uintptr(unsafe.Pointer(&cofs[0]))
i = 0
}
if funcLen > 0 {
fns = make([]*valueBindInfo, funcLen, funcLen)
for fnName, fn := range info.FuncsInfo {
var inParamBuf bytes.Buffer
var outParamBuf bytes.Buffer
for j, inParamType := range fn.InParam {
if j > 0 {
inParamBuf.WriteString(",")
}
inParamBuf.WriteString(strconv.Itoa(int(inParamType.Jsv)))
}
for j, outParanType := range fn.OutParam {
if j > 0 {
outParamBuf.WriteString(",")
}
outParamBuf.WriteString(strconv.Itoa(int(outParanType.Jsv)))
}
fns[i] = &valueBindInfo{
Name: api.PascalStr(fnName),
EventId: fn.EventId,
BindType: uintptr(V8_VALUE_FUNCTION),
FnInNum: uintptr(fn.InNum),
FnInParamType: api.PascalStr(inParamBuf.String()),
FnOutNum: uintptr(fn.OutNum),
FnOutParamType: api.PascalStr(outParamBuf.String()),
}
i++
m.createObjectFuncVariable(info.FullObjName, fnName, fn)
}
funcPtr = uintptr(unsafe.Pointer(&fns[0]))
}
co := &cefObject{
Id: info.Instance,
ParentId: info.ParentInstance,
Name: api.PascalStr(info.ObjName),
FullObjName: api.PascalStr(info.FullObjName),
FieldLen: uintptr(fieldLen),
Fields: fieldPtr,
FuncLen: uintptr(funcLen),
Funcs: funcPtr,
}
common.Proc(internale_CEFV8ValueRef_ObjectValueBindInfo).Call(uintptr(unsafe.Pointer(co)))
}
//创建 结构对象的字段变量
func (m *structTypeInfo) createObjectFieldVariable(fullParentName, fieldName string, sfi *structFieldInfo) {
newICEFv8Value(sfi.EventId, fullParentName, fieldName, sfi.FieldValue, nil, sfi.ValueType.Jsv, IS_OBJECT)
}
//创建 结构对象的函数变量
func (m *structTypeInfo) createObjectFuncVariable(fullParentName, funcName string, sfi *structFuncInfo) {
newICEFv8Value(sfi.EventId, fullParentName, funcName, nil, sfi, V8_VALUE_FUNCTION, IS_OBJECT)
}
//分析对象的字段
func (m *structObjectInfo) analysisObjectField(typ reflect.Type, typPtr reflect.Type, value reflect.Value) {
if m.Parent == nil {
m.ObjName = typ.Name()
m.FullObjName = m.ObjName
m.FullObjName = m.ObjName
}
m.Instance = value.Elem().UnsafeAddr()
m.Ptr = unsafe.Pointer(m.Instance)
//字段信息遍历
for i := 0; i < typ.NumField(); i++ {
field := value.Elem().Field(i)
fieldType := field.Type()
fieldName := typ.Field(i).Name
var b, isPrt = false, false
//取出类型,同时判断出是循环引用的类型
if fieldType.Kind() == reflect.Ptr {
fieldType = fieldType.Elem()
isPrt = true
}
//结构对象,循环引用的对象不被支持
if isPrt && fieldType.Kind() == reflect.Struct && !field.IsZero() {
subSoi := &structObjectInfo{FieldsInfo: make(map[string]*structFieldInfo), SubStructObjectInfo: make(map[string]*structObjectInfo)}
subSoi.Parent = m
subSoi.ParentInstance = m.Instance
subSoi.ObjName = fieldName
subSoi.FullObjName = fmt.Sprintf("%s.%s", subSoi.Parent.FullObjName, subSoi.ObjName)
m.SubStructObjectInfo[fieldName] = subSoi
//是结构对象分析
if isPrt {
subSoi.analysisObjectField(fieldType, field.Type(), field)
} else {
subSoi.analysisObjectField(fieldType, fieldType, field)
}
b = true
} else if fieldType.Kind() == reflect.Slice { //数组
} else if typ.Field(i).Type.Kind() != reflect.Ptr && fieldType.Kind() != reflect.Struct && typ.Field(i).IsExported() {
//过滤掉指针类型和非导出大写字段,和不是结构类型
b = true
} else if fieldType.Kind() == reflect.Struct && field.IsZero() {
logger.Debug("字段类型-对象,", fieldName, " 未初始化, 忽略JS绑定映射.")
}
if b { //b=true可以正常解析映射
filedValue := value.Elem().FieldByName(fieldName)
t := fieldType.Kind().String()
m.FieldsInfo[fieldName] = &structFieldInfo{
EventId: uintptr(__bind_id()),
ValueType: &vt{
Jsv: common.JSValueType(t),
Gov: common.GOValueType(t),
},
FieldValue: &filedValue,
}
}
}
m.analysisObjectMethod(typPtr, value)
}
//分析对象的函数方法
//不符合js类型的函数的参数不会被解析成js函数
func (m *structObjectInfo) analysisObjectMethod(typPtr reflect.Type, value reflect.Value) {
m.FuncsInfo = make(map[string]*structFuncInfo)
for idx := 0; idx < typPtr.NumMethod(); idx++ {
method := typPtr.Method(idx)
if method.IsExported() {
if fi, err := checkFunc(method.Type, FN_TYPE_OBJECT); err == nil {
methodValue := value.MethodByName(method.Name)
m.FuncsInfo[method.Name] = &structFuncInfo{
EventId: uintptr(__bind_id()),
funcInfo: fi,
Method: methodValue,
}
} else {
panic(err.Error())
}
}
}
}