A: JS ipc.on options: mode

This commit is contained in:
杨红岩 2024-10-15 12:04:21 +08:00
parent 05a7690506
commit cad0352bde
2 changed files with 128 additions and 22 deletions

View File

@ -14,6 +14,8 @@ package cef
import (
"github.com/energye/energy/v2/cef/internal/ipc"
ipcArgument "github.com/energye/energy/v2/cef/ipc/argument"
"github.com/energye/energy/v2/cef/ipc/types"
"github.com/energye/energy/v2/cef/process"
"sync"
"time"
@ -70,11 +72,13 @@ type ipcOnHandler struct {
// ipc.emit 回调结果
type ipcCallback struct {
isSync bool //同否同步 true:同步 false:异步, 默认false
resultType result_type //返回值类型 0:function 1:variable 默认:0
variable *ICefV8Value //回调函数, 根据 resultType
function *ICefV8Value //回调函数, 根据 resultType
name *ICefV8Value //事件名称
isSync bool //同否同步 true:同步 false:异步, 默认false
resultType result_type //返回值类型 0:function 1:variable 默认:0
variable *ICefV8Value //回调函数, 根据 resultType
function *ICefV8Value //回调函数, 根据 resultType
name *ICefV8Value //事件名称
mode types.Mode //监听模式
asyncHandler *asyncGoExecuteJSHandler //监听模式为 MAsync
}
// IPC 内部定义使用 key 不允许使用
@ -193,3 +197,75 @@ func (m *ipcOnHandler) clear() {
}
m.callbackList = make(map[string]*ipcCallback)
}
// JS: ipc.on 异步模式完成事件处理
type asyncGoExecuteJSHandler struct {
handler *ICefV8Handler
callback *ICefV8Value
}
// 返回一个新的 asyncGoExecuteJSHandler
func newAsyncGoExecuteJSHandler() *asyncGoExecuteJSHandler {
asyncHandler := &asyncGoExecuteJSHandler{
handler: V8HandlerRef.New(),
}
// 创建处理器函数, 在异步监听模式时使用
asyncHandler.handler.Execute(asyncHandler.asyncHandler)
asyncHandler.callback = V8ValueRef.NewFunction("callback", asyncHandler.handler)
asyncHandler.callback.SetCanNotFree(true)
return asyncHandler
}
func (m *asyncGoExecuteJSHandler) free() {
if m.callback != nil {
m.callback.Free()
m.callback = nil
}
}
// Js: ipc.on 异步监听模式完成处理器
func (m *asyncGoExecuteJSHandler) asyncHandler(name string, object *ICefV8Value, arguments *TCefV8ValueArray, retVal *ResultV8Value, exception *ResultString) bool {
idValue := object.GetValueByKey("id")
defer idValue.Free()
messageId := idValue.GetIntValue()
size := arguments.Size()
result := make([]interface{}, size)
for i := 0; i < size; i++ {
tempVal := arguments.Get(i)
if !tempVal.IsValid() {
result[i] = nil
continue
}
isObject := tempVal.IsObject() || tempVal.IsArray()
callbackArgsBytes := ValueConvert.V8ValueToProcessMessageArray(tempVal)
tempVal.Free()
if isObject {
result[i] = callbackArgsBytes
} else {
if val, ok := callbackArgsBytes.([]interface{}); ok && len(val) == 1 {
result[i] = callbackArgsBytes.([]interface{})[0]
} else {
result[i] = nil
}
}
}
replayGoExecuteJSEvent(messageId, result)
return true
}
func replayGoExecuteJSEvent(messageId int32, callbackArgsBytes interface{}) {
if messageId != 0 {
callbackMessage := &ipcArgument.List{
Id: messageId,
BId: ipc.RenderChan().BrowserId(),
Name: internalIPCGoExecuteJSEventReplay,
}
if callbackArgsBytes != nil {
callbackMessage.Data = callbackArgsBytes //json.NewJSONArray(callbackArgsBytes).Data()
}
// send ipc message
// send bytes data to browser ipc
ipc.RenderChan().IPC().Send(callbackMessage.Bytes())
callbackMessage.Reset()
}
}

View File

@ -18,6 +18,7 @@ import (
ipcArgument "github.com/energye/energy/v2/cef/ipc/argument"
"github.com/energye/energy/v2/cef/ipc/context"
"github.com/energye/energy/v2/cef/ipc/target"
"github.com/energye/energy/v2/cef/ipc/types"
"github.com/energye/energy/v2/consts"
"github.com/energye/energy/v2/pkgs/json"
"time"
@ -47,9 +48,10 @@ func (m *ipcRenderProcess) clear(frameId int64) {
// JS ipc.on 监听事件
func (m *ipcOnHandler) jsOnEvent(name string, object *ICefV8Value, arguments *TCefV8ValueArray, retVal *ResultV8Value, exception *ResultString) (result bool) {
var size int
if name != internalIPCOn {
return
} else if arguments.Size() != 2 { //必须是2个参数
} else if size = arguments.Size(); !(size >= 2 && size <= 3) { //必须是2 | 3个参数
exception.SetValue("ipc.on parameter should be 2 quantity")
arguments.Free()
return
@ -73,11 +75,37 @@ func (m *ipcOnHandler) jsOnEvent(name string, object *ICefV8Value, arguments *TC
arguments.Free()
return
}
//监听选项, 第三个参数
options := arguments.Get(2)
if size == 3 && !options.IsObject() {
exception.SetValue("ipc.on event options should be a object")
arguments.Free()
return
}
retVal.SetResult(V8ValueRef.NewBool(true))
onCallback.SetCanNotFree(true)
onNameValue = onName.GetStringValue()
//ipc on
m.addCallback(onNameValue, &ipcCallback{function: V8ValueRef.UnWrap(onCallback), name: V8ValueRef.UnWrap(onName)})
callback := &ipcCallback{
function: V8ValueRef.UnWrap(onCallback),
name: V8ValueRef.UnWrap(onName),
}
// 监听模式JS: ipc.on 监听事件 options 模式(mode)值是 MAsync(1)时,在回调函数的参数列表最后一个参数 complete 对象
if size == 3 && options.IsValid() {
modeValue := options.GetValueByKey("mode")
if modeValue.IsValid() {
callback.mode = types.Mode(modeValue.GetIntValue())
modeValue.Free()
}
options.Free()
if callback.mode == types.MAsync {
callback.asyncHandler = newAsyncGoExecuteJSHandler()
}
}
//ipc on, 添加到维护集合
m.addCallback(onNameValue, callback)
result = true
return
}
@ -139,6 +167,17 @@ func (m *ipcRenderProcess) ipcGoExecuteJSEvent(browser *ICefBrowser, frame *ICef
//bytes to v8array value
argsArray, err = ValueConvert.BytesToV8ArrayValue(argumentList.Bytes())
}
// MAsync: 异步模式
if callback.mode == types.MAsync {
if argsArray == nil {
argsArray = V8ValueArrayRef.New()
}
complete := V8ValueRef.NewObject(nil)
complete.SetValueByKey("callback", callback.asyncHandler.callback, consts.V8_PROPERTY_ATTRIBUTE_READONLY)
complete.SetValueByKey("id", V8ValueRef.NewInt(messageId), consts.V8_PROPERTY_ATTRIBUTE_READONLY)
argsArray.Add(complete)
}
// 执行事件函数
if argsArray != nil && err == nil {
// parse v8array success
ret = callback.function.ExecuteFunctionWithContext(ctx, nil, argsArray)
@ -147,7 +186,8 @@ func (m *ipcRenderProcess) ipcGoExecuteJSEvent(browser *ICefBrowser, frame *ICef
// parse v8array fail
ret = callback.function.ExecuteFunctionWithContext(ctx, nil, nil)
}
if ret != nil && ret.IsValid() && messageId != 0 { // messageId != 0 callback func args
// MSync: 同步模式
if callback.mode == types.MSync && ret != nil && ret.IsValid() && messageId != 0 { // messageId != 0 callback func args
// v8value to process message bytes
callbackArgsBytes = ValueConvert.V8ValueToProcessMessageArray(ret)
ret.Free()
@ -158,19 +198,9 @@ func (m *ipcRenderProcess) ipcGoExecuteJSEvent(browser *ICefBrowser, frame *ICef
ctx.Exit()
}
ctx.Free()
if messageId != 0 { //messageId != 0 callback func
callbackMessage := &ipcArgument.List{
Id: messageId,
BId: ipc.RenderChan().BrowserId(),
Name: internalIPCGoExecuteJSEventReplay,
}
if callbackArgsBytes != nil {
callbackMessage.Data = callbackArgsBytes //json.NewJSONArray(callbackArgsBytes).Data()
}
// send ipc message
// send bytes data to browser ipc
ipc.RenderChan().IPC().Send(callbackMessage.Bytes())
callbackMessage.Reset()
// MSync: 同步模式
if callback.mode == types.MSync {
replayGoExecuteJSEvent(messageId, callbackArgsBytes)
}
}
return