Files

78 lines
1.6 KiB
Go

package users_service
import (
"log"
"sync"
"time"
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
)
type user struct {
DisplayName string
Verified bool
}
// Cache atomically replaces snapshots and throttles refreshes, including misses.
// Failed authentication lookups preserve the last usable display-name snapshot.
type Cache struct {
mu sync.RWMutex
refresh sync.Mutex
users map[string]user
updated time.Time
enabled bool
}
func New(enabled bool) *Cache { return &Cache{users: make(map[string]user), enabled: enabled} }
func (c *Cache) Refresh() {
if !c.enabled {
return
}
c.refresh.Lock()
defer c.refresh.Unlock()
c.mu.RLock()
recent := time.Since(c.updated) < time.Minute
c.mu.RUnlock()
if recent {
return
}
users, err := casdoorsdk.GetUsers()
c.mu.Lock()
defer c.mu.Unlock()
c.updated = time.Now()
if err != nil {
log.Printf("[W] cannot refresh author cache: %v", err)
return
}
snapshot := make(map[string]user, len(users))
for _, u := range users {
name := u.DisplayName
if name == "" {
name = u.Name
}
snapshot[u.Id] = user{DisplayName: name, Verified: u.IsAdmin || u.Tag == "verified"}
}
c.users = snapshot
}
func (c *Cache) lookup(id string) (user, bool) {
c.mu.RLock()
stale := time.Since(c.updated) >= time.Minute
c.mu.RUnlock()
if stale {
c.Refresh()
}
c.mu.RLock()
defer c.mu.RUnlock()
u, ok := c.users[id]
return u, ok
}
func (c *Cache) ResolveAuthor(id, fallback string) string {
if u, ok := c.lookup(id); ok && u.DisplayName != "" {
return u.DisplayName
}
return fallback
}
func (c *Cache) IsVerified(id string) bool { u, ok := c.lookup(id); return ok && u.Verified }