feat(ui): show user's lastAccess (#3342)

* feat(server): update user's lastAccess

* feat(ui): show user's lastAccess
This commit is contained in:
Deluan Quintão
2024-09-30 20:46:10 -04:00
committed by GitHub
parent 5e8085bf3c
commit a9334b7787
10 changed files with 148 additions and 11 deletions
+42
View File
@@ -10,6 +10,7 @@ import (
"net/http"
"net/url"
"strings"
"sync"
"time"
"github.com/go-chi/chi/v5"
@@ -18,8 +19,10 @@ import (
"github.com/navidrome/navidrome/conf"
"github.com/navidrome/navidrome/consts"
"github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/model"
"github.com/navidrome/navidrome/model/request"
"github.com/unrolled/secure"
"golang.org/x/time/rate"
)
func requestLogger(next http.Handler) http.Handler {
@@ -298,3 +301,42 @@ func URLParamsMiddleware(next http.Handler) http.Handler {
next.ServeHTTP(w, r)
})
}
var userAccessLimiter idLimiterMap
func UpdateLastAccessMiddleware(ds model.DataStore) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
usr, ok := request.UserFrom(ctx)
if ok {
userAccessLimiter.Do(usr.ID, func() {
start := time.Now()
ctx, cancel := context.WithTimeout(ctx, time.Second)
defer cancel()
err := ds.User(ctx).UpdateLastAccessAt(usr.ID)
if err != nil {
log.Warn(ctx, "Could not update user's lastAccessAt", "username", usr.UserName,
"elapsed", time.Since(start), err)
} else {
log.Trace(ctx, "Update user's lastAccessAt", "username", usr.UserName,
"elapsed", time.Since(start))
}
})
}
next.ServeHTTP(w, r)
})
}
}
// idLimiterMap is a thread-safe map that stores rate.Sometimes limiters for each user ID.
// Used to make the map type and thread safe.
type idLimiterMap struct {
sm sync.Map
}
func (m *idLimiterMap) Do(id string, f func()) {
limiter, _ := m.sm.LoadOrStore(id, &rate.Sometimes{Interval: 2 * time.Second})
limiter.(*rate.Sometimes).Do(f)
}