package store import ( "sync" "time" ) // uploadHistory tracks running total/count of upload durations for one device. type uploadHistory struct { mu sync.Mutex total time.Duration count int64 } func (u *uploadHistory) add(d time.Duration) { u.mu.Lock() defer u.mu.Unlock() u.total += d u.count++ } func (u *uploadHistory) average() time.Duration { u.mu.Lock() defer u.mu.Unlock() if u.count == 0 { return 0 } // Truncating integer division — same idea as C# BigInteger total / count. return u.total / time.Duration(u.count) } func (s *Store) uploadFor(id DeviceID) *uploadHistory { s.mu.Lock() defer s.mu.Unlock() u, ok := s.uploads[id] if !ok { u = &uploadHistory{} s.uploads[id] = u } return u } // AddUpload records an upload duration (nanoseconds as time.Duration) for deviceID. // sent_at from the API is intentionally ignored here; the HTTP layer still accepts it. func (s *Store) AddUpload(deviceID DeviceID, uploadTime time.Duration) { s.uploadFor(deviceID).add(uploadTime) } // AverageUploadTime returns the mean upload duration for deviceID. // Formatting for the API (duration.String()) belongs at the HTTP edge. // Unknown / never-seen devices return 0. func (s *Store) AverageUploadTime(deviceID DeviceID) time.Duration { s.mu.Lock() u, ok := s.uploads[deviceID] s.mu.Unlock() if !ok { return 0 } return u.average() }