energy/cef/cef-v8-value-bind-events.go
2023-03-02 15:11:04 +08:00

398 lines
12 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 Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
//----------------------------------------
// V8 JSValue 绑定事件
package cef
import (
"fmt"
"github.com/energye/energy/common"
"github.com/energye/energy/common/imports"
. "github.com/energye/energy/consts"
"github.com/energye/energy/ipc"
"github.com/energye/energy/logger"
"github.com/energye/golcl/lcl/api"
"github.com/energye/golcl/lcl/api/dllimports"
"reflect"
"unsafe"
)
var (
setCefWindowBindCallbackFunc dllimports.ProcAddr
)
func cefV8WindowBindFuncEventsInit() {
// 初始设置回调函数指针
setCefWindowBindCallbackFunc = imports.Proc(internale_SetCEFWindowBindCallbackFunc)
setCefWindowBindCallbackFunc.Call(cefWindowBindEvent)
}
// cefWindowBindCallbackEventProc 绑定的变量回调事件
func cefWindowBindCallbackEventProc(f uintptr, args uintptr, argcout int) uintptr {
getVal := func(i int) uintptr {
return common.GetParamOf(i, args)
}
eventType := BIND_EVENT(getVal(0))
if BE_FUNC == eventType { //function
v8BindFuncCallbackHandler(eventType, f, args, argcout)
} else if BE_GET == eventType || BE_SET == eventType { // get or set
v8BindFieldCallbackHandler(eventType, f, args, argcout)
} else if BE_CTX_CRT_BIND == eventType { // context create bind
fmt.Println("WindowBindCallbackEventProc eventType", eventType, argcout)
}
return 0
}
// v8BindFieldCallbackHandler 字段处理
func v8BindFieldCallbackHandler(eventType BIND_EVENT, fullNamePtr uintptr, args uintptr, argsLen int) {
var (
exceptionPrt *uintptr
errorMessage = Empty
)
defer func() {
if err := recover(); err != nil {
if exceptionPrt != nil {
*exceptionPrt = api.PascalStr((err.(error)).Error())
}
logger.Error("V8BindFieldCallbackHandler Error", err)
}
}()
getVal := func(i int) uintptr {
return common.GetParamOf(i, args)
}
getPtr := func(i int) unsafe.Pointer {
return unsafe.Pointer(getVal(i))
}
fullName := api.GoStr(fullNamePtr)
if eventType == BE_SET { //设置值
var (
newValueType = (V8_JS_VALUE_TYPE)(getVal(1))
newStringValue string
newIntValue int32
newDoubleValue float64
newBoolValue bool
)
exceptionPrt = (*uintptr)(getPtr(3))
args := ipc.NewArgumentList()
defer args.Clear()
args.SetString(0, fullName)
switch newValueType {
case V8_VALUE_STRING:
newStringValue = api.GoStr(getVal(2))
args.SetString(1, newStringValue)
case V8_VALUE_INT:
newIntValue = int32(getVal(2))
args.SetInt32(1, newIntValue)
case V8_VALUE_DOUBLE:
newDoubleValue = *(*float64)(getPtr(2))
args.SetFloat64(1, newDoubleValue)
case V8_VALUE_BOOLEAN:
newBoolValue = api.GoBool(getVal(2))
args.SetBool(1, newBoolValue)
default:
errorMessage = cefErrorMessage(CVE_ERROR_TYPE_NOT_SUPPORTED)
}
if errorMessage == Empty {
iCtx := ipc.IPC.Render().EmitAndReturn(ipc.Ln_SET_BIND_FIELD_VALUE, args)
if iCtx != nil {
args := iCtx.Arguments()
isSuccess := args.GetBool(0)
if !isSuccess {
exception := CEF_V8_EXCEPTION(args.GetInt8(1))
errorMessage = cefErrorMessage(exception)
}
iCtx.Free()
} else {
errorMessage = cefErrorMessage(CVE_ERROR_IPC_GET_BIND_FIELD_VALUE_FAIL)
}
}
*exceptionPrt = api.PascalStr(errorMessage)
} else if eventType == BE_GET { //获取值和set处理不一样需要在go里知道实际类型
var (
newValueType = (*V8_JS_VALUE_TYPE)(getPtr(1))
retStringValuePrt = (*uintptr)(getPtr(2))
retIntValuePrt = (*int32)(getPtr(3))
retDoubleValuePrt = (*float64)(getPtr(4))
retBoolValuePrt = (*bool)(getPtr(5))
)
exceptionPrt = (*uintptr)(getPtr(6))
args := ipc.NewArgumentList()
defer args.Clear()
args.SetString(0, fullName)
iCtx := ipc.IPC.Render().EmitAndReturn(ipc.Ln_GET_BIND_FIELD_VALUE, args)
if iCtx != nil {
data := iCtx.Message().Data()
isSuccess := common.ByteToBool(data[0])
valueType := V8_JS_VALUE_TYPE(common.ByteToInt8(data[1]))
if isSuccess {
errorMessage = getPtrValue(valueType, data[2:], retStringValuePrt, retIntValuePrt, retDoubleValuePrt, retBoolValuePrt)
} else {
exception := CEF_V8_EXCEPTION(int8(data[1]))
errorMessage = cefErrorMessage(exception)
}
if errorMessage == Empty {
*newValueType = valueType
}
iCtx.Free()
} else {
errorMessage = cefErrorMessage(CVE_ERROR_IPC_GET_BIND_FIELD_VALUE_FAIL)
}
*exceptionPrt = api.PascalStr(errorMessage)
}
}
// setPtrValue 设置指针值
func setPtrValue(jsValue JSValue, newValueType V8_JS_VALUE_TYPE, stringValue string, intValue int32, doubleValue float64, boolValue bool) CEF_V8_EXCEPTION {
if jsValue.isCommon() {
//valueType说明给的值类型不相同需要将 jsValue 转换一下
switch newValueType { //设置值这里是通用类型只需要知道js里设置的什么类型即可
case V8_VALUE_STRING:
jsValue.setValue(stringValue)
case V8_VALUE_INT:
jsValue.setValue(intValue)
case V8_VALUE_DOUBLE:
jsValue.setValue(doubleValue)
case V8_VALUE_BOOLEAN:
jsValue.setValue(boolValue)
default:
return CVE_ERROR_TYPE_NOT_SUPPORTED
}
jsValue.ValueType().Jsv = newValueType
} else { //object
if refValue, ok := jsValue.getValue().(*reflect.Value); !ok {
return CVE_ERROR_TYPE_INVALID
} else {
if newValueType == V8_VALUE_STRING && jsValue.ValueType().Jsv == V8_VALUE_STRING {
refValue.Set(reflect.ValueOf(stringValue))
} else if newValueType == V8_VALUE_INT && jsValue.ValueType().Jsv == V8_VALUE_INT {
refValue.SetInt(int64(intValue))
} else if newValueType == V8_VALUE_DOUBLE && jsValue.ValueType().Jsv == V8_VALUE_DOUBLE {
refValue.SetFloat(doubleValue)
} else if newValueType == V8_VALUE_BOOLEAN && jsValue.ValueType().Jsv == V8_VALUE_BOOLEAN {
refValue.SetBool(boolValue)
} else {
return CVE_ERROR_TYPE_NOT_SUPPORTED
}
}
}
return CVE_ERROR_OK
}
// getPtrValue 获取指针值
func getPtrValue(valueType V8_JS_VALUE_TYPE, newValue interface{}, stringValuePrt *uintptr, intValuePrt *int32, doubleValuePrt *float64, boolValuePrt *bool) string {
switch valueType {
case V8_VALUE_STRING:
if value, err := common.ValueToString(newValue); err == nil {
*stringValuePrt = api.PascalStr(value)
} else {
return cefErrorMessage(CVE_ERROR_GET_STRING_FAIL)
}
case V8_VALUE_INT:
if value, err := common.ValueToInt32(newValue); err == nil {
*intValuePrt = value
} else {
return cefErrorMessage(CVE_ERROR_GET_INT_FAIL)
}
case V8_VALUE_DOUBLE:
if value, err := common.ValueToFloat64(newValue); err == nil {
*doubleValuePrt = value
} else {
return cefErrorMessage(CVE_ERROR_GET_DOUBLE_FAIL)
}
case V8_VALUE_BOOLEAN:
if value, err := common.ValueToBool(newValue); err == nil {
*boolValuePrt = value
} else {
return cefErrorMessage(CVE_ERROR_GET_BOOL_FAIL)
}
case V8_VALUE_NULL:
case V8_VALUE_UNDEFINED:
default:
return cefErrorMessage(CVE_ERROR_TYPE_NOT_SUPPORTED)
}
return ""
}
// v8BindFuncCallbackHandler 函数处理
func v8BindFuncCallbackHandler(eventType BIND_EVENT, fullNamePtr uintptr, args uintptr, argsLen int) {
var (
exceptionPrt *uintptr
errorMessage = Empty
)
defer func() {
if err := recover(); err != nil {
logger.Error("V8BindFuncCallbackHandler recover:", err)
if exceptionPrt != nil {
*exceptionPrt = api.PascalStr(" " + (err.(error)).Error())
}
}
}()
getVal := func(i int) uintptr {
return common.GetParamOf(i, args)
}
getPtr := func(i int) unsafe.Pointer {
return unsafe.Pointer(getVal(i))
}
fullName := api.GoStr(fullNamePtr)
exceptionPrt = (*uintptr)(getPtr(1))
var jsValue, ok = VariableBind.bindValue(fullName)
var fnInfo *funcInfo
if !ok {
errorMessage = cefErrorMessage(CVE_ERROR_NOT_FOUND_FUNC)
return
}
fnInfo = jsValue.getFuncInfo()
if fnInfo != nil {
var (
inIdx = 0
i = 0
argsDefLen = int(2 + fnInfo.OutNum)
)
var (
outParams []reflect.Value
ok bool
inArgumentList ipc.IArgumentList
retStringValuePrt *uintptr
retIntValuePrt *int32
retDoubleValuePrt *float64
retBoolValuePrt *bool
outVType *VT
)
if fnInfo.OutNum == 2 {
argsDefLen++
if fnInfo.OutParam[0].Jsv == V8_VALUE_EXCEPTION {
outVType = fnInfo.OutParam[1]
} else {
outVType = fnInfo.OutParam[0]
}
} else if fnInfo.OutNum == 1 {
if fnInfo.OutParam[0].Jsv != V8_VALUE_EXCEPTION {
argsDefLen++
outVType = fnInfo.OutParam[0]
}
}
inArgumentList = ipc.NewArgumentList()
defer inArgumentList.Clear()
//遍历入参,并校验,默认参数结束下标位置开始
for inIdx = argsDefLen; inIdx < argsLen && i < len(fnInfo.InParam); inIdx++ {
i = inIdx - argsDefLen
inVType := fnInfo.InParam[i]
switch inVType.Jsv {
case V8_VALUE_STRING:
str := api.GoStr(getVal(inIdx))
inArgumentList.SetString(i, str)
case V8_VALUE_INT:
if value := common.NumberUintPtrToInt(getVal(inIdx), inVType.Gov); value != nil {
inArgumentList.SetIntAuto(i, value, inVType.Gov)
} else {
errorMessage = cefErrorMessage(CVE_ERROR_FUNC_GET_IN_PAM_INT_FAIL)
break
}
case V8_VALUE_DOUBLE:
if value := common.NumberPtrToFloat(getPtr(inIdx), inVType.Gov); value != nil {
inArgumentList.SetFloatAuto(i, value, inVType.Gov)
} else {
errorMessage = cefErrorMessage(CVE_ERROR_FUNC_GET_IN_PAM_DOUBLE_FAIL)
break
}
case V8_VALUE_BOOLEAN:
inArgumentList.SetBool(i, api.GoBool(getVal(inIdx)))
default:
//参数错误停止调用,返回
errorMessage = cefErrorMessage(CVE_ERROR_FUNC_IN_PAM)
break
}
}
//有出参时出参长度是2并校验
//出参的固定下标为2
if errorMessage == Empty && outVType != nil {
//得到出参的类型指针 出参的固定下标为2
switch outVType.Jsv {
case V8_VALUE_STRING:
retStringValuePrt = (*uintptr)(getPtr(2))
case V8_VALUE_INT:
retIntValuePrt = (*int32)(getPtr(2))
case V8_VALUE_DOUBLE:
retDoubleValuePrt = (*float64)(getPtr(2))
case V8_VALUE_BOOLEAN:
retBoolValuePrt = (*bool)(getPtr(2))
default:
errorMessage = cefErrorMessage(CVE_ERROR_FUNC_OUT_PAM)
break
}
}
if errorMessage == Empty {
if SingleProcess || common.Args.IsMain() {
outParams, ok = jsValue.invoke(inArgumentList.ToReflectValue())
} else {
ok = true
inArgumentList.SetString(inArgumentList.Size(), fullName)
var iCtx = ipc.IPC.Render().EmitAndReturn(ipc.Ln_EXECUTE_BIND_FUNC, inArgumentList)
if iCtx != nil {
var outArgument = ipc.NewArgumentList()
defer outArgument.Clear()
data := iCtx.Message().Data()
isSuccess := common.ByteToBool(data[0])
if isSuccess {
outArgument.UnPackage(data[1:])
outParams = outArgument.ToReflectValue()
} else {
exception := CEF_V8_EXCEPTION(int8(data[1]))
errorMessage = cefErrorMessage(exception)
}
iCtx.Free()
}
}
if ok {
if outVType != nil && len(outParams) > 0 &&
(retStringValuePrt != nil || retIntValuePrt != nil || retDoubleValuePrt != nil || retBoolValuePrt != nil) {
//出参处理
outParamValue := outParams[fnInfo.OutParamIdx]
switch outVType.Jsv {
case V8_VALUE_STRING:
if value, err := common.ValueToString(outParamValue.Interface()); err == nil {
*retStringValuePrt = api.PascalStr(value)
} else {
errorMessage = cefErrorMessage(CVE_ERROR_FUNC_GET_OUT_PAM_STRING_FAIL)
}
case V8_VALUE_INT:
if value, err := common.ValueToInt32(outParamValue.Interface()); err == nil {
*retIntValuePrt = value
} else {
errorMessage = cefErrorMessage(CVE_ERROR_FUNC_GET_OUT_PAM_INT_FAIL)
}
case V8_VALUE_DOUBLE:
if value, err := common.ValueToFloat64(outParamValue.Interface()); err == nil {
*retDoubleValuePrt = value
} else {
errorMessage = cefErrorMessage(CVE_ERROR_FUNC_GET_OUT_PAM_DOUBLE_FAIL)
}
case V8_VALUE_BOOLEAN:
if value, err := common.ValueToBool(outParamValue.Interface()); err == nil {
*retBoolValuePrt = value
} else {
errorMessage = cefErrorMessage(CVE_ERROR_FUNC_GET_OUT_PAM_BOOLEAN_FAIL)
}
default:
errorMessage = cefErrorMessage(CVE_ERROR_FUNC_OUT_PAM)
break
}
}
} else {
errorMessage = cefErrorMessage(CVE_ERROR_UNKNOWN_ERROR)
}
}
} else {
errorMessage = cefErrorMessage(CVE_ERROR_NOT_FOUND_FUNC)
}
*exceptionPrt = api.PascalStr(errorMessage)
}