package main import ( "sync" ) // Message represents a log entry from the express backend type Message struct { Timestamp int64 `json:"timestamp"` Source string `json:"source"` // "logging" | "diagnostic" | "user" Text []string `json:"text"` } // LogStore is a thread-safe ring buffer for log messages type LogStore struct { mu sync.RWMutex messages []Message head int // next write position full bool // whether buffer has wrapped capacity int } // NewLogStore creates a new log store with the given capacity func NewLogStore(capacity int) *LogStore { return &LogStore{ messages: make([]Message, capacity), capacity: capacity, } } // Add inserts a new message into the store func (s *LogStore) Add(msg Message) { s.mu.Lock() defer s.mu.Unlock() s.messages[s.head] = msg s.head++ if s.head >= s.capacity { s.head = 0 s.full = true } } // Count returns the number of messages in the store func (s *LogStore) Count() int { s.mu.RLock() defer s.mu.RUnlock() if s.full { return s.capacity } return s.head } // GetRecent returns the most recent n messages, newest first func (s *LogStore) GetRecent(n int) []Message { s.mu.RLock() defer s.mu.RUnlock() count := s.Count() if n > count { n = count } if n == 0 { return nil } result := make([]Message, n) pos := s.head - 1 for i := 0; i < n; i++ { if pos < 0 { pos = s.capacity - 1 } result[i] = s.messages[pos] pos-- } return result } // Filter parameters for retrieving logs type FilterParams struct { Limit int // max messages to return (0 = default 100) Before int64 // only messages before this timestamp After int64 // only messages after this timestamp } // GetFiltered returns messages matching the filter criteria func (s *LogStore) GetFiltered(params FilterParams) []Message { s.mu.RLock() defer s.mu.RUnlock() limit := params.Limit if limit <= 0 { limit = 100 } count := s.Count() if count == 0 { return nil } result := make([]Message, 0, limit) pos := s.head - 1 for i := 0; i < count && len(result) < limit; i++ { if pos < 0 { pos = s.capacity - 1 } msg := s.messages[pos] // Apply filters if params.Before > 0 && msg.Timestamp >= params.Before { pos-- continue } if params.After > 0 && msg.Timestamp <= params.After { pos-- continue } result = append(result, msg) pos-- } return result }