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-03-21 22:05:31 +08:00
|
|
|
// IPC 通道
|
2023-03-20 10:09:54 +08:00
|
|
|
package channel
|
2023-03-19 00:00:09 +08:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/binary"
|
|
|
|
"errors"
|
|
|
|
"github.com/energye/energy/common"
|
|
|
|
. "github.com/energye/energy/consts"
|
|
|
|
"github.com/energye/energy/logger"
|
|
|
|
"github.com/energye/energy/pkgs/json"
|
|
|
|
"github.com/energye/golcl/lcl/rtl/version"
|
|
|
|
"math"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2023-03-20 09:11:57 +08:00
|
|
|
protocolHeader = []byte{0x01, 0x09, 0x08, 0x07, 0x00, 0x08, 0x02, 0x02} //协议头
|
|
|
|
protocolHeaderLength = int32(len(protocolHeader)) //协议头长度
|
|
|
|
messageTypeLength = int32(1) //消息类型 int8
|
|
|
|
channelIdLength = int32(8) //发送通道 int64
|
|
|
|
toChannelIdLength = int32(8) //接收通道 int64
|
|
|
|
dataByteLength = int32(4) //数据长度 int32
|
|
|
|
headerLength = int(protocolHeaderLength + messageTypeLength + 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 //
|
|
|
|
port int // net ipc
|
|
|
|
browser = &browserChannel{
|
|
|
|
channel: sync.Map{},
|
|
|
|
mutex: sync.Mutex{},
|
|
|
|
}
|
|
|
|
render = &renderChannel{
|
|
|
|
mutex: sync.Mutex{},
|
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-03-20 09:11:57 +08:00
|
|
|
mt_invalid mt = iota - 1 // 无效类型
|
|
|
|
mt_connection // 建立链接消息
|
|
|
|
mt_connectd // 已链接
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
}
|
|
|
|
//主进程获取端口号
|
|
|
|
if common.Args.IsMain() {
|
|
|
|
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
|
|
|
// Browser 返回 browser 通道
|
2023-03-20 10:09:54 +08:00
|
|
|
func Browser() IBrowserChannel {
|
|
|
|
return browser
|
2023-03-19 00:00:09 +08:00
|
|
|
}
|
|
|
|
|
2023-03-19 01:31:30 +08:00
|
|
|
// Render 返回 render 通道
|
2023-03-20 10:09:54 +08:00
|
|
|
func Render() IRenderChannel {
|
|
|
|
return render
|
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-03-20 09:11:57 +08:00
|
|
|
Connect() net.Conn // IPC 通道链接
|
|
|
|
ChannelId() int64 // 返回 发送通道ID
|
|
|
|
ToChannelId() int64 // 返回 接收发送通道ID
|
|
|
|
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 // 消息类型
|
|
|
|
Length() uint32 // 数据长度
|
|
|
|
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)
|
|
|
|
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
|
|
|
|
s uint32 // size
|
|
|
|
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-03-20 09:11:57 +08:00
|
|
|
channelId int64 //render channelId
|
|
|
|
toChannelId int64 //
|
|
|
|
ipcType IPC_TYPE // ipcType
|
|
|
|
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-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-03-19 00:27:06 +08:00
|
|
|
func (m *ipcMessage) Length() uint32 {
|
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-03-20 15:00:49 +08:00
|
|
|
channelId int64 //通道ID
|
|
|
|
isConnect bool //是否已链接
|
|
|
|
conn net.Conn //通道链接 net or unix
|
|
|
|
ipcType IPC_TYPE //IPC类型
|
|
|
|
channelType ChannelType //链接通道类型
|
|
|
|
handler IPCCallback //
|
2023-03-19 15:25:46 +08:00
|
|
|
}
|
|
|
|
|
2023-03-20 09:23:27 +08:00
|
|
|
// IsConnect 返回是否已链接
|
2023-03-19 22:40:10 +08:00
|
|
|
func (m *channel) IsConnect() bool {
|
|
|
|
if m == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return m.isConnect
|
|
|
|
}
|
|
|
|
|
2023-03-19 15:25:46 +08:00
|
|
|
// Close 关闭当前ipc通道链接
|
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-03-19 22:40:10 +08:00
|
|
|
// read 读取 net or unix 内容
|
|
|
|
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-03-20 09:23:27 +08:00
|
|
|
// write 写入消息
|
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 {
|
|
|
|
return 0, errors.New("通道链接未建立成功")
|
2023-03-19 00:00:09 +08:00
|
|
|
}
|
|
|
|
var (
|
|
|
|
dataByteLen = len(data)
|
|
|
|
)
|
2023-03-19 00:27:06 +08:00
|
|
|
if dataByteLen > math.MaxUint32 {
|
2023-03-19 00:00:09 +08:00
|
|
|
return 0, errors.New("超出最大消息长度")
|
|
|
|
}
|
2023-03-20 15:00:49 +08:00
|
|
|
var writeBuf = new(bytes.Buffer)
|
|
|
|
_ = binary.Write(writeBuf, binary.BigEndian, protocolHeader) //协议头
|
|
|
|
_ = binary.Write(writeBuf, binary.BigEndian, int8(messageType)) //消息类型
|
|
|
|
_ = binary.Write(writeBuf, binary.BigEndian, channelId) //通道Id
|
|
|
|
_ = binary.Write(writeBuf, binary.BigEndian, toChannelId) //通道Id
|
|
|
|
_ = binary.Write(writeBuf, binary.BigEndian, uint32(dataByteLen)) //数据长度
|
|
|
|
_ = binary.Write(writeBuf, binary.BigEndian, data) //数据
|
|
|
|
n, err = m.conn.Write(writeBuf.Bytes())
|
|
|
|
writeBuf.Reset()
|
|
|
|
writeBuf = nil
|
2023-03-19 00:00:09 +08:00
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
2023-03-19 22:40:10 +08:00
|
|
|
// ipcRead 读取通道消息
|
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() {
|
|
|
|
logger.Debug("IPC Read Disconnect type:", ipcType, "ChannelType:", chnType, "processType:", common.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 {
|
|
|
|
logger.Debug("IPC Read【Error】IPCType:", ipcType, "ChannelType:", chnType, "Error:", err)
|
|
|
|
return
|
|
|
|
} else if size == 0 {
|
|
|
|
logger.Debug("IPC Read【Size == 0】IPCType:", ipcType, "ChannelType:", chnType, "header:", header, "Error:", err)
|
|
|
|
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-03-20 09:11:57 +08:00
|
|
|
t int8 //消息类型
|
|
|
|
channelId, toChannelId int64 //
|
|
|
|
dataLen uint32 //数据长度
|
|
|
|
low, high int32 //
|
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-03-20 09:11:57 +08:00
|
|
|
//发送通道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-03-20 09:11:57 +08:00
|
|
|
//接收通道ID
|
|
|
|
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-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
|
|
|
|
}
|
|
|
|
//数据
|
|
|
|
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-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-03-19 00:00:09 +08:00
|
|
|
message: &ipcMessage{
|
|
|
|
t: mt(t),
|
|
|
|
s: dataLen,
|
|
|
|
v: dataByte,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
logger.Debug("无效的 != headerLength")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|