mirror of
https://gitee.com/energye/energy.git
synced 2024-11-30 10:47:57 +08:00
467 lines
14 KiB
Go
467 lines
14 KiB
Go
//----------------------------------------
|
||
//
|
||
// Copyright © yanghy. All Rights Reserved.
|
||
//
|
||
// Licensed under Apache License Version 2.0, January 2004
|
||
//
|
||
// https://www.apache.org/licenses/LICENSE-2.0
|
||
//
|
||
//----------------------------------------
|
||
|
||
// energy 渲染进程 IPC
|
||
package cef
|
||
|
||
import (
|
||
"bytes"
|
||
"fmt"
|
||
"github.com/energye/energy/consts"
|
||
"github.com/energye/energy/ipc/channel"
|
||
"github.com/energye/energy/pkgs/json"
|
||
jsoniter "github.com/json-iterator/go"
|
||
"sync"
|
||
)
|
||
|
||
// ipcRenderProcess 渲染进程
|
||
type ipcRenderProcess struct {
|
||
bind *ICefV8Value // go bind
|
||
ipcObject *ICefV8Value // ipc object
|
||
emitHandler *ipcEmitHandler // ipc.emit handler
|
||
onHandler *ipcOnHandler // ipc.on handler
|
||
ipcChannel channel.IRenderChannel //channel
|
||
browserId int32
|
||
frameId int64
|
||
buffer *bytes.Buffer
|
||
lock sync.Mutex
|
||
}
|
||
|
||
func (m *ipcRenderProcess) clear() {
|
||
if m.bind != nil {
|
||
m.bind.Free()
|
||
m.bind = nil
|
||
}
|
||
if m.ipcObject != nil {
|
||
m.ipcObject.Free()
|
||
m.ipcObject = nil
|
||
}
|
||
//if m.onHandler != nil {
|
||
// m.onHandler.clear()
|
||
//}
|
||
}
|
||
|
||
func (m *ipcRenderProcess) ipcChannelRender(browser *ICefBrowser, frame *ICefFrame) {
|
||
if m.ipcChannel == nil {
|
||
m.browserId = browser.Identifier()
|
||
m.frameId = frame.Identifier()
|
||
m.ipcChannel = channel.NewRender(m.frameId)
|
||
m.ipcChannel.Handler(func(context channel.IIPCContext) {
|
||
fmt.Println("ipcRender", m.browserId, context.Message().JSON().Size(), context.ChannelId(), context.ToChannelId())
|
||
context.Free()
|
||
})
|
||
//go func() {
|
||
// for true {
|
||
// time.Sleep(time.Second)
|
||
// m.ipcChannel.Send([]byte("aaa"))
|
||
// }
|
||
//}()
|
||
}
|
||
}
|
||
|
||
// makeCtx ipc 和 bind
|
||
func (m *ipcRenderProcess) makeCtx(context *ICefV8Context) {
|
||
m.makeIPC(context)
|
||
//m.makeBind(context)
|
||
}
|
||
|
||
// makeIPC ipc
|
||
func (m *ipcRenderProcess) makeIPC(context *ICefV8Context) {
|
||
// ipc emit
|
||
m.emitHandler.handler = V8HandlerRef.New()
|
||
m.emitHandler.handler.Execute(m.ipcJSExecuteGoEvent)
|
||
// ipc on
|
||
m.onHandler.handler = V8HandlerRef.New()
|
||
m.onHandler.handler.Execute(m.ipcJSOnEvent)
|
||
// ipc object
|
||
m.ipcObject = V8ValueRef.NewObject(nil)
|
||
m.ipcObject.setValueByKey(internalEmit, V8ValueRef.newFunction(internalEmit, m.emitHandler.handler), consts.V8_PROPERTY_ATTRIBUTE_READONLY)
|
||
m.ipcObject.setValueByKey(internalOn, V8ValueRef.newFunction(internalOn, m.onHandler.handler), consts.V8_PROPERTY_ATTRIBUTE_READONLY)
|
||
// global to v8 ipc key
|
||
context.Global().setValueByKey(internalIPCKey, m.ipcObject, consts.V8_PROPERTY_ATTRIBUTE_READONLY)
|
||
}
|
||
|
||
// ipcJSOnEvent JS ipc.on 监听事件
|
||
func (m *ipcRenderProcess) ipcJSOnEvent(name string, object *ICefV8Value, arguments *TCefV8ValueArray, retVal *ResultV8Value, exception *ResultString) (result bool) {
|
||
if name != internalOn {
|
||
retVal.SetResult(V8ValueRef.NewBool(false))
|
||
return
|
||
} else if arguments.Size() != 2 { //必须是2个参数
|
||
retVal.SetResult(V8ValueRef.NewBool(false))
|
||
exception.SetValue("ipc.on parameter should be 2 quantity")
|
||
arguments.Free()
|
||
return
|
||
}
|
||
var (
|
||
onName *ICefV8Value // 事件名
|
||
onNameValue string // 事件名
|
||
onCallback *ICefV8Value // 事件回调函数
|
||
)
|
||
onName = arguments.Get(0)
|
||
//事件名 第一个参数必须是字符串
|
||
if !onName.IsString() {
|
||
retVal.SetResult(V8ValueRef.NewBool(false))
|
||
exception.SetValue("ipc.on event name should be a string")
|
||
return
|
||
}
|
||
onCallback = arguments.Get(1)
|
||
//第二个参数必须是函数
|
||
if !onCallback.IsFunction() {
|
||
retVal.SetResult(V8ValueRef.NewBool(false))
|
||
exception.SetValue("ipc.on event callback should be a function")
|
||
return
|
||
}
|
||
onCallback.SetCanNotFree(true)
|
||
onNameValue = onName.GetStringValue()
|
||
//ipc on
|
||
m.onHandler.addCallback(onNameValue, &ipcCallback{ /*arguments: arguments, */ context: V8ContextRef.Current(), function: V8ValueRef.UnWrap(onCallback)})
|
||
result = true
|
||
return
|
||
}
|
||
|
||
var s bool
|
||
|
||
// ipcGoExecuteJSEvent Go ipc.emit 执行JS事件
|
||
func (m *ipcRenderProcess) ipcGoExecuteJSEvent(browser *ICefBrowser, frame *ICefFrame, sourceProcess consts.CefProcessId, message *ICefProcessMessage) (result bool) {
|
||
//argument := message.ArgumentList()
|
||
if s {
|
||
fmt.Println("ipcGoExecuteJSEvent s", s)
|
||
}
|
||
s = true
|
||
defer func() {
|
||
s = false
|
||
}()
|
||
argumentListBytes := message.ArgumentList().GetBinary(0)
|
||
var messageDataBytes []byte
|
||
if argumentListBytes.IsValid() {
|
||
size := argumentListBytes.GetSize()
|
||
messageDataBytes = make([]byte, size)
|
||
c := argumentListBytes.GetData(messageDataBytes, 0)
|
||
argumentListBytes.Free() //立即释放掉
|
||
message.Free()
|
||
if c == 0 {
|
||
result = false
|
||
return
|
||
}
|
||
}
|
||
var messageId int32
|
||
var emitName string
|
||
var argument json.JSON
|
||
var argumentList json.JSONArray
|
||
if messageDataBytes != nil {
|
||
argument = json.NewJSON(messageDataBytes)
|
||
messageId = int32(argument.GetIntByKey(ipc_id))
|
||
emitName = argument.GetStringByKey(ipc_event)
|
||
argumentList = argument.GetArrayByKey(ipc_argumentList)
|
||
messageDataBytes = nil
|
||
}
|
||
defer func() {
|
||
if argument != nil {
|
||
argument.Free()
|
||
}
|
||
}()
|
||
|
||
if callback := ipcRender.onHandler.getCallback(emitName); callback != nil {
|
||
//if callback.context.Enter() {
|
||
fmt.Println("messageId:", messageId)
|
||
//1
|
||
//argumentArrayValue, _ := ipcValueConvert.BytesToV8ArrayValue(argumentList.Bytes())
|
||
//fmt.Println("messageId", messageId, "err", err, argumentArrayValue)
|
||
//ret := callback.function.ExecuteFunctionWithContext(callback.context, nil, argumentArrayValue)
|
||
//argumentArrayValue.Free()
|
||
//2
|
||
argumentArrayValue := ipcValueConvert.BytesToV8ValueArray(argumentList.Bytes())
|
||
ret := callback.function.ExecuteFunctionWithContext(callback.context, nil, argumentArrayValue)
|
||
argumentArrayValue.Free()
|
||
//3
|
||
//ret := callback.function.ExecuteFunctionWithContextForArgsBytes(callback.context, nil, argumentList.Bytes())
|
||
argumentList.Free()
|
||
//fmt.Println("messageId", messageId, "ret", ret)
|
||
//if messageId != 0 { // callback
|
||
//ipcValueConvert.V8ValueToProcessMessage(ret)
|
||
//ret := V8ValueRef.NewString("字符串")
|
||
frame.SendProcessMessageForV8Value(internalProcessMessageIPCEmitReply, consts.PID_BROWSER, ret)
|
||
|
||
//var retBytes []byte
|
||
//retBytes = ipcValueConvert.V8ValueToProcessMessageBytes(ret)
|
||
//retMessage := ProcessMessageRef.new(internalProcessMessageIPCEmitReply)
|
||
//if len(retBytes) > 0 {
|
||
// retMessage.ArgumentList().SetBinary(0, BinaryValueRef.New(retBytes))
|
||
// retBytes = nil
|
||
//}
|
||
//frame.SendProcessMessage(consts.PID_BROWSER, retMessage)
|
||
//retMessage.Free()
|
||
//}
|
||
//ret.Free()
|
||
callback.context.Exit()
|
||
//frame.SendProcessMessageForV8Value(internalProcessMessageIPCEmitReply, consts.PID_BROWSER, ret)
|
||
//}
|
||
result = true
|
||
}
|
||
return
|
||
}
|
||
|
||
// ipcJSExecuteGoEvent JS ipc.emit 执行Go事件
|
||
func (m *ipcRenderProcess) ipcJSExecuteGoEvent(name string, object *ICefV8Value, arguments *TCefV8ValueArray, retVal *ResultV8Value, exception *ResultString) (result bool) {
|
||
var (
|
||
emitName *ICefV8Value //事件名
|
||
emitNameValue string //事件名
|
||
emitArgs *ICefV8Value //事件参数
|
||
emitCallback *ICefV8Value //事件回调函数
|
||
args any
|
||
freeV8Value = func(value *ICefV8Value) {
|
||
if value != nil {
|
||
value.Free()
|
||
}
|
||
}
|
||
)
|
||
result = true
|
||
isFree := false
|
||
defer func() {
|
||
if isFree { //失败时释放掉
|
||
result = false
|
||
freeV8Value(emitCallback)
|
||
}
|
||
}()
|
||
if name != internalEmit {
|
||
isFree = true
|
||
return
|
||
}
|
||
if arguments.Size() >= 1 { // 1 ~ 3 个参数
|
||
defer func() {
|
||
//释放掉这些指针,不然不会自动释放
|
||
freeV8Value(emitName)
|
||
freeV8Value(emitArgs)
|
||
if args != nil {
|
||
args = nil
|
||
}
|
||
}()
|
||
emitName = arguments.Get(0)
|
||
if !emitName.IsString() {
|
||
exception.SetValue("ipc.emit event name should be a string")
|
||
isFree = true
|
||
return
|
||
}
|
||
if arguments.Size() == 2 {
|
||
args2 := arguments.Get(1)
|
||
if args2.IsArray() {
|
||
emitArgs = args2
|
||
} else if args2.IsFunction() {
|
||
emitCallback = args2
|
||
} else {
|
||
exception.SetValue("ipc.emit second argument can only be a parameter or callback function")
|
||
isFree = true
|
||
return
|
||
}
|
||
} else if arguments.Size() == 3 {
|
||
emitArgs = arguments.Get(1)
|
||
emitCallback = arguments.Get(2)
|
||
if !emitArgs.IsArray() || !emitCallback.IsFunction() {
|
||
exception.SetValue("ipc.emit second argument can only be a input parameter. third parameter can only be a callback function")
|
||
isFree = true
|
||
return
|
||
}
|
||
}
|
||
emitNameValue = emitName.GetStringValue()
|
||
//入参
|
||
if emitArgs != nil {
|
||
//V8Value 转换
|
||
args = ipcValueConvert.V8ValueToProcessMessageArray(emitArgs)
|
||
if args == nil {
|
||
exception.SetValue("ipc.emit convert parameter to value value error")
|
||
isFree = true
|
||
return
|
||
}
|
||
}
|
||
context := V8ContextRef.Current()
|
||
var messageId int32 = 0
|
||
//回调函数
|
||
if emitCallback != nil {
|
||
//回调函数临时存放到缓存中
|
||
emitCallback.SetCanNotFree(true)
|
||
messageId = ipcRender.emitHandler.addCallback(&ipcCallback{
|
||
//arguments: arguments,
|
||
context: context,
|
||
function: V8ValueRef.UnWrap(emitCallback),
|
||
})
|
||
}
|
||
|
||
//frame := context.Frame()
|
||
//message := json.NewJSONObject(nil)
|
||
//message.Set(ipc_id, messageId)
|
||
//message.Set(ipc_name, internalIPCJSExecuteGoEvent)
|
||
//message.Set(ipc_event, emitNameValue)
|
||
//message.Set(ipc_argumentList, json.NewJSONArray(args).Data())
|
||
//frame.SendProcessMessageForJSONBytes(internalIPCJSExecuteGoEvent, consts.PID_BROWSER, message.Bytes())
|
||
data := &ipcChannelMessage{
|
||
MessageId: messageId,
|
||
BrowserId: m.browserId,
|
||
FrameId: m.frameId,
|
||
Name: internalIPCJSExecuteGoEvent,
|
||
EventName: emitNameValue,
|
||
Data: args,
|
||
}
|
||
if sendData, err := jsoniter.Marshal(data); err == nil {
|
||
m.ipcChannel.Send(sendData)
|
||
}
|
||
//message.Free()
|
||
//frame.Free()
|
||
args = nil
|
||
//context.Free() // TODO dev
|
||
retVal.SetResult(V8ValueRef.NewBool(true))
|
||
}
|
||
return
|
||
}
|
||
|
||
// ipcJSExecuteGoEventMessageReply JS执行Go监听,Go的消息回复
|
||
func (m *ipcRenderProcess) ipcJSExecuteGoEventMessageReply(browser *ICefBrowser, frame *ICefFrame, sourceProcess consts.CefProcessId, message *ICefProcessMessage) (result bool) {
|
||
result = true
|
||
argumentListBytes := message.ArgumentList().GetBinary(0)
|
||
var messageDataBytes []byte
|
||
if argumentListBytes.IsValid() {
|
||
size := argumentListBytes.GetSize()
|
||
messageDataBytes = make([]byte, size)
|
||
c := argumentListBytes.GetData(messageDataBytes, 0)
|
||
argumentListBytes.Free() //立即释放掉
|
||
if c == 0 {
|
||
result = false
|
||
return
|
||
}
|
||
}
|
||
var (
|
||
messageId int32
|
||
isReturnArgs bool
|
||
argumentList json.JSONArray
|
||
)
|
||
if messageDataBytes != nil {
|
||
argumentList = json.NewJSONArray(messageDataBytes)
|
||
messageId = int32(argumentList.GetIntByIndex(0))
|
||
isReturnArgs = argumentList.GetBoolByIndex(1)
|
||
messageDataBytes = nil
|
||
}
|
||
defer func() {
|
||
if argumentList != nil {
|
||
argumentList.Free()
|
||
}
|
||
}()
|
||
|
||
if callback := ipcRender.emitHandler.getCallback(messageId); callback != nil {
|
||
callback.function.SetCanNotFree(false)
|
||
//第二个参数 true 有返回参数
|
||
if isReturnArgs {
|
||
//[]byte
|
||
returnArgs := argumentList.GetArrayByIndex(2)
|
||
//解析 '[]byte' 参数
|
||
if callback.context.Enter() {
|
||
callback.function.ExecuteFunctionWithContextForArgsBytes(callback.context, nil, returnArgs.Bytes()).Free()
|
||
callback.context.Exit()
|
||
}
|
||
returnArgs.Free()
|
||
} else { //无返回参数
|
||
if callback.context.Enter() {
|
||
callback.function.ExecuteFunctionWithContext(callback.context, nil, nil).Free()
|
||
}
|
||
callback.context.Exit()
|
||
}
|
||
//remove
|
||
callback.free()
|
||
}
|
||
return
|
||
}
|
||
|
||
// makeBind bind object accessor
|
||
func (m *ipcRenderProcess) makeBind(context *ICefV8Context) {
|
||
var (
|
||
bindRootObjectAccessor *ICefV8Accessor // bind accessor
|
||
bindSubObjectAccessor *ICefV8Accessor // bind sub object accessor
|
||
bindFuncHandler *ICefV8Handler // bind func handler
|
||
)
|
||
bindRootObjectAccessor = V8AccessorRef.New()
|
||
bindRootObjectAccessor.Get(m.bindGet)
|
||
bindRootObjectAccessor.Set(m.bindSet)
|
||
// bind object
|
||
m.bind = V8ValueRef.NewObject(bindRootObjectAccessor)
|
||
|
||
fmt.Println("\tbindCount", VariableBind.bindCount())
|
||
binds := VariableBind.binds()
|
||
for name, value := range binds {
|
||
fmt.Println("\t", name, "\t", value.ValueType().ToString())
|
||
var v8value *ICefV8Value
|
||
if value.IsFunction() {
|
||
if bindFuncHandler == nil {
|
||
bindFuncHandler = V8HandlerRef.New()
|
||
bindFuncHandler.Execute(m.bindFuncExecute)
|
||
}
|
||
v8value = V8ValueRef.newFunction(name, bindFuncHandler)
|
||
m.bind.setValueByKey(name, v8value, consts.V8_PROPERTY_ATTRIBUTE_NONE)
|
||
} else {
|
||
if value.IsString() {
|
||
v8value = V8ValueRef.NewString("")
|
||
} else if value.IsInteger() {
|
||
v8value = V8ValueRef.NewInt(0)
|
||
} else if value.IsDouble() {
|
||
v8value = V8ValueRef.NewDouble(0.0)
|
||
} else if value.IsBool() {
|
||
v8value = V8ValueRef.NewBool(false)
|
||
} else if value.IsNull() {
|
||
v8value = V8ValueRef.NewNull()
|
||
} else if value.IsUndefined() {
|
||
v8value = V8ValueRef.NewUndefined()
|
||
} else if value.IsObject() {
|
||
if bindSubObjectAccessor == nil {
|
||
bindSubObjectAccessor = V8AccessorRef.New()
|
||
bindSubObjectAccessor.Get(m.bindSubObjectGet)
|
||
bindSubObjectAccessor.Set(m.bindSubObjectSet)
|
||
}
|
||
v8value = V8ValueRef.NewObject(bindSubObjectAccessor)
|
||
} else if value.IsArray() {
|
||
v8value = V8ValueRef.NewArray(0)
|
||
}
|
||
if v8value != nil {
|
||
m.bind.setValueByAccessor(name, consts.V8_ACCESS_CONTROL_DEFAULT, consts.V8_PROPERTY_ATTRIBUTE_NONE)
|
||
m.bind.setValueByKey(name, v8value, consts.V8_PROPERTY_ATTRIBUTE_NONE)
|
||
}
|
||
}
|
||
}
|
||
|
||
// global to v8 bind objectRootName
|
||
context.Global().setValueByKey(internalObjectRootName, m.bind, consts.V8_PROPERTY_ATTRIBUTE_NONE)
|
||
}
|
||
|
||
// bindFuncExecute 绑定函数执行
|
||
func (m *ipcRenderProcess) bindFuncExecute(name string, object *ICefV8Value, arguments *TCefV8ValueArray, retVal *ResultV8Value, exception *ResultString) bool {
|
||
fmt.Println("bindFuncExecute handler name:", name)
|
||
return false
|
||
}
|
||
|
||
// bindSubObjectGet 绑定对象取值
|
||
func (m *ipcRenderProcess) bindSubObjectGet(name string, object *ICefV8Value, retVal *ResultV8Value, exception *ResultString) bool {
|
||
fmt.Println("bindSubObjectGet accessor name:", name)
|
||
return false
|
||
}
|
||
|
||
// bindSubObjectSet 绑定对象赋值
|
||
func (m *ipcRenderProcess) bindSubObjectSet(name string, object *ICefV8Value, value *ICefV8Value, exception *ResultString) bool {
|
||
fmt.Println("bindSubObjectSet accessor name:", name)
|
||
return false
|
||
}
|
||
|
||
// bindGet 绑定字段取值
|
||
func (m *ipcRenderProcess) bindGet(name string, object *ICefV8Value, retVal *ResultV8Value, exception *ResultString) bool {
|
||
fmt.Println("bindGet accessor name:", name)
|
||
return false
|
||
}
|
||
|
||
// bindSet 绑定字段赋值
|
||
func (m *ipcRenderProcess) bindSet(name string, object *ICefV8Value, value *ICefV8Value, exception *ResultString) bool {
|
||
fmt.Println("bindSet accessor name:", name)
|
||
return false
|
||
}
|