energy/pkgs/channel/channel.go

433 lines
11 KiB
Go
Raw Normal View History

2023-03-19 00:00:09 +08:00
//----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// Licensed under Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
//----------------------------------------
2023-05-31 17:41:14 +08:00
// IPC Channel
// Communication between multiple processes
2023-03-20 10:09:54 +08:00
package channel
2023-03-19 00:00:09 +08:00
import (
"bytes"
"encoding/binary"
"errors"
2023-05-31 18:00:34 +08:00
"github.com/energye/energy/v2/cef/process"
"github.com/energye/energy/v2/common"
. "github.com/energye/energy/v2/consts"
"github.com/energye/energy/v2/logger"
"github.com/energye/energy/v2/pkgs/json"
2023-03-19 00:00:09 +08:00
"github.com/energye/golcl/lcl/rtl/version"
"math"
"net"
"os"
"path/filepath"
)
var (
2023-05-31 17:41:14 +08:00
protocolHeader = []byte{0x01, 0x09, 0x08, 0x07, 0x00, 0x08, 0x02, 0x02} // 协议头
protocolHeaderLength = int32(len(protocolHeader)) // 协议头长度
messageTypeLength = int32(1) // 消息类型 int8
processIdLength = int32(1) // 消息来源 int8
channelIdLength = int32(8) // 发送通道 int64
toChannelIdLength = int32(8) // 接收通道 int64
dataByteLength = int32(4) // 数据长度 int32
headerLength = int(protocolHeaderLength + messageTypeLength + processIdLength + channelIdLength + toChannelIdLength + dataByteLength) // 协议头长度
2023-03-19 00:00:09 +08:00
)
var (
2023-03-20 10:09:54 +08:00
memoryAddress = "energy.sock" //
ipcSock string // sock path
useNetIPCChannel = false //
2023-03-23 11:10:35 +08:00
port = 19878 // net ipc default: 19878
2023-03-19 00:00:09 +08:00
)
2023-03-19 21:44:39 +08:00
//mt 消息类型
2023-03-19 00:00:09 +08:00
type mt int8
const (
2023-05-31 17:41:14 +08:00
mt_invalid mt = iota - 1 // 无效类型
mt_connection // 建立链接消息
mt_connectd // 已链接消息
mt_update_channel_id // 更新通道ID消息
mt_common // 普通消息
mt_relay // 转发消息
2023-03-19 00:00:09 +08:00
)
2023-03-19 21:48:24 +08:00
// IPCCallback 回调
2023-03-19 01:31:30 +08:00
type IPCCallback func(context IIPCContext)
2023-03-19 00:00:09 +08:00
func init() {
ipcSock = filepath.Join(os.TempDir(), memoryAddress)
}
2023-03-19 01:31:30 +08:00
func removeMemory() {
os.Remove(ipcSock)
}
func UseNetIPCChannel() bool {
return useNetIPCChannel
}
func MemoryAddress() string {
return memoryAddress
}
func isUseNetIPC() bool {
if common.IsDarwin() || common.IsLinux() {
return false
}
ov := version.OSVersion
if (ov.Major > 10) || (ov.Major == 10 && ov.Build >= 17063) {
return false
}
return true
}
2023-05-31 17:41:14 +08:00
// SetPort 设置 net socket 端口号, 如参数 "v" 非指定范围内端口则获取随机未使用端口号
2023-03-23 11:07:24 +08:00
//
// v 1024 ~ 65535
func SetPort(v int) {
if v >= 1024 && v < 65535 {
port = v
} else {
port = 0
port = Port()
}
}
2023-03-19 01:31:30 +08:00
// Port 获取并返回net socket端口
2023-03-20 10:09:54 +08:00
func Port() int {
if port != 0 {
return port
2023-03-19 00:00:09 +08:00
}
//主进程获取端口号
2023-05-31 17:41:14 +08:00
if process.Args.IsMain() {
2023-03-19 00:00:09 +08:00
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
if err != nil {
panic("Failed to Get unused Port number Error: " + err.Error())
}
listen, err := net.ListenTCP("tcp", addr)
if err != nil {
panic("Failed to Get unused Port number Error: " + err.Error())
}
defer listen.Close()
2023-03-20 10:09:54 +08:00
port = listen.Addr().(*net.TCPAddr).Port
2023-03-19 00:00:09 +08:00
}
2023-03-20 10:09:54 +08:00
return port
2023-03-19 00:00:09 +08:00
}
2023-03-19 01:31:30 +08:00
// IIPCContext IPC通信回调上下文
2023-03-19 00:00:09 +08:00
type IIPCContext interface {
2023-05-31 17:41:14 +08:00
Connect() net.Conn // IPC 通道链接
ChannelId() int64 // 返回 发送通道ID
ToChannelId() int64 // 返回 接收发送通道ID
ChannelType() ChannelType // 返回 当前通道类型
ProcessId() CefProcessId // 返回 通道消息来源
Message() IMessage // 消息
Free() //
2023-03-19 00:00:09 +08:00
}
2023-03-19 01:31:30 +08:00
// IMessage 消息内容接口
2023-03-19 00:00:09 +08:00
type IMessage interface {
2023-03-20 09:11:57 +08:00
Type() mt // 消息类型
2023-05-31 17:41:14 +08:00
Length() int32 // 数据长度
2023-03-20 09:11:57 +08:00
Data() []byte // 数据
JSON() json.JSON // 转为 JSON 对象并返回
clear() // 清空
2023-03-19 00:00:09 +08:00
}
2023-03-19 22:40:10 +08:00
// IChannel 通道链接
type IChannel interface {
IsConnect() bool
Close()
read(b []byte) (n int, err error)
2023-03-20 09:11:57 +08:00
write(messageType mt, channelId, toChannelId int64, data []byte) (n int, err error)
2023-03-19 22:40:10 +08:00
}
2023-03-20 10:09:54 +08:00
type IBrowserChannel interface {
Channel(channelId int64) IChannel
ChannelIds() (result []int64)
Send(channelId int64, data []byte)
Handler(handler IPCCallback)
Close()
}
type IRenderChannel interface {
Channel() IChannel
Send(data []byte)
SendToChannel(toChannelId int64, data []byte)
2023-05-31 17:41:14 +08:00
UpdateChannelId(toChannelId int64)
2023-03-20 10:09:54 +08:00
Handler(handler IPCCallback)
Close()
}
2023-03-19 01:31:30 +08:00
// ipcMessage 消息内容
2023-03-19 00:00:09 +08:00
type ipcMessage struct {
2023-03-19 21:44:39 +08:00
t mt // type
2023-05-31 17:41:14 +08:00
s int32 // size
2023-03-19 21:44:39 +08:00
v []byte // data
2023-03-19 00:00:09 +08:00
}
2023-03-19 01:31:30 +08:00
// IPCContext IPC 上下文
2023-03-19 00:00:09 +08:00
type IPCContext struct {
2023-05-31 17:41:14 +08:00
channelId int64 //render channelId
toChannelId int64 //
ipcType IPC_TYPE // ipc type
channelType ChannelType // ipc channel type
processId CefProcessId // ipc msg source, browser or render
connect net.Conn // connect
message IMessage // message
2023-03-19 00:00:09 +08:00
}
2023-03-19 01:31:30 +08:00
// Free 释放消息内存空间
2023-03-19 00:00:09 +08:00
func (m *IPCContext) Free() {
if m.message != nil {
m.message.clear()
m.message = nil
}
}
2023-03-20 09:11:57 +08:00
// ChannelId 返回发送通道ID
2023-03-19 00:00:09 +08:00
func (m *IPCContext) ChannelId() int64 {
2023-03-19 00:10:52 +08:00
return m.channelId
2023-03-19 00:00:09 +08:00
}
2023-03-20 09:11:57 +08:00
// ToChannelId 返回接收通道ID
func (m *IPCContext) ToChannelId() int64 {
return m.toChannelId
}
2023-05-31 17:41:14 +08:00
// ChannelType 返回当前通道类型
func (m *IPCContext) ChannelType() ChannelType {
return m.channelType
}
func (m *IPCContext) ProcessId() CefProcessId {
return m.processId
}
2023-03-19 01:31:30 +08:00
// Message 返回消息内容
2023-03-19 00:00:09 +08:00
func (m *IPCContext) Message() IMessage {
return m.message
}
2023-03-19 01:31:30 +08:00
// Connect 返回当前通道链接
2023-03-19 00:00:09 +08:00
func (m *IPCContext) Connect() net.Conn {
return m.connect
}
2023-03-19 01:31:30 +08:00
// Type 消息类型
2023-03-19 00:00:09 +08:00
func (m *ipcMessage) Type() mt {
return m.t
}
2023-03-19 01:31:30 +08:00
// Data 消息[]byte数据
2023-03-19 00:00:09 +08:00
func (m *ipcMessage) Data() []byte {
return m.v
}
2023-03-19 01:31:30 +08:00
// Length 消息[]byte长度
2023-05-31 17:41:14 +08:00
func (m *ipcMessage) Length() int32 {
2023-03-19 00:00:09 +08:00
return m.s
}
2023-03-19 01:31:30 +08:00
// JSON 消息转为JSON对象
2023-03-19 00:00:09 +08:00
func (m *ipcMessage) JSON() json.JSON {
return json.NewJSON(m.v)
}
2023-03-19 01:31:30 +08:00
// clear 清空内容
2023-03-19 00:00:09 +08:00
func (m *ipcMessage) clear() {
2023-03-19 01:31:30 +08:00
m.t = mt_invalid
2023-03-19 00:00:09 +08:00
m.v = nil
m.s = 0
}
2023-03-19 21:44:39 +08:00
// channel 通道
type channel struct {
2023-05-31 17:41:14 +08:00
channelId int64
isConnect bool
conn net.Conn
ipcType IPC_TYPE
channelType ChannelType
handler IPCCallback
2023-03-19 15:25:46 +08:00
}
2023-05-31 17:41:14 +08:00
// IsConnect return is connect success
2023-03-19 22:40:10 +08:00
func (m *channel) IsConnect() bool {
if m == nil {
return false
}
return m.isConnect
}
2023-05-31 17:41:14 +08:00
// Close the current IPC channel connect
2023-03-19 21:44:39 +08:00
func (m *channel) Close() {
2023-03-19 15:25:46 +08:00
if m.conn != nil {
m.conn.Close()
m.conn = nil
}
}
2023-05-31 17:41:14 +08:00
// read data
2023-03-19 22:40:10 +08:00
func (m *channel) read(b []byte) (n int, err error) {
2023-03-19 15:25:46 +08:00
if m.ipcType == IPCT_NET {
return m.conn.Read(b)
} else {
n, _, err := m.conn.(*net.UnixConn).ReadFromUnix(b)
return n, err
}
}
2023-05-31 17:41:14 +08:00
// write data
2023-03-20 09:11:57 +08:00
func (m *channel) write(messageType mt, channelId, toChannelId int64, data []byte) (n int, err error) {
2023-03-19 00:00:09 +08:00
defer func() {
data = nil
}()
2023-03-19 15:25:46 +08:00
if m.conn == nil {
2023-05-31 17:41:14 +08:00
return 0, errors.New("channel link not established successfully")
2023-03-19 00:00:09 +08:00
}
var (
dataByteLen = len(data)
)
2023-05-31 17:41:14 +08:00
if dataByteLen > math.MaxInt32 {
return 0, errors.New("exceeded maximum message length")
}
var processId CefProcessId
if m.channelType == Ct_Server {
processId = PID_BROWSER
} else {
processId = PID_RENDER
2023-03-19 00:00:09 +08:00
}
2023-03-20 15:00:49 +08:00
var writeBuf = new(bytes.Buffer)
2023-05-31 17:41:14 +08:00
_ = binary.Write(writeBuf, binary.BigEndian, protocolHeader) //protocol header
_ = binary.Write(writeBuf, binary.BigEndian, int8(messageType)) //message type
_ = binary.Write(writeBuf, binary.BigEndian, int8(processId)) //source of information
_ = binary.Write(writeBuf, binary.BigEndian, channelId) //source channel Id
_ = binary.Write(writeBuf, binary.BigEndian, toChannelId) //to channel Id
_ = binary.Write(writeBuf, binary.BigEndian, int32(dataByteLen)) //data length
_ = binary.Write(writeBuf, binary.BigEndian, data) //data bytes
2023-03-20 15:00:49 +08:00
n, err = m.conn.Write(writeBuf.Bytes())
writeBuf.Reset()
writeBuf = nil
2023-03-19 00:00:09 +08:00
return n, err
}
2023-05-31 17:41:14 +08:00
// ipcRead Read channel messages
2023-03-19 21:44:39 +08:00
func (m *channel) ipcRead() {
2023-03-19 00:00:09 +08:00
var ipcType, chnType string
2023-03-19 15:25:46 +08:00
if m.ipcType == IPCT_NET {
2023-03-19 00:00:09 +08:00
ipcType = "[net]"
} else {
ipcType = "[unix]"
}
2023-03-19 21:44:39 +08:00
if m.channelType == Ct_Server {
2023-03-19 00:00:09 +08:00
chnType = "[server]"
} else {
chnType = "[client]"
}
defer func() {
2023-05-31 17:41:14 +08:00
logger.Debug("IPC Read Disconnect type:", ipcType, "ChannelType:", chnType, "processType:", process.Args.ProcessType())
2023-03-19 15:25:46 +08:00
m.Close()
2023-03-19 00:00:09 +08:00
}()
for {
header := make([]byte, headerLength)
2023-03-19 22:40:10 +08:00
size, err := m.read(header)
2023-03-19 00:00:09 +08:00
if err != nil {
2023-05-31 17:41:14 +08:00
logger.Debug("IPC Read [Error] type:", ipcType, "ChannelType:", chnType, "Error:", err)
2023-03-19 00:00:09 +08:00
return
} else if size == 0 {
2023-05-31 17:41:14 +08:00
logger.Debug("IPC Read [Size == 0] type:", ipcType, "ChannelType:", chnType, "header:", header, "Error:", err)
2023-03-19 00:00:09 +08:00
return
}
if size == headerLength {
for i, protocol := range protocolHeader {
if header[i] != protocol {
2023-03-20 20:07:52 +08:00
logger.Debug("check header protocol error", i, header[i], protocol)
2023-03-19 00:00:09 +08:00
return
}
}
var (
2023-05-31 17:41:14 +08:00
t, proId int8 //
channelId, toChannelId int64 //
dataLen int32 //数据长度
low, high int32 //
2023-03-19 00:00:09 +08:00
)
2023-05-31 17:41:14 +08:00
//message type
2023-03-19 00:00:09 +08:00
low = protocolHeaderLength
2023-03-19 00:27:06 +08:00
high = protocolHeaderLength + messageTypeLength
2023-03-19 00:00:09 +08:00
err = binary.Read(bytes.NewReader(header[low:high]), binary.BigEndian, &t)
if err != nil {
2023-03-20 09:23:27 +08:00
logger.Debug("binary.Read.t: ", err)
2023-03-19 00:00:09 +08:00
return
}
2023-05-31 17:41:14 +08:00
//message source
low = high
high = high + processIdLength
err = binary.Read(bytes.NewReader(header[low:high]), binary.BigEndian, &proId)
if err != nil {
logger.Debug("binary.Read.t: ", err)
return
}
//send channel id
2023-03-19 00:27:06 +08:00
low = high
high = high + channelIdLength
err = binary.Read(bytes.NewReader(header[low:high]), binary.BigEndian, &channelId)
if err != nil {
2023-03-20 09:23:27 +08:00
logger.Debug("binary.Read.channelId: ", err)
2023-03-19 00:27:06 +08:00
return
}
2023-03-19 00:00:09 +08:00
2023-05-31 17:41:14 +08:00
//receive channel id
2023-03-20 09:11:57 +08:00
low = high
high = high + toChannelIdLength
err = binary.Read(bytes.NewReader(header[low:high]), binary.BigEndian, &toChannelId)
if err != nil {
2023-03-20 09:23:27 +08:00
logger.Debug("binary.Read.toChannelId: ", err)
2023-03-20 09:11:57 +08:00
return
}
2023-05-31 17:41:14 +08:00
//data length
2023-03-19 00:00:09 +08:00
low = high
high = high + dataByteLength
err = binary.Read(bytes.NewReader(header[low:high]), binary.BigEndian, &dataLen)
if err != nil {
2023-03-20 09:23:27 +08:00
logger.Debug("binary.Read.dataLen: ", err)
2023-03-19 00:00:09 +08:00
return
}
2023-05-31 17:41:14 +08:00
//data
2023-03-19 00:00:09 +08:00
dataByte := make([]byte, dataLen)
if dataLen > 0 {
2023-03-19 22:40:10 +08:00
size, err = m.read(dataByte)
2023-03-19 00:00:09 +08:00
}
if err != nil {
2023-03-20 09:23:27 +08:00
logger.Debug("binary.Read.dataByte: ", err)
2023-03-19 00:00:09 +08:00
return
}
2023-05-31 17:41:14 +08:00
// call handler
2023-03-19 15:25:46 +08:00
m.handler(&IPCContext{
2023-03-20 09:11:57 +08:00
channelId: channelId,
toChannelId: toChannelId,
ipcType: m.ipcType,
connect: m.conn,
2023-05-31 17:41:14 +08:00
channelType: m.channelType,
processId: CefProcessId(proId),
message: &ipcMessage{ // message data
2023-03-19 00:00:09 +08:00
t: mt(t),
s: dataLen,
v: dataByte,
},
})
} else {
2023-05-31 17:41:14 +08:00
logger.Debug("invalid != headerLength")
2023-03-19 00:00:09 +08:00
break
}
}
}