package model import ( "fmt" "sync" "time" ) // DataPointID 数据点标识 type DataPointID struct { DeviceID string // 设备ID MetricCode string // 指标代码 Labels map[string]string // 自定义标签 } // String 返回数据点标识的字符串表示 func (id DataPointID) String() string { return fmt.Sprintf("%s:%s:%v", id.DeviceID, id.MetricCode, id.Labels) } // DataValue 数据值 type DataValue struct { Timestamp time.Time // 时间戳 Value interface{} // 支持 int64 或 float64 } // CircularBuffer 环形缓冲区 type CircularBuffer struct { Values [30]DataValue // 固定大小为30的环形缓冲区 Head int // 当前写入位置 Lock sync.RWMutex // 细粒度锁 } // NewCircularBuffer 创建一个新的环形缓冲区 func NewCircularBuffer() *CircularBuffer { return &CircularBuffer{ Head: -1, // 初始化为-1,表示缓冲区为空 } } // Write 写入一个新的数据值 func (cb *CircularBuffer) Write(value DataValue) { cb.Lock.Lock() defer cb.Lock.Unlock() cb.Head = (cb.Head + 1) % len(cb.Values) cb.Values[cb.Head] = value } // Read 读取所有数据值,按时间顺序返回 func (cb *CircularBuffer) Read() []DataValue { cb.Lock.RLock() defer cb.Lock.RUnlock() if cb.Head == -1 { return []DataValue{} // 缓冲区为空 } result := make([]DataValue, 0, len(cb.Values)) // 从最旧的数据开始 oldest := (cb.Head + 1) % len(cb.Values) // 如果缓冲区未满,oldest可能指向未初始化的元素 // 我们需要检查并跳过这些元素 for i := 0; i < len(cb.Values); i++ { idx := (oldest + i) % len(cb.Values) // 跳过未初始化的元素 if cb.Values[idx].Timestamp.IsZero() { continue } result = append(result, cb.Values[idx]) } return result } // GetLatest 获取最新的数据值 func (cb *CircularBuffer) GetLatest() (DataValue, bool) { cb.Lock.RLock() defer cb.Lock.RUnlock() if cb.Head == -1 { return DataValue{}, false // 缓冲区为空 } return cb.Values[cb.Head], true } // GetDuration 获取最新值的持续时间 func (cb *CircularBuffer) GetDuration() time.Duration { cb.Lock.RLock() defer cb.Lock.RUnlock() if cb.Head == -1 { return 0 // 缓冲区为空 } latest := cb.Values[cb.Head] // 如果只有一个值,无法计算持续时间 if len(cb.Values) == 1 { return 0 } // 查找前一个不同的值 for i := 1; i < len(cb.Values); i++ { idx := (cb.Head - i + len(cb.Values)) % len(cb.Values) prev := cb.Values[idx] // 跳过未初始化的元素 if prev.Timestamp.IsZero() { continue } // 如果值不同,计算持续时间 if prev.Value != latest.Value { return latest.Timestamp.Sub(prev.Timestamp) } } // 所有值都相同,无法计算持续时间 return 0 }