Files
amcs/internal/auth/access_tracker.go
Hein 4aed4105aa
Some checks failed
CI / build-and-test (push) Failing after -30m35s
fix(auth): add JSON tags to AccessSnapshot fields for proper serialization
2026-04-05 11:59:08 +02:00

82 lines
1.6 KiB
Go

package auth
import (
"sort"
"sync"
"time"
)
type AccessSnapshot struct {
KeyID string `json:"key_id"`
LastPath string `json:"last_path"`
RemoteAddr string `json:"remote_addr"`
UserAgent string `json:"user_agent"`
RequestCount int `json:"request_count"`
LastAccessedAt time.Time `json:"last_accessed_at"`
}
type AccessTracker struct {
mu sync.RWMutex
entries map[string]AccessSnapshot
}
func NewAccessTracker() *AccessTracker {
return &AccessTracker{entries: make(map[string]AccessSnapshot)}
}
func (t *AccessTracker) Record(keyID, path, remoteAddr, userAgent string, now time.Time) {
if t == nil || keyID == "" {
return
}
t.mu.Lock()
defer t.mu.Unlock()
entry := t.entries[keyID]
entry.KeyID = keyID
entry.LastPath = path
entry.RemoteAddr = remoteAddr
entry.UserAgent = userAgent
entry.LastAccessedAt = now.UTC()
entry.RequestCount++
t.entries[keyID] = entry
}
func (t *AccessTracker) Snapshot() []AccessSnapshot {
if t == nil {
return nil
}
t.mu.RLock()
defer t.mu.RUnlock()
items := make([]AccessSnapshot, 0, len(t.entries))
for _, entry := range t.entries {
items = append(items, entry)
}
sort.Slice(items, func(i, j int) bool {
return items[i].LastAccessedAt.After(items[j].LastAccessedAt)
})
return items
}
func (t *AccessTracker) ConnectedCount(now time.Time, window time.Duration) int {
if t == nil {
return 0
}
cutoff := now.UTC().Add(-window)
t.mu.RLock()
defer t.mu.RUnlock()
count := 0
for _, entry := range t.entries {
if !entry.LastAccessedAt.Before(cutoff) {
count++
}
}
return count
}