mirror of
https://github.com/alexedwards/scs.git
synced 2025-07-13 01:00:17 +02:00
142 lines
3.4 KiB
Go
142 lines
3.4 KiB
Go
package memstore
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type item struct {
|
|
object []byte
|
|
expiration int64
|
|
}
|
|
|
|
// MemStore represents the session store.
|
|
type MemStore struct {
|
|
items map[string]item
|
|
mu sync.RWMutex
|
|
stopCleanup chan bool
|
|
}
|
|
|
|
// New returns a new MemStore instance, with a background cleanup goroutine that
|
|
// runs every minute to remove expired session data.
|
|
func New() *MemStore {
|
|
return NewWithCleanupInterval(time.Minute)
|
|
}
|
|
|
|
// NewWithCleanupInterval returns a new MemStore instance. The cleanupInterval
|
|
// parameter controls how frequently expired session data is removed by the
|
|
// background cleanup goroutine. Setting it to 0 prevents the cleanup goroutine
|
|
// from running (i.e. expired sessions will not be removed).
|
|
func NewWithCleanupInterval(cleanupInterval time.Duration) *MemStore {
|
|
m := &MemStore{
|
|
items: make(map[string]item),
|
|
}
|
|
|
|
if cleanupInterval > 0 {
|
|
go m.startCleanup(cleanupInterval)
|
|
}
|
|
|
|
return m
|
|
}
|
|
|
|
// Find returns the data for a given session token from the MemStore instance.
|
|
// If the session token is not found or is expired, the returned exists flag will
|
|
// be set to false.
|
|
func (m *MemStore) Find(token string) ([]byte, bool, error) {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
item, found := m.items[token]
|
|
if !found {
|
|
return nil, false, nil
|
|
}
|
|
|
|
if time.Now().UnixNano() > item.expiration {
|
|
return nil, false, nil
|
|
}
|
|
|
|
return item.object, true, nil
|
|
}
|
|
|
|
// Commit adds a session token and data to the MemStore instance with the given
|
|
// expiry time. If the session token already exists, then the data and expiry
|
|
// time are updated.
|
|
func (m *MemStore) Commit(token string, b []byte, expiry time.Time) error {
|
|
m.mu.Lock()
|
|
m.items[token] = item{
|
|
object: b,
|
|
expiration: expiry.UnixNano(),
|
|
}
|
|
m.mu.Unlock()
|
|
|
|
return nil
|
|
}
|
|
|
|
// Delete removes a session token and corresponding data from the MemStore
|
|
// instance.
|
|
func (m *MemStore) Delete(token string) error {
|
|
m.mu.Lock()
|
|
delete(m.items, token)
|
|
m.mu.Unlock()
|
|
|
|
return nil
|
|
}
|
|
|
|
// All returns a map containing the token and data for all active (i.e.
|
|
// not expired) sessions.
|
|
func (m *MemStore) All() (map[string][]byte, error) {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
var mm = make(map[string][]byte)
|
|
|
|
for token, item := range m.items {
|
|
if item.expiration > time.Now().UnixNano() {
|
|
mm[token] = item.object
|
|
}
|
|
}
|
|
|
|
return mm, nil
|
|
}
|
|
|
|
func (m *MemStore) startCleanup(interval time.Duration) {
|
|
m.stopCleanup = make(chan bool)
|
|
ticker := time.NewTicker(interval)
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
m.deleteExpired()
|
|
case <-m.stopCleanup:
|
|
ticker.Stop()
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// StopCleanup terminates the background cleanup goroutine for the MemStore
|
|
// instance. It's rare to terminate this; generally MemStore instances and
|
|
// their cleanup goroutines are intended to be long-lived and run for the lifetime
|
|
// of your application.
|
|
//
|
|
// There may be occasions though when your use of the MemStore is transient.
|
|
// An example is creating a new MemStore instance in a test function. In this
|
|
// scenario, the cleanup goroutine (which will run forever) will prevent the
|
|
// MemStore object from being garbage collected even after the test function
|
|
// has finished. You can prevent this by manually calling StopCleanup.
|
|
func (m *MemStore) StopCleanup() {
|
|
if m.stopCleanup != nil {
|
|
m.stopCleanup <- true
|
|
}
|
|
}
|
|
|
|
func (m *MemStore) deleteExpired() {
|
|
now := time.Now().UnixNano()
|
|
m.mu.Lock()
|
|
for token, item := range m.items {
|
|
if now > item.expiration {
|
|
delete(m.items, token)
|
|
}
|
|
}
|
|
m.mu.Unlock()
|
|
}
|