feat(app): add lightweight status access tracking
This commit is contained in:
81
internal/auth/access_tracker.go
Normal file
81
internal/auth/access_tracker.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AccessSnapshot struct {
|
||||
KeyID string
|
||||
LastPath string
|
||||
RemoteAddr string
|
||||
UserAgent string
|
||||
RequestCount int
|
||||
LastAccessedAt time.Time
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user