You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
5.6 KiB
222 lines
5.6 KiB
package app
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"gitea.anxinyun.cn/container/common_models"
|
|
"gitea.anxinyun.cn/container/common_utils"
|
|
"gitea.anxinyun.cn/container/common_utils/configLoad"
|
|
"log"
|
|
"net/rpc"
|
|
"node/et_worker/et_recv"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
type EtNode struct {
|
|
nodeInfo *common_models.NodeArgs
|
|
master *rpcMaster
|
|
ch chan *common_models.ProcessData
|
|
recvDataHandler *et_recv.RecvDataHanler
|
|
}
|
|
|
|
type rpcMaster struct {
|
|
conn *rpc.Client
|
|
addr string
|
|
}
|
|
|
|
const chSize = 2
|
|
|
|
func NewEtWorker() *EtNode {
|
|
node := &EtNode{
|
|
ch: make(chan *common_models.ProcessData, chSize),
|
|
recvDataHandler: et_recv.NewRecvDataHanler(),
|
|
}
|
|
node.exitMonitor()
|
|
node.heartMonitor()
|
|
return node
|
|
}
|
|
|
|
// Handler 是 RPC 服务方法,由 master 远程调用
|
|
func (the *EtNode) Handler(iotaData common_models.IotaData, replay *bool) error {
|
|
*replay = true
|
|
err := the.ConsumerProcess(&iotaData)
|
|
if err != nil {
|
|
*replay = false
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// ConsumerProcess 将 IotaData -> ProcessData
|
|
func (the *EtNode) ConsumerProcess(iotaData *common_models.IotaData) error {
|
|
deviceData, err := the.recvDataHandler.OnDataHandler(*iotaData)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if deviceData == nil {
|
|
return nil
|
|
}
|
|
|
|
log.Printf("rpc处理设备数据[%s]-time[%s]-[%v]", deviceData.DeviceId, deviceData.AcqTime, deviceData.Raw)
|
|
//log.Printf("rpc处理设备数据[%s]-time[%s]-data:%v", iotaData.DeviceId, iotaData.TriggerTime, iotaData.ThemeData.ThemeData)
|
|
the.ch <- &common_models.ProcessData{
|
|
DeviceData: *deviceData,
|
|
Stations: []common_models.Station{},
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 实现源接口
|
|
func (the *EtNode) Process(ctx context.Context) (<-chan any, error) {
|
|
source := make(chan any, chSize)
|
|
go func() {
|
|
defer close(source)
|
|
for {
|
|
select {
|
|
case a := <-the.ch:
|
|
source <- a
|
|
log.Printf("存储数据=>source out,len=%d,%d", len(source), len(the.ch))
|
|
case <-ctx.Done():
|
|
log.Println("退出[source] EtNode.Process")
|
|
return
|
|
}
|
|
|
|
}
|
|
}()
|
|
return source, nil
|
|
}
|
|
|
|
// RegisterToMaster 调用 master 发布的RPC服务方法 master.NodeRegister
|
|
func (the *EtNode) RegisterToMaster() {
|
|
maxCount := 3
|
|
connectCount := 0
|
|
for {
|
|
connectCount++
|
|
if connectCount > maxCount {
|
|
log.Printf("RegisterToMaster 失败 超过%d次,准备退出", maxCount)
|
|
time.Sleep(time.Second * 10)
|
|
os.Exit(1)
|
|
}
|
|
masterAddr := loadMasterAddr()
|
|
masterConn, err := rpc.Dial("tcp", masterAddr)
|
|
if err != nil {
|
|
log.Printf("链接失败-> node[%s]", masterAddr)
|
|
time.Sleep(time.Second * 5)
|
|
continue
|
|
}
|
|
the.master = &rpcMaster{
|
|
conn: masterConn,
|
|
addr: masterAddr,
|
|
}
|
|
time.Sleep(time.Millisecond * 200)
|
|
//获取node自己地址
|
|
ipPrefix := configLoad.LoadConfig().GetString("node.hostIpPrefix")
|
|
ip4 := common_utils.ReadIP4WithPrefixFirst(ipPrefix)
|
|
hostName, err := os.Hostname()
|
|
log.Printf("node [%s] ip=%s", hostName, ip4)
|
|
port := configLoad.LoadConfig().GetUint16("node.port")
|
|
callNodeAddr := fmt.Sprintf("%s:%d", ip4, port)
|
|
|
|
if the.nodeInfo == nil {
|
|
the.nodeInfo = &common_models.NodeArgs{
|
|
ID: hostName + time.Now().Format("_20060102_150405"),
|
|
NodeType: "etNode",
|
|
Status: "",
|
|
Resources: "",
|
|
Addr: callNodeAddr,
|
|
ThingIds: []string{},
|
|
}
|
|
}
|
|
|
|
var result bool
|
|
err = the.master.conn.Call("master.NodeRegister", the.nodeInfo, &result)
|
|
if err != nil {
|
|
log.Printf("node[%s] 注册到 master[%s]异常:%v", the.nodeInfo.Addr, the.master.addr, result)
|
|
continue
|
|
}
|
|
break
|
|
}
|
|
}
|
|
func (the *EtNode) heartToMaster() {
|
|
maxCount := 3
|
|
connectCount := 0
|
|
reRegister := false
|
|
for {
|
|
connectCount++
|
|
if connectCount > maxCount {
|
|
log.Printf("heartToMaster 失败 超过%d次", maxCount)
|
|
reRegister = true
|
|
break
|
|
}
|
|
var result bool
|
|
err := the.master.conn.Call("master.NodeHeart", the.nodeInfo, &result)
|
|
if err != nil {
|
|
log.Printf("node[%s] 心跳到 master[%s]异常:%v", the.nodeInfo.Addr, the.master.addr, result)
|
|
time.Sleep(time.Second * 5)
|
|
continue
|
|
}
|
|
break
|
|
}
|
|
if reRegister { //触发重新注册
|
|
log.Printf("node[%s] 心跳失败触发-重新注册到 master[%s]", the.nodeInfo.Addr, the.master.addr)
|
|
the.RegisterToMaster()
|
|
}
|
|
}
|
|
|
|
func (the *EtNode) UnRegisterToMaster() {
|
|
var result bool
|
|
if err := the.master.conn.Call("master.NodeUnRegister", the.nodeInfo, &result); err != nil {
|
|
log.Printf("node[%s] 注销到 master,异常:%v", the.nodeInfo.Addr, err.Error())
|
|
} else {
|
|
log.Printf("node[%s] 注销到 master,结果:%v", the.nodeInfo.Addr, result)
|
|
}
|
|
}
|
|
func (the *EtNode) exitMonitor() {
|
|
go func() {
|
|
c := make(chan os.Signal, 1)
|
|
// 通过signal.Notify函数将信号通道c注册到系统相关的退出信号上
|
|
// 这里使用了两个退出信号:syscall.SIGINT(Ctrl+C)和syscall.SIGTERM(系统发送的退出信号)
|
|
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
|
|
// 阻塞等待接收信号
|
|
s := <-c
|
|
log.Printf("接收到退出信号:%v,进行清理工作\n", s)
|
|
the.UnRegisterToMaster()
|
|
time.Sleep(3 * time.Second)
|
|
os.Exit(0)
|
|
}()
|
|
}
|
|
func (the *EtNode) heartMonitor() {
|
|
go func() {
|
|
ticker := time.NewTicker(time.Minute)
|
|
defer ticker.Stop()
|
|
for range ticker.C {
|
|
if the.master != nil {
|
|
log.Printf("node[%s] 心跳触发-> master[%s]", the.nodeInfo.Addr, the.master.addr)
|
|
the.heartToMaster()
|
|
}
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
// LoadCh test用
|
|
func (the *EtNode) LoadCh() chan *common_models.ProcessData {
|
|
return the.ch
|
|
}
|
|
|
|
func loadMasterAddr() string {
|
|
masterHost := configLoad.LoadConfig().GetString("node.remoteMasterHost")
|
|
masterPort := configLoad.LoadConfig().GetUint16("master.port")
|
|
if masterHost == "" {
|
|
masterHost = "127.0.0.1"
|
|
}
|
|
if masterPort == 0 {
|
|
masterPort = 50000
|
|
}
|
|
return fmt.Sprintf("%s:%d", masterHost, masterPort)
|
|
}
|
|
|