dujunchen 1 месяц назад
Родитель
Сommit
d0eea2ffdf

+ 1 - 1
cmd/main.go

@@ -72,7 +72,7 @@ func main() {
 func initVersion() {
 	if gitCommitCode != "" {
 		//构建信息
-		utils.Logger.Printf("software version: V10.01")
+		//utils.Logger.Printf("software version: V10.01")
 		lfshook.NewLogger().Printf("git commit code: %s", gitCommitCode)
 		lfshook.NewLogger().Printf("build date: %s", buildDateTime)
 		lfshook.NewLogger().Printf("go version: %s", goVersion)

+ 18 - 6
internal/app/ami/action/call.go

@@ -106,12 +106,13 @@ func HangupTask(TaskName string) {
 			lfshook.NewLogger().Infof("QueueStatus err:%+v", err)
 			return
 		}
-		for _, caller := range resCaller.Entrys {
-			//lfshook.NewLogger().Infof("===QueueStatus=entry=%+v", caller)
-			time.Sleep(time.Millisecond * 50)
-			RedirectInQueue(caller.CallerIDNum, "0300", "queues-icp-redirect", caller.CallerIDNum) // redirect All PAD redirect to ICP queue
+		if resCaller != nil {
+			for _, caller := range resCaller.Entrys {
+				//lfshook.NewLogger().Infof("===QueueStatus=entry=%+v", caller)
+				time.Sleep(time.Millisecond * 50)
+				RedirectInQueue(caller.CallerIDNum, "0300", "queues-icp-redirect", caller.CallerIDNum) // redirect All PAD redirect to ICP queue
+			}
 		}
-
 	}
 
 	taskInfo, ok := priority.RegistryTask.Get(TaskName)
@@ -247,6 +248,11 @@ func InterruptRunningTask(toRunTask string) {
 				lfshook.NewLogger().Infof("QueueStatus err:%+v", err)
 				return
 			}
+
+			if resCaller == nil {
+				return
+			}
+
 			for _, caller := range resCaller.Entrys {
 				//lfshook.NewLogger().Infof("===QueueStatus=entry=%+v", caller)
 				time.Sleep(time.Millisecond * 50)
@@ -497,7 +503,9 @@ func SetPadTimer() {
 		lfshook.NewLogger().Infof("QueueStatus err%+v", err)
 		return
 	}
-
+	if res == nil {
+		return
+	}
 	if res.Calls != "0" {
 
 		lfshook.NewLogger().Infof("PAD SetPadTimer Set QueueTimer timeout 30s !")
@@ -524,6 +532,10 @@ func SetPadTimer() {
 				return
 			}
 
+			if res == nil {
+				return
+			}
+
 			if res.Calls == "0" { // OCC queue empty
 				resCaller, err := QueueStatus("0300", "") // check ICP queue, get entries
 				if err != nil {

+ 25 - 7
internal/app/ami/action/index.go

@@ -142,7 +142,7 @@ func HandleAMI(event map[string]string) {
 			//获取录音文件时长,检测录音文件是否超过3min;
 			duration, err := utils.GetDuration(event["FILENAME"])
 			if err != nil {
-				utils.Logger.Printf("Get duration err: %+v", err)
+				utils.Logger.Printf("%s Get duration err: %+v", event["FILENAME"], err)
 				break
 			}
 			//lfshook.NewLogger().Infof("==========duration===== %d", duration)
@@ -154,7 +154,7 @@ func HandleAMI(event map[string]string) {
 			} else if duration < 600 { //小于600秒文件进行转换和切割
 				FileNames, err = utils.ConvertAndSegmentWAV(event["FILENAME"], strings.Replace(event["FILENAME"], ".wav", "", -1))
 				if err != nil {
-					lfshook.NewLogger().Infof("Get duration err: %+v", err)
+					lfshook.NewLogger().Infof("%s  Get duration err: %+v", event["FILENAME"], err)
 					break
 				}
 				//lfshook.NewLogger().Infof("=============== File %+v found after convert", FileNames)
@@ -181,7 +181,13 @@ func HandleAMI(event map[string]string) {
 
 					if strings.Contains(event["FILENAME"], "PAD") {
 						_, caller, callee := utils.GetPadInfo(event["FILENAME"])
-						trainInfo = fmt.Sprintf("TrainNumber %s  CarNumber %s ", active.TrainNum, active.TrainInfoMap[active.TrainNum][int(caller[2])])
+
+						carNum := int(caller[2] - '0')
+						//trainInfo = fmt.Sprintf("TrainNumber %s  CarNumber %s ", active.TrainNum, active.TrainInfoMap[active.TrainNum][int(caller[2])])
+						lfshook.NewLogger().Infof("Train info===caller[2]==========:%c===============", carNum)
+
+						trainInfo = fmt.Sprintf("TrainNumber %s  CarNumber %s ", active.TrainNum, active.TrainInfoMap[active.TrainNum][carNum])
+
 						lfshook.NewLogger().Infof("Train info=============%s===============", trainInfo)
 
 						if len(caller) == 4 && len(caller) > 0 {
@@ -217,8 +223,9 @@ func HandleAMI(event map[string]string) {
 				path := filepath.Dir(event["FILENAME"])
 				rcdFileName := filepath.Base(event["FILENAME"])
 				xmlFileName := strings.Replace(rcdFileName, "wav", "xml", 1)
-				xmlFilePath := path + xmlFileName
+				xmlFilePath := path + "/" + xmlFileName
 
+				lfshook.NewLogger().Infof("Train info= xml path============%s===============", xmlFilePath)
 				err := active.GenerateXML(xmlFilePath)
 				if err != nil {
 					lfshook.NewLogger().Infof("Generate recording XML err:%+v", err)
@@ -242,7 +249,11 @@ func HandleAMI(event map[string]string) {
 			time.Sleep(time.Millisecond * 100) //wait endpoimt release
 
 			res, _ := QueueStatus("0301", "") // check OCC queue ,if empty PAD end
-			if res.Calls == "0" {             //OCC queue is empty
+			if res == nil {
+				return
+			}
+
+			if res.Calls == "0" { //OCC queue is empty
 				alstatus.OccPad("end")
 				priority.OCCAnswer = 0
 				priority.PADOccStart = 0
@@ -324,7 +335,9 @@ func HandleAMI(event map[string]string) {
 			if utils.IsPAIU(number) {
 				res, _ := QueueStatus("0300", "")  // check ICP queue ,if empty PAD end
 				res1, _ := QueueStatus("0301", "") // check OCC queue ,if empty PAD end
-
+				if res == nil || res1 == nil {
+					return
+				}
 				lfshook.NewLogger().Infof("===Hangup  PAD====== ICP Queue calls:%s  OCC Queue calls:%s", res.Calls, res1.Calls)
 				//if res.Calls == "0" && res1.Calls == "0" {
 
@@ -391,7 +404,9 @@ func HandleAMI(event map[string]string) {
 				lfshook.NewLogger().Infof("ICP QueueStatus err:%+v", err)
 				return
 			}
-
+			if ICPQueue == nil {
+				return
+			}
 			if priority.ICPAnswer == 0 && ICPQueue.Calls == "1" { //ICP did not answer any first call to the ICP queue ; Ready to Set Occ Queue Timer
 				toRunpriority := priority.GetPriorityByKey("PAD-ICP")
 
@@ -429,6 +444,9 @@ func HandleAMI(event map[string]string) {
 						lfshook.NewLogger().Infof("OCC QueueStatus err:%+v", err)
 						return
 					}
+					if res == nil {
+						return
+					}
 
 					if res.Calls == "0" { // OCC queue empty
 						resCaller, err := QueueStatus("0300", "") // check ICP queue, get entries

+ 47 - 21
internal/app/stc/broadcast/stc-broadcast.go

@@ -6,6 +6,7 @@ import (
 	"encoding/binary"
 	"fmt"
 	"io"
+	"log"
 	"net"
 	"pbx-api-gin/internal/app/ami/action"
 	"pbx-api-gin/internal/app/stc/active"
@@ -43,13 +44,29 @@ func HandleStcCmd(ctx context.Context, conn net.Conn) {
 				buf.Write(tmp[:n])
 			}
 
+			/*for {
+				packet, err := msgdata.ExtractPacket(&buf)
+				if err != nil {
+					lfshook.NewLogger().Logger.Infof("ExtractPacket:%+v", err)
+					break
+				}
+				go processPacket(packet)
+			}*/
+			lfshook.NewLogger().Logger.Infof("buf:%x==============================", buf.Bytes())
 			for {
 				packet, err := msgdata.ExtractPacket(&buf)
 				if err != nil {
+					log.Printf("parse error: %v, resetting buffer", err)
+					buf.Reset() // 解析失败,清空避免污染
 					break
 				}
+				if packet == nil {
+					break // 当前无完整包,等待下次 ReadFrom
+				}
+				//处理 packet...
 				go processPacket(packet)
 			}
+
 		}
 	}
 }
@@ -58,37 +75,41 @@ func HandleStcCmd(ctx context.Context, conn net.Conn) {
 func processHeartbeat(info []byte) {
 	//dataCount := info[0]
 	//Get train info
-	trainNumB1 := info[2]
-	trainNumB2 := info[3]
-	active.TrainNum = fmt.Sprintf("%s%s", string(trainNumB1), string(trainNumB2))
-	lfshook.NewLogger().Logger.Infof("TrainNum:%s===Byte1:%x=====Byte2:%x====str1:%s===str2:%s", active.TrainNum, trainNumB1, trainNumB2, string(trainNumB1), string(trainNumB2))
+	value := binary.BigEndian.Uint16(info[2:4]) //info[2] +  info[3]
+	active.TrainNum = "TS" + strconv.Itoa(int(value))
+
+	lfshook.NewLogger().Logger.Infof("TrainNum: %s", active.TrainNum)
 
 	//Get ICP volume
-	active.DeviceEndpoint.ICPInfo[0].Volume = string((info[9] >> 4) & 0xF)
+	icpBit8 := info[9] & 0xF
+	icpBit1 := (info[9] >> 4) & 0xF
+	active.DeviceEndpoint.ICPInfo[0].Volume = fmt.Sprintf("%d", icpBit1)
 	active.DeviceEndpoint.ICPInfo[0].ID = "1"
-	active.DeviceEndpoint.ICPInfo[1].Volume = string((info[9]) & 0xF)
+	active.DeviceEndpoint.ICPInfo[1].Volume = fmt.Sprintf("%d", icpBit8)
 	active.DeviceEndpoint.ICPInfo[1].ID = "8"
 
 	//Get Pacu info
-	eidsStat := info[1]
-	pacuStat := info[4]
-	pacuVolume := binary.BigEndian.Uint32(info[4:8])
+	eidsStat := info[1] //PACU mute
+	pacuStat := info[4] //PACU status
+
+	pacuVolume := binary.BigEndian.Uint32(info[5:9]) //info[5]-info[8]
+
+	lfshook.NewLogger().Logger.Infof("=eidsStat:%x=======pacuStat:%x=====", eidsStat, pacuStat)
 
 	for i := 0; i < 8; i++ {
-		eidsBit := (eidsStat >> i) & 0x01       // 右移 i 位,再与 1 取最低位
-		fmt.Printf("bit %d = %d\n", i, eidsBit) // bit 0 是 LSB(最低位,最右)
-		//id = i
-		//mute = eidsBit
+		eidsBit := (eidsStat >> i) & 0x01 // 右移 i 位,再与 1 取最低位
+		//fmt.Printf("eidsBit bit %d = %d\n", i, eidsBit) // bit 0 是 LSB(最低位,最右)
 
+		//get 1 bit every time
 		pacuStatBit := (pacuStat >> i) & 0x01
-		fmt.Printf("bit %d = %d\n", i, pacuStatBit)
-		//status = pacuStatBit
+		//fmt.Printf("pacuStatBit bit %d = %d\n", i, pacuStatBit)
 
-		pacuVolBit := (pacuVolume >> i) & 0xF
-		fmt.Printf("bit %d = %d\n", i, pacuVolBit)
-		//volum = pacuVolBit
+		//get 4 bit every time
+		var pacuVolBit int8
+		pacuVolBit = int8((pacuVolume >> i) & 0xF)
+		//fmt.Printf("pacuVolBit bit %d = %x\n", i, pacuVolBit)
 
-		active.DeviceEndpoint.PacuInfo[i].ID = strconv.Itoa(i)
+		active.DeviceEndpoint.PacuInfo[i].ID = strconv.Itoa(i + 1)
 		if eidsBit == 1 {
 			active.DeviceEndpoint.PacuInfo[i].Mute = true
 		} else {
@@ -113,7 +134,7 @@ func processPacket(packet []byte) {
 	}
 
 	//for recv data log debug
-	if packet[5] != 0x03 && packet[5] != 0x0c && packet[5] != 0x01 {
+	if packet[5] != 0x03 && packet[5] != 0x0c /* && packet[5] != 0x01*/ {
 		lfshook.NewLogger().Logger.Infof("Get data from STC:%x", packet)
 	}
 
@@ -135,8 +156,13 @@ func processPacket(packet []byte) {
 
 	switch packet[5] {
 	case 0x01: //heartbeat
-		processHeartbeat(packet[8:])
+		dataLen := binary.BigEndian.Uint16(packet[6:8])
 
+		if dataLen == 10 {
+			processHeartbeat(packet[8:])
+		} else {
+			lfshook.NewLogger().Logger.Infof("=========Heartbeat data err !====len < 10=========")
+		}
 	case 0x02: // STN
 		if active.ActivedCab != "" {
 			if priority.CheckPriority("STN") {

+ 47 - 16
internal/app/stc/data/msgdata.go

@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"encoding/binary"
 	"fmt"
+	"pbx-api-gin/pkg/lfshook"
 )
 
 // Protocol 定义协议数据结构
@@ -126,14 +127,15 @@ func SubstrByRune(s string, start, length int) string {
 	return string(runes[start:end])
 }
 
-// extractPacket 从 buffer 中提取第一个完整数据包
 func ExtractPacket(buf *bytes.Buffer) ([]byte, error) {
 	data := buf.Bytes()
-	startIdx := -1
-	endIdx := -1
+	leng := buf.Len()
+
+	//lfshook.NewLogger().Logger.Infof("========start=========ExtractPacket raw data len=%d, hex=%x", leng, data)
 
-	// 查找起始标记 0x7f 0x83 0x9d
-	for i := 0; i < len(data)-2; i++ {
+	// Step 1: 查找起始标记 0x7f 0x8e 0x9d
+	startIdx := -1
+	for i := 0; i <= len(data)-3; i++ { // <= len-3 防止越界
 		if data[i] == 0x7f && data[i+1] == 0x8e && data[i+2] == 0x9d {
 			startIdx = i
 			break
@@ -141,15 +143,41 @@ func ExtractPacket(buf *bytes.Buffer) ([]byte, error) {
 	}
 
 	if startIdx == -1 {
-		// 没找到起始标记,清掉前面无用数据(防止 OOM)
-		if buf.Len() > 1024 {
-			buf.Next(buf.Len() - 10) // 保留最后10字节继续查找
+		//无起始标记:保守策略——丢弃过长脏数据,保留最后 MAX_LOOKAHEAD 字节防漏包
+		const MAX_LOOKAHEAD = 32
+		if leng > MAX_LOOKAHEAD {
+			buf.Next(leng - MAX_LOOKAHEAD)
+			lfshook.NewLogger().Logger.Warnf("no start marker found, trimmed buffer to last %d bytes", MAX_LOOKAHEAD)
 		}
-		return nil, fmt.Errorf("no start marker found")
+		return nil, nil // 明确告知:需继续读取
+	}
+
+	// Step 2: 安全读取 DataLength(偏移 startIdx+6 ~ startIdx+8)
+	if startIdx+8 > len(data) {
+		lfshook.NewLogger().Logger.Infof("startIdx=%d, need data[%d:%d] for DataLength but len=%d → insufficient data",
+			startIdx, startIdx+6, startIdx+8, len(data))
+		return nil, nil // 数据不够,等下次读取
 	}
 
-	// 从起始位置开始查找结束标记 0xFE
-	for i := startIdx; i < len(data); i++ {
+	dataLen := binary.BigEndian.Uint16(data[startIdx+6 : startIdx+8])
+	//lfshook.NewLogger().Logger.Infof("ExtractPacket datalen=%d (0x%04x) at offset %d", dataLen, dataLen, startIdx+6)
+
+	// Step 3: 计算理论包结束位置:startIdx + 8(头长) + dataLen + 1(0xFE)
+	endPosTheo := startIdx + 8 + int(dataLen) + 1
+	if endPosTheo > len(data) {
+		lfshook.NewLogger().Logger.Infof("theoretical endPos=%d > data len=%d → need more data", endPosTheo, len(data))
+		return nil, nil // 包未收全,等下次读取
+	}
+	//lfshook.NewLogger().Logger.Infof("t=================end================%x", data[endPosTheo])
+	// Step 4: 在 [startIdx+8+dataLen, endPosTheo] 范围内查找 0xFE(容错:允许在理论位置附近 1~2 字节浮动)
+	searchStart := startIdx + 8 + int(dataLen)
+	searchEnd := endPosTheo
+	if searchEnd > len(data) {
+		searchEnd = len(data) // 安全截断
+	}
+
+	endIdx := -1
+	for i := searchStart; i <= searchEnd; i++ {
 		if data[i] == 0xFE {
 			endIdx = i
 			break
@@ -157,15 +185,18 @@ func ExtractPacket(buf *bytes.Buffer) ([]byte, error) {
 	}
 
 	if endIdx == -1 {
-		return nil, fmt.Errorf("no end marker found")
+		lfshook.NewLogger().Logger.Infof("0xFE not found in expected range [%d,%d), dataLen=%d", searchStart, searchEnd, dataLen)
+		return nil, nil // 结束符缺失,但可能是延迟到达,继续等
 	}
 
-	// 提取完整包 [startIdx 到 endIdx]
-	packet := make([]byte, endIdx-startIdx+1)
+	//找到完整包:[startIdx, endIdx](含两端)
+	packetLen := endIdx - startIdx + 1
+	packet := make([]byte, packetLen)
 	copy(packet, data[startIdx:endIdx+1])
 
-	// 从 buffer 中删除已处理的数据
+	// 从 buffer 中移除已处理部分
 	buf.Next(endIdx + 1)
-
+	//lfshook.NewLogger().Logger.Infof("extracted packet len=%d, start=0x7f8e9d, end=0xFE", packetLen)
+	lfshook.NewLogger().Logger.Infof("=============return============== %x", packet)
 	return packet, nil
 }

+ 1 - 1
internal/app/stc/index.go

@@ -33,7 +33,7 @@ func StartStcConnection(conn net.Conn, cab string) {
 			continue
 		}
 
-		trainInfo := fmt.Sprintf("Train Number %s     CabNumber %s", active.TrainNum, active.ActivedCab)
+		trainInfo := fmt.Sprintf("CabNumber %s", active.ActivedCab)
 		//set connection log
 		if logTag == 0 {
 			utils.Logger.Printf("Train Information: %s, Message: Connection to Cab%s STC is up !", trainInfo, cab)

+ 1 - 1
pkg/utils/cmd.go

@@ -49,7 +49,7 @@ func ExecCmd(cmdName string, arg ...string) (stdOut, errOut string, err error) {
 		if err != nil {
 			lfshook.NewLogger().Errorf("cmd.Wait(%s) %s\n", cmdName, err)
 		} else {
-			lfshook.NewLogger().Info("cmd.Wait(%s)\n", cmdName)
+			lfshook.NewLogger().Infof("cmd.Wait(%s)\n", cmdName)
 		}
 		cancel()
 	}()

+ 5 - 2
pkg/utils/file.go

@@ -34,6 +34,7 @@ func GetDuration(filePath string) (int, error) {
 
 	output, err := cmd.Output()
 	if err != nil {
+		lfshook.NewLogger().Logger.Infof("=======GetDuration err:%+v ! ============", output)
 		return 0, err
 	}
 
@@ -108,7 +109,8 @@ func ConvertAndSegmentWAV(inputFile string, outputPrefix string) ([]string, erro
 	output, err := cmd.CombinedOutput()
 	if err != nil && !strings.Contains(string(output), "Conversion failed!") {
 		// 即使有警告(如非关键错误),只要文件生成了就继续解析
-		log.Printf("ffmpeg 执行时有警告: %v", err)
+		//log.Printf("ffmpeg 执行时有警告: %v", err)
+		lfshook.NewLogger().Logger.Infof("=======ConvertAndSegmentWAV err:%+v ! ============", output)
 	}
 	// 解析输出,提取所有生成的文件名
 	files := extractFilenamesFromFFmpegOutput(outputPrefix)
@@ -122,7 +124,8 @@ func extractFilenamesFromFFmpegOutput(prefix string) []string {
 	pattern := fmt.Sprintf("%s_*", prefix)
 	matches, err := filepath.Glob(pattern)
 	if err != nil {
-		log.Fatal("模式匹配错误:", err)
+		//log.Fatal("模式匹配错误:", err)
+		lfshook.NewLogger().Logger.Infof("=======模式匹配错误:%+v ! ============", err)
 	}
 
 	return matches