|
|
@@ -0,0 +1,582 @@
|
|
|
+package function
|
|
|
+
|
|
|
+import (
|
|
|
+ "bytes"
|
|
|
+ "encoding/binary"
|
|
|
+ "fmt"
|
|
|
+ "os"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+
|
|
|
+ "github.com/sigurn/crc16"
|
|
|
+ "go.uber.org/zap"
|
|
|
+)
|
|
|
+
|
|
|
+var (
|
|
|
+ gCrc16Table = crc16.MakeTable(crc16.CRC16_MODBUS) // 选择 Modbus
|
|
|
+)
|
|
|
+
|
|
|
+/************** 快照文件结构体 **************/
|
|
|
+
|
|
|
+type SegmentOfCIBuffer struct {
|
|
|
+ Len uint16 `json:"len"`
|
|
|
+ Crc16 uint16 `json:"crc16"`
|
|
|
+ TimeStamp uint32 `json:"timeStamp"`
|
|
|
+}
|
|
|
+
|
|
|
+type EquipmentSn struct {
|
|
|
+ Len int32 `json:"len"`
|
|
|
+ Data string `json:"data"`
|
|
|
+}
|
|
|
+
|
|
|
+type HwfAlarmDataItem struct {
|
|
|
+ AlarmCode uint16 `json:"alarmCode"` //故障编码
|
|
|
+ Level uint8 `json:"level"` //故障等级
|
|
|
+ NeedSave uint8 `json:"needSave"` //该故障是否需要保存
|
|
|
+ TimeStart uint32 `json:"timeStart"` //该故障的开始时间
|
|
|
+}
|
|
|
+
|
|
|
+type AlarmList struct {
|
|
|
+ Count int32 `json:"count"`
|
|
|
+ DataItem []HwfAlarmDataItem `json:"dataItem"`
|
|
|
+}
|
|
|
+
|
|
|
+type SnapXid struct {
|
|
|
+ IdType uint8 `json:"idType"` // PID : 1, VID : 0
|
|
|
+ DataType uint8 `json:"dataType"` // 0-UINT32 1-INT32 2-FLOAT 3-PCHAR
|
|
|
+ ID uint16 `json:"id"` // 在PID和VID配置表中对应的id, 可基于此找到对应的PID/VID
|
|
|
+}
|
|
|
+
|
|
|
+type XidDataType interface {
|
|
|
+ uint32 | int32 | float32 | string
|
|
|
+}
|
|
|
+
|
|
|
+type XidSegmentHeader struct {
|
|
|
+ Xid SnapXid `json:"xid"`
|
|
|
+ Len int32 `json:"len"` // DATA 的长度
|
|
|
+}
|
|
|
+
|
|
|
+type XidSegment[T XidDataType] struct {
|
|
|
+ Header XidSegmentHeader `json:"header"`
|
|
|
+ Data T `json:"data"` // DATA 取决于 SnapXid.DataType
|
|
|
+}
|
|
|
+
|
|
|
+type XidSegmentType interface {
|
|
|
+ XidSegment[uint32] | XidSegment[int32] | XidSegment[float32] | XidSegment[string]
|
|
|
+}
|
|
|
+
|
|
|
+type XidSegmentIf interface {
|
|
|
+ GetXid() any
|
|
|
+ CreateXid(v any) error
|
|
|
+}
|
|
|
+
|
|
|
+func (x *XidSegment[T]) GetXid() any {
|
|
|
+ return x
|
|
|
+}
|
|
|
+
|
|
|
+func (x *XidSegment[T]) CreateXid(v any) error {
|
|
|
+ val, ok := v.(XidSegment[T])
|
|
|
+ if !ok {
|
|
|
+ return fmt.Errorf("invalid type: expected %T", x.Data)
|
|
|
+ }
|
|
|
+ *x = val
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+type InfoSegmentPackage struct {
|
|
|
+ Header SegmentOfCIBuffer `json:"header"`
|
|
|
+ HeadStr [4]byte `json:"headerStr"` // "HEAD"
|
|
|
+ GateSn EquipmentSn `json:"aGateSn"`
|
|
|
+ PowerSn EquipmentSn `json:"aPowerSn"`
|
|
|
+ Alarm AlarmList `json:"alarm"`
|
|
|
+}
|
|
|
+
|
|
|
+type XidSegmentPackage struct {
|
|
|
+ Header SegmentOfCIBuffer `json:"header"`
|
|
|
+ XidList []XidSegmentIf `json:"xidList"`
|
|
|
+}
|
|
|
+
|
|
|
+type SnapFilePackage struct {
|
|
|
+ Info InfoSegmentPackage `json:"info"`
|
|
|
+ Xid XidSegmentPackage `json:"xid"`
|
|
|
+}
|
|
|
+
|
|
|
+/************** 快照JSON数据结构体 **************/
|
|
|
+
|
|
|
+type AlarmCodeInfo struct {
|
|
|
+ AlarmCode uint16 `json:"alarmCode"` //故障编码
|
|
|
+ Level uint8 `json:"level"` //故障等级
|
|
|
+ TimeStart uint32 `json:"timeStart"` //该故障的开始时间
|
|
|
+}
|
|
|
+
|
|
|
+type AlarmInfoJson struct {
|
|
|
+ Total int32 `json:"total"`
|
|
|
+ AlarmList []AlarmCodeInfo `json:"alarmList"`
|
|
|
+}
|
|
|
+
|
|
|
+type XID[T XidDataType] struct {
|
|
|
+ ID uint16 `json:"id"`
|
|
|
+ Type string `json:"type"` // "PID" or "VID"
|
|
|
+ // Macro string `json:"macro"` // 代码中的宏名称
|
|
|
+ // Brief string `json:"brief"` // 简介
|
|
|
+ Data T `json:"data"`
|
|
|
+}
|
|
|
+
|
|
|
+type XidIf interface {
|
|
|
+ GetXid() any
|
|
|
+ CreateXid(v any) error
|
|
|
+}
|
|
|
+
|
|
|
+func (x *XID[T]) GetXid() any {
|
|
|
+ return x
|
|
|
+}
|
|
|
+
|
|
|
+func (x *XID[T]) CreateXid(v any) error {
|
|
|
+ val, ok := v.(XID[T])
|
|
|
+ if !ok {
|
|
|
+ return fmt.Errorf("invalid type: expected %T", x.Data)
|
|
|
+ }
|
|
|
+ *x = val
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+type SnapInfoJson struct {
|
|
|
+ XidList []XidIf `json:"xidList"`
|
|
|
+}
|
|
|
+
|
|
|
+type SnapJson struct {
|
|
|
+ TimeStamp uint32 `json:"timeStamp"`
|
|
|
+ SiteSn string `json:"aGateSn"`
|
|
|
+ PowerSn []string `json:"aPowerSn"`
|
|
|
+ AlarmInfo AlarmInfoJson `json:"alarmInfo"`
|
|
|
+ SnapInfo SnapInfoJson `json:"snapInfo"`
|
|
|
+}
|
|
|
+
|
|
|
+/************** 解析数据结构体 **************/
|
|
|
+
|
|
|
+type ParserAlarmSnapshot struct {
|
|
|
+ FilePath string `json:"filePath"`
|
|
|
+ FilePackage []SnapFilePackage `json:"filePackage"`
|
|
|
+ SnapJson []SnapJson `json:"snapJson"`
|
|
|
+}
|
|
|
+
|
|
|
+type SegmentDataType struct {
|
|
|
+ Header SegmentOfCIBuffer
|
|
|
+ Data []byte
|
|
|
+}
|
|
|
+
|
|
|
+type SegmentType struct {
|
|
|
+ InfoSegment SegmentDataType
|
|
|
+ XidSegment SegmentDataType
|
|
|
+ BinData []byte
|
|
|
+}
|
|
|
+
|
|
|
+// 创建ParserAlarmSnapshot结果体必须使用函数NewParserAlarmSnapshot
|
|
|
+func NewParserAlarmSnapshot(filePath string) *ParserAlarmSnapshot {
|
|
|
+ return &ParserAlarmSnapshot{
|
|
|
+ FilePath: filePath,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (parser *ParserAlarmSnapshot) ParserSnapFile() error {
|
|
|
+ binData, err := os.ReadFile(parser.FilePath)
|
|
|
+ if err != nil {
|
|
|
+ zap.L().Error("snap文件读取失败", zap.String("err", err.Error()), zap.String("FilePath", parser.FilePath))
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ var newBinData []byte
|
|
|
+ // 寻找第一个有效 "HEAD" 的位置,生成新的连续数据段
|
|
|
+ pRemainingData := binData
|
|
|
+ startIdx := int(0)
|
|
|
+ for {
|
|
|
+ idx := bytes.Index(pRemainingData, []byte("HEAD"))
|
|
|
+ if idx == -1 {
|
|
|
+ fmt.Println("未找到 HEAD 结束")
|
|
|
+ break
|
|
|
+ } else if idx < 8 {
|
|
|
+ // 数据开头不完整,跳到下一个数据
|
|
|
+ pRemainingData = pRemainingData[idx+4:]
|
|
|
+ startIdx = startIdx + idx + 4
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算前8个字节的开始位置
|
|
|
+ start := idx - 8
|
|
|
+ startIdx = startIdx + start
|
|
|
+
|
|
|
+ // 检查有效性
|
|
|
+ _, err := parser.checkSnapData(pRemainingData[start:])
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("第一个数据段无效")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ pHeaderData := binData[:startIdx]
|
|
|
+ pRemainingData = pRemainingData[start:]
|
|
|
+
|
|
|
+ // 重新拼接循环数据
|
|
|
+ newBinData = make([]byte, len(binData))
|
|
|
+ copy(newBinData, pRemainingData)
|
|
|
+ copy(newBinData[len(pRemainingData):], pHeaderData)
|
|
|
+
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ // 声明一个切片,用来存放多个 Segment
|
|
|
+ var segmentList []*SegmentType
|
|
|
+
|
|
|
+ pNewBinData := newBinData
|
|
|
+ pBinIdx := startIdx
|
|
|
+ // 生成数据段列表
|
|
|
+ for {
|
|
|
+ // 检查 HEAD 头
|
|
|
+ if !bytes.Equal(pNewBinData[8:8+4], []byte("HEAD")) {
|
|
|
+ // 往下寻找新的 HEAD 头
|
|
|
+ idx := bytes.Index(pNewBinData, []byte("HEAD"))
|
|
|
+ if idx == -1 {
|
|
|
+ fmt.Println("未找到 HEAD 结束")
|
|
|
+ break
|
|
|
+ } else if idx < 8 {
|
|
|
+ // 数据开头不完整,跳到下一个数据
|
|
|
+ pNewBinData = pNewBinData[idx+4:]
|
|
|
+ pBinIdx = pBinIdx + idx + 4
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ pNewBinData = pNewBinData[idx-8:]
|
|
|
+ pBinIdx = pBinIdx + idx - 8
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查有效性
|
|
|
+ segData, err := parser.checkSnapData(pNewBinData)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Printf("数据段格式错误 index: %d\n", pBinIdx)
|
|
|
+ // 数据开头不完整,跳到下一个数据
|
|
|
+ pNewBinData = pNewBinData[8+4:]
|
|
|
+ pBinIdx = pBinIdx + 8 + 4
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ segmentList = append(segmentList, segData)
|
|
|
+
|
|
|
+ pNewBinData = pNewBinData[len(segData.BinData):]
|
|
|
+ pBinIdx = pBinIdx + len(segData.BinData)
|
|
|
+ if len(pNewBinData) == 0 {
|
|
|
+ // 数据刚好处理完,无剩余无效数据
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理每个数据段
|
|
|
+ for _, pData := range segmentList {
|
|
|
+ var filePackage SnapFilePackage
|
|
|
+ var snapJson SnapJson
|
|
|
+ if err := parser.parserInfoSegment(&filePackage, &snapJson, pData.InfoSegment); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := parser.parserXidSegment(&filePackage, &snapJson, pData.XidSegment); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ parser.FilePackage = append(parser.FilePackage, filePackage)
|
|
|
+ parser.SnapJson = append(parser.SnapJson, snapJson)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// 检验数据的正确性和完整性
|
|
|
+// 1、校验两段SegmentOfCIBuffer的CRC
|
|
|
+// 2、同时检查数据长度是否完整
|
|
|
+func (parser *ParserAlarmSnapshot) checkSnapData(binData []byte) (*SegmentType, error) {
|
|
|
+ // 处理数据段一
|
|
|
+ var infoHeader SegmentOfCIBuffer
|
|
|
+ headerSize := binary.Size(infoHeader)
|
|
|
+ if len(binData) < headerSize {
|
|
|
+ zap.L().Error("snap文件长度异常", zap.String("FilePath", parser.FilePath))
|
|
|
+ return nil, fmt.Errorf("snap文件长度异常")
|
|
|
+ }
|
|
|
+
|
|
|
+ headerRaw := binData[:headerSize] // 头部数据
|
|
|
+ headerReader := bytes.NewReader(headerRaw)
|
|
|
+
|
|
|
+ if err := binary.Read(headerReader, binary.LittleEndian, &infoHeader); err != nil {
|
|
|
+ zap.L().Error("snap文件读取转换失败", zap.String("err", err.Error()), zap.String("FilePath", parser.FilePath))
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取数据长度
|
|
|
+ infoBufferLen := int(infoHeader.Len)
|
|
|
+ if len(binData[headerSize:]) < infoBufferLen {
|
|
|
+ zap.L().Error("snap文件长度异常", zap.String("FilePath", parser.FilePath))
|
|
|
+ return nil, fmt.Errorf("snap文件长度异常")
|
|
|
+ }
|
|
|
+
|
|
|
+ // Info Buffer
|
|
|
+ pInfoBufferRaw := binData[headerSize:]
|
|
|
+ pInfoBufferRaw = pInfoBufferRaw[:infoBufferLen]
|
|
|
+
|
|
|
+ // 校验CRC
|
|
|
+ bufferCrc := infoHeader.Crc16
|
|
|
+ calcCrc := crc16.Checksum(pInfoBufferRaw, gCrc16Table)
|
|
|
+ if bufferCrc != calcCrc {
|
|
|
+ zap.L().Error("snap文件CRC校验失败", zap.String("FilePath", parser.FilePath))
|
|
|
+ return nil, fmt.Errorf("snap文件CRC校验失败")
|
|
|
+ }
|
|
|
+
|
|
|
+ pInfoBufferRaw = pInfoBufferRaw[4:] // 排除 “HEAD” 头
|
|
|
+
|
|
|
+ // 处理数据段二
|
|
|
+ var xidHeader SegmentOfCIBuffer
|
|
|
+ headerSize = binary.Size(xidHeader)
|
|
|
+ secBinData := binData[headerSize+infoBufferLen:]
|
|
|
+ if len(secBinData) < headerSize {
|
|
|
+ zap.L().Error("snap文件长度异常", zap.String("FilePath", parser.FilePath))
|
|
|
+ return nil, fmt.Errorf("snap文件长度异常")
|
|
|
+ }
|
|
|
+
|
|
|
+ headerRaw = secBinData[:headerSize] // 头部数据
|
|
|
+ headerReader = bytes.NewReader(headerRaw)
|
|
|
+
|
|
|
+ if err := binary.Read(headerReader, binary.LittleEndian, &xidHeader); err != nil {
|
|
|
+ zap.L().Error("snap文件读取转换失败", zap.String("err", err.Error()), zap.String("FilePath", parser.FilePath))
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取数据长度
|
|
|
+ xidBufferLen := int(xidHeader.Len)
|
|
|
+ if len(secBinData[headerSize:]) < xidBufferLen {
|
|
|
+ zap.L().Error("snap文件长度异常", zap.String("FilePath", parser.FilePath))
|
|
|
+ return nil, fmt.Errorf("snap文件长度异常")
|
|
|
+ }
|
|
|
+
|
|
|
+ // Xid Buffer
|
|
|
+ pXidBufferRaw := secBinData[headerSize:]
|
|
|
+ pXidBufferRaw = pXidBufferRaw[:xidBufferLen]
|
|
|
+
|
|
|
+ // 校验CRC
|
|
|
+ bufferCrc = xidHeader.Crc16
|
|
|
+ calcCrc = crc16.Checksum(pXidBufferRaw, gCrc16Table)
|
|
|
+ if bufferCrc != calcCrc {
|
|
|
+ zap.L().Error("snap文件CRC校验失败", zap.String("FilePath", parser.FilePath))
|
|
|
+ return nil, fmt.Errorf("snap文件CRC校验失败")
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算数据总长度
|
|
|
+ dataLen := headerSize + infoBufferLen + headerSize + xidBufferLen
|
|
|
+
|
|
|
+ return &SegmentType{
|
|
|
+ InfoSegment: SegmentDataType{
|
|
|
+ Header: infoHeader,
|
|
|
+ Data: pInfoBufferRaw,
|
|
|
+ },
|
|
|
+ XidSegment: SegmentDataType{
|
|
|
+ Header: xidHeader,
|
|
|
+ Data: pXidBufferRaw,
|
|
|
+ },
|
|
|
+ BinData: binData[:dataLen],
|
|
|
+ }, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (parser *ParserAlarmSnapshot) parserInfoSegment(pkg *SnapFilePackage, snapJson *SnapJson, segData SegmentDataType) error {
|
|
|
+ header := segData.Header
|
|
|
+ pkg.Info.Header = header
|
|
|
+
|
|
|
+ // 填充JSON数据
|
|
|
+ snapJson.TimeStamp = header.TimeStamp
|
|
|
+
|
|
|
+ pInfoBufferRaw := segData.Data // Info Buffer
|
|
|
+
|
|
|
+ // 写入数据头标签 HEAD
|
|
|
+ copy(pkg.Info.HeadStr[:], "HEAD")
|
|
|
+
|
|
|
+ equipmentSnLenReader := bytes.NewReader(pInfoBufferRaw[:binary.Size(pkg.Info.GateSn.Len)])
|
|
|
+ if err := binary.Read(equipmentSnLenReader, binary.LittleEndian, &pkg.Info.GateSn.Len); err != nil {
|
|
|
+ zap.L().Error("snap文件读取设备aGate SN长度失败", zap.String("err", err.Error()), zap.String("FilePath", parser.FilePath))
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if pkg.Info.GateSn.Len < 0 {
|
|
|
+ zap.L().Error("snap文件读取设备aGate SN长度小于0", zap.String("len", strconv.Itoa(int(pkg.Info.GateSn.Len))), zap.String("FilePath", parser.FilePath))
|
|
|
+ return fmt.Errorf("snap文件读取设备aGate SN长度小于0")
|
|
|
+ }
|
|
|
+ pInfoBufferRaw = pInfoBufferRaw[binary.Size(pkg.Info.GateSn.Len):]
|
|
|
+
|
|
|
+ // 提取aGate SN
|
|
|
+ equipmentSnDataRaw := pInfoBufferRaw[:pkg.Info.GateSn.Len]
|
|
|
+ pkg.Info.GateSn.Data = string(equipmentSnDataRaw)
|
|
|
+ snapJson.SiteSn = string(equipmentSnDataRaw)
|
|
|
+
|
|
|
+ pInfoBufferRaw = pInfoBufferRaw[pkg.Info.GateSn.Len:]
|
|
|
+
|
|
|
+ equipmentSnLenReader = bytes.NewReader(pInfoBufferRaw[:binary.Size(pkg.Info.PowerSn.Len)])
|
|
|
+ if err := binary.Read(equipmentSnLenReader, binary.LittleEndian, &pkg.Info.PowerSn.Len); err != nil {
|
|
|
+ zap.L().Error("snap文件读取设备aPower SN长度失败", zap.String("err", err.Error()), zap.String("FilePath", parser.FilePath))
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if pkg.Info.PowerSn.Len < 0 {
|
|
|
+ zap.L().Error("snap文件读取设备aPower SN长度小于0", zap.String("len", strconv.Itoa(int(pkg.Info.PowerSn.Len))), zap.String("FilePath", parser.FilePath))
|
|
|
+ return fmt.Errorf("snap文件读取设备aPower SN长度小于0")
|
|
|
+ }
|
|
|
+ pInfoBufferRaw = pInfoBufferRaw[binary.Size(pkg.Info.PowerSn.Len):]
|
|
|
+
|
|
|
+ // 提取aPower SN
|
|
|
+ equipmentSnDataRaw = pInfoBufferRaw[:pkg.Info.PowerSn.Len]
|
|
|
+ pkg.Info.PowerSn.Data = string(equipmentSnDataRaw)
|
|
|
+ snapJson.PowerSn = strings.Split(string(equipmentSnDataRaw), ",")
|
|
|
+
|
|
|
+ pInfoBufferRaw = pInfoBufferRaw[pkg.Info.PowerSn.Len:]
|
|
|
+
|
|
|
+ alarmCountReader := bytes.NewReader(pInfoBufferRaw[:binary.Size(pkg.Info.Alarm.Count)])
|
|
|
+ if err := binary.Read(alarmCountReader, binary.LittleEndian, &pkg.Info.Alarm.Count); err != nil {
|
|
|
+ zap.L().Error("snap文件读取告警数量失败", zap.String("err", err.Error()), zap.String("FilePath", parser.FilePath))
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ snapJson.AlarmInfo.Total = pkg.Info.Alarm.Count
|
|
|
+
|
|
|
+ pInfoBufferRaw = pInfoBufferRaw[binary.Size(pkg.Info.Alarm.Count):]
|
|
|
+
|
|
|
+ for i := 0; i < int(pkg.Info.Alarm.Count); i++ {
|
|
|
+ var alarmDataItem HwfAlarmDataItem
|
|
|
+ alarmDataItemReader := bytes.NewBuffer(pInfoBufferRaw[:binary.Size(alarmDataItem)])
|
|
|
+ if err := binary.Read(alarmDataItemReader, binary.LittleEndian, &alarmDataItem); err != nil {
|
|
|
+ zap.L().Error("snap文件读取告警项失败", zap.String("err", err.Error()), zap.String("FilePath", parser.FilePath))
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ pkg.Info.Alarm.DataItem = append(pkg.Info.Alarm.DataItem, alarmDataItem)
|
|
|
+ snapJson.AlarmInfo.AlarmList = append(snapJson.AlarmInfo.AlarmList, AlarmCodeInfo{
|
|
|
+ AlarmCode: alarmDataItem.AlarmCode,
|
|
|
+ Level: alarmDataItem.Level,
|
|
|
+ TimeStart: alarmDataItem.TimeStart,
|
|
|
+ })
|
|
|
+
|
|
|
+ pInfoBufferRaw = pInfoBufferRaw[binary.Size(alarmDataItem):]
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (parser *ParserAlarmSnapshot) parserXidSegment(pkg *SnapFilePackage, snapJson *SnapJson, segData SegmentDataType) error {
|
|
|
+ header := segData.Header
|
|
|
+
|
|
|
+ pkg.Xid.Header = header
|
|
|
+
|
|
|
+ pXidBufferRaw := segData.Data // Xid Buffer
|
|
|
+
|
|
|
+ for len(pXidBufferRaw) > 0 {
|
|
|
+ var xidHeader XidSegmentHeader
|
|
|
+ snapXidHeaderReader := bytes.NewReader(pXidBufferRaw[:binary.Size(xidHeader)])
|
|
|
+ if err := binary.Read(snapXidHeaderReader, binary.LittleEndian, &xidHeader); err != nil {
|
|
|
+ zap.L().Error("snap文件读取XID数据头失败", zap.String("err", err.Error()), zap.String("FilePath", parser.FilePath))
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ pXidBufferRaw = pXidBufferRaw[binary.Size(xidHeader):]
|
|
|
+
|
|
|
+ var IdTypeStr string
|
|
|
+ switch xidHeader.Xid.IdType {
|
|
|
+ case 0:
|
|
|
+ IdTypeStr = "VID"
|
|
|
+ case 1:
|
|
|
+ IdTypeStr = "PID"
|
|
|
+ default:
|
|
|
+ zap.L().Error("snap文件读取XID数据ID类型错误", zap.String("id_type", strconv.Itoa(int(xidHeader.Xid.IdType))), zap.String("FilePath", parser.FilePath))
|
|
|
+ return fmt.Errorf("snap文件读取XID数据ID类型错误")
|
|
|
+ }
|
|
|
+
|
|
|
+ switch xidHeader.Xid.DataType {
|
|
|
+ case 0:
|
|
|
+ var xid XidSegment[uint32]
|
|
|
+ xid.Header = xidHeader
|
|
|
+ var data uint32
|
|
|
+ if xidHeader.Len != int32(binary.Size(data)) {
|
|
|
+ zap.L().Error("snap文件读取XID数据长度错误", zap.String("type", strconv.Itoa(int(xidHeader.Xid.DataType))), zap.String("len", strconv.Itoa(int(xidHeader.Len))), zap.String("FilePath", parser.FilePath))
|
|
|
+ return fmt.Errorf("snap文件读取XID数据长度错误")
|
|
|
+ }
|
|
|
+ dataReader := bytes.NewReader(pXidBufferRaw[:binary.Size(data)])
|
|
|
+ if err := binary.Read(dataReader, binary.LittleEndian, &data); err != nil {
|
|
|
+ zap.L().Error("snap文件读取XID数据失败", zap.String("err", err.Error()), zap.String("FilePath", parser.FilePath))
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ xid.Data = data
|
|
|
+ pkg.Xid.XidList = append(pkg.Xid.XidList, &xid)
|
|
|
+
|
|
|
+ // 赋值到JSON数据
|
|
|
+ snapJson.SnapInfo.XidList = append(snapJson.SnapInfo.XidList, &XID[uint32]{
|
|
|
+ ID: xidHeader.Xid.ID,
|
|
|
+ Type: IdTypeStr,
|
|
|
+ Data: data,
|
|
|
+ })
|
|
|
+ case 1:
|
|
|
+ var xid XidSegment[int32]
|
|
|
+ xid.Header = xidHeader
|
|
|
+ var data int32
|
|
|
+ if xidHeader.Len != int32(binary.Size(data)) {
|
|
|
+ zap.L().Error("snap文件读取XID数据长度错误", zap.String("type", strconv.Itoa(int(xidHeader.Xid.DataType))), zap.String("len", strconv.Itoa(int(xidHeader.Len))), zap.String("FilePath", parser.FilePath))
|
|
|
+ return fmt.Errorf("snap文件读取XID数据长度错误")
|
|
|
+ }
|
|
|
+ dataReader := bytes.NewReader(pXidBufferRaw[:binary.Size(data)])
|
|
|
+ if err := binary.Read(dataReader, binary.LittleEndian, &data); err != nil {
|
|
|
+ zap.L().Error("snap文件读取XID数据失败", zap.String("err", err.Error()), zap.String("FilePath", parser.FilePath))
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ xid.Data = data
|
|
|
+ pkg.Xid.XidList = append(pkg.Xid.XidList, &xid)
|
|
|
+
|
|
|
+ // 赋值到JSON数据
|
|
|
+ snapJson.SnapInfo.XidList = append(snapJson.SnapInfo.XidList, &XID[int32]{
|
|
|
+ ID: xidHeader.Xid.ID,
|
|
|
+ Type: IdTypeStr,
|
|
|
+ Data: data,
|
|
|
+ })
|
|
|
+ case 2:
|
|
|
+ var xid XidSegment[float32]
|
|
|
+ xid.Header = xidHeader
|
|
|
+ var data float32
|
|
|
+ if xidHeader.Len != int32(binary.Size(data)) {
|
|
|
+ zap.L().Error("snap文件读取XID数据长度错误", zap.String("type", strconv.Itoa(int(xidHeader.Xid.DataType))), zap.String("len", strconv.Itoa(int(xidHeader.Len))), zap.String("FilePath", parser.FilePath))
|
|
|
+ return fmt.Errorf("snap文件读取XID数据长度错误")
|
|
|
+ }
|
|
|
+ dataReader := bytes.NewReader(pXidBufferRaw[:binary.Size(data)])
|
|
|
+ if err := binary.Read(dataReader, binary.LittleEndian, &data); err != nil {
|
|
|
+ zap.L().Error("snap文件读取XID数据失败", zap.String("err", err.Error()), zap.String("FilePath", parser.FilePath))
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ xid.Data = data
|
|
|
+ pkg.Xid.XidList = append(pkg.Xid.XidList, &xid)
|
|
|
+
|
|
|
+ // 赋值到JSON数据
|
|
|
+ snapJson.SnapInfo.XidList = append(snapJson.SnapInfo.XidList, &XID[float32]{
|
|
|
+ ID: xidHeader.Xid.ID,
|
|
|
+ Type: IdTypeStr,
|
|
|
+ Data: data,
|
|
|
+ })
|
|
|
+ case 3:
|
|
|
+ var xid XidSegment[string]
|
|
|
+ xid.Header = xidHeader
|
|
|
+ strBytes := make([]byte, xidHeader.Len)
|
|
|
+ dataReader := bytes.NewReader(pXidBufferRaw[:xidHeader.Len])
|
|
|
+ if err := binary.Read(dataReader, binary.LittleEndian, &strBytes); err != nil {
|
|
|
+ zap.L().Error("snap文件读取XID数据失败", zap.String("err", err.Error()), zap.String("FilePath", parser.FilePath))
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ xid.Data = string(strBytes)
|
|
|
+ pkg.Xid.XidList = append(pkg.Xid.XidList, &xid)
|
|
|
+
|
|
|
+ // 赋值到JSON数据
|
|
|
+ snapJson.SnapInfo.XidList = append(snapJson.SnapInfo.XidList, &XID[string]{
|
|
|
+ ID: xidHeader.Xid.ID,
|
|
|
+ Type: IdTypeStr,
|
|
|
+ Data: xid.Data,
|
|
|
+ })
|
|
|
+ default:
|
|
|
+ zap.L().Error("snap文件读取XID类型错误", zap.String("type", strconv.Itoa(int(xidHeader.Xid.DataType))), zap.String("FilePath", parser.FilePath))
|
|
|
+ return fmt.Errorf("snap文件读取XID类型错误")
|
|
|
+ }
|
|
|
+
|
|
|
+ pXidBufferRaw = pXidBufferRaw[xidHeader.Len:]
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|