62 lines
1.7 KiB
Go
62 lines
1.7 KiB
Go
package rest
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/patrickmn/go-cache"
|
|
)
|
|
|
|
// LoadingCache defines interface for caching
|
|
type LoadingCache interface {
|
|
Get(key string, ttl time.Duration, fn func() ([]byte, error)) (data []byte, err error)
|
|
Flush()
|
|
}
|
|
|
|
// loadingCache implements LoadingCache interface on top of cache.Cache
|
|
type loadingCache struct {
|
|
bytesCache *cache.Cache
|
|
postFlushFn func()
|
|
}
|
|
|
|
// NewLoadingCache makes loadingCache implementation
|
|
func NewLoadingCache(defaultExpiration, cleanupInterval time.Duration, postFlushFn func()) LoadingCache {
|
|
return &loadingCache{bytesCache: cache.New(defaultExpiration, cleanupInterval), postFlushFn: postFlushFn}
|
|
}
|
|
|
|
// Get is loading cache method to get value by key or load via fn if not found
|
|
func (lc *loadingCache) Get(key string, ttl time.Duration, fn func() ([]byte, error)) (data []byte, err error) {
|
|
if b, ok := lc.bytesCache.Get(key); ok {
|
|
log.Printf("[DEBUG] cache hit %s", key)
|
|
return b.([]byte), nil
|
|
}
|
|
|
|
log.Printf("[DEBUG] cache miss %s", key)
|
|
if data, err = fn(); err != nil {
|
|
return data, err
|
|
}
|
|
lc.bytesCache.Set(key, data, ttl)
|
|
return data, nil
|
|
}
|
|
|
|
// Flush clears cache and calls postFlushFn async
|
|
func (lc *loadingCache) Flush() {
|
|
lc.bytesCache.Flush()
|
|
if lc.postFlushFn != nil {
|
|
go lc.postFlushFn()
|
|
}
|
|
}
|
|
|
|
// URLKey gets url from request to use is as cache key
|
|
// admins will have separate keys in order tp prevent leak of admin-only data to regular users
|
|
func URLKey(r *http.Request) string {
|
|
adminPrefix := "admin!!"
|
|
key := strings.TrimPrefix(r.URL.String(), adminPrefix) // prevents attach with fake url to get admin view
|
|
if user, err := GetUserInfo(r); err == nil && user.Admin { // make seprate cache key for admins
|
|
key = adminPrefix + key
|
|
}
|
|
return key
|
|
}
|