78 lines
1.6 KiB
Go
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 }
|