You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
2.3 KiB

// Copyright 2018 Lars Hoogestraat
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package session
import (
// Provider an interface for storing and accessing sessions
type Provider interface {
Create(sid string) *Session
Get(sid string) (*Session, error)
FindByValue(key string, value interface{}) []*Session
Remove(sid string)
Clean(ticker *time.Ticker, timeoutAfter time.Duration)
// InMemoryProvider implements a in memory storage for sessions
type InMemoryProvider struct {
sessions map[string]*Session
mutex sync.RWMutex
// NewInMemoryProvider creates a new in memory provider
func NewInMemoryProvider() *InMemoryProvider {
return &InMemoryProvider{
sessions: make(map[string]*Session),
// Create stores a session in the map
func (imp *InMemoryProvider) Create(sid string) *Session {
defer imp.mutex.Unlock()
imp.sessions[sid] = &Session{
sid: sid,
lastTouched: time.Now(),
values: make(map[string]interface{}),
return imp.sessions[sid]
// Get receives the session from the map by the session identifier
func (imp *InMemoryProvider) Get(sid string) (*Session, error) {
defer imp.mutex.RUnlock()
if sess, ok := imp.sessions[sid]; ok {
sess.lastTouched = time.Now()
return sess, nil
return nil, fmt.Errorf("no session with id %s found", sid)
// FindByValue finds all sessions from the map found by the key and value
func (imp *InMemoryProvider) FindByValue(key string, value interface{}) []*Session {
defer imp.mutex.RUnlock()
var sessions []*Session
for _, s := range imp.sessions {
if s.values[key] == value {
sessions = append(sessions, s)
return sessions
// Remove removes a session by the session identifier from the map
func (imp *InMemoryProvider) Remove(sid string) {
defer imp.mutex.Unlock()
delete(imp.sessions, sid)
// Clean clean sessions after the specified timeout
func (imp *InMemoryProvider) Clean(ticker *time.Ticker, timeoutAfter time.Duration) {
go func() {
for range ticker.C {
for key, value := range imp.sessions {
if time.Now().After(value.lastTouched.Add(timeoutAfter)) {
delete(imp.sessions, key)