package bcap import ( "sync" "time" "github.com/gopacket/gopacket" ) type Analyzer struct { decoder *Decoder tracker *Tracker mu sync.Mutex firstPacketTS time.Time } func NewAnalyzer() *Analyzer { return NewAnalyzerWithConfig(nil) } func NewAnalyzerWithConfig(config *PacketsConfig) *Analyzer { return &Analyzer{ decoder: NewDecoder(), tracker: NewTrackerWithConfig(config), } } func (a *Analyzer) Stop() { if a.tracker != nil { a.tracker.Stop() } } func (a *Analyzer) Decoder() *Decoder { return a.decoder } func (a *Analyzer) Tracker() *Tracker { return a.tracker } func (a *Analyzer) ObservePacket(packet gopacket.Packet) (Observation, error) { return a.ObservePacketWithOptions(packet, DecodeOptions{}) } func (a *Analyzer) ObservePacketWithOptions(packet gopacket.Packet, opts DecodeOptions) (Observation, error) { if opts.BaseTime.IsZero() { opts.BaseTime = a.ensureBaseTime(packet) } decoded, err := a.decoder.DecodeWithOptions(packet, opts) if err != nil { return Observation{}, err } return a.tracker.Observe(decoded) } func (a *Analyzer) ensureBaseTime(packet gopacket.Packet) time.Time { a.mu.Lock() defer a.mu.Unlock() if packet == nil { return time.Time{} } metadata := packet.Metadata() if metadata == nil || metadata.Timestamp.IsZero() { return time.Time{} } if a.firstPacketTS.IsZero() { a.firstPacketTS = metadata.Timestamp } return a.firstPacketTS }