func (c *SandboxCache) Get(sandboxID string) (*user.User, error) {
	if err := parseCacheID(sandboxID); err != nil {
		return nil, err
	}
	c.mu.RLock()
	defer c.mu.RUnlock()
	if entry, exists := c.Entries[sandboxID]; exists {
		if err := entry.Valid(c.maxEntryLifetime); err != nil {
			return nil, err
		}
		return entry.user, nil
	}
	return nil, errors.New("cached sandbox id not found")
}
Get returns cached user entry.
package cache
import (
	"errors"
	"fmt"
	"sync"
	"time"
	"github.com/greenpau/caddy-authorize/pkg/user"
)
const defaultSandboxCleanupInternal int = 60
const minSandboxCleanupInternal int = 0
const defaultSandboxMaxEntryLifetime int = 300
const minSandboxMaxEntryLifetime int = 60
type SandboxCacheEntry struct {
	sandboxID string
	createdAt time.Time
	user      *user.User
	expired bool
}
type SandboxCache struct {
	mu sync.RWMutex
	cleanupInternal int
	maxEntryLifetime int
	managed bool
	exit    chan bool
	Entries map[string]*SandboxCacheEntry
}
func NewSandboxCache() *SandboxCache {
	return &SandboxCache{
		cleanupInternal:  defaultSandboxCleanupInternal,
		maxEntryLifetime: defaultSandboxMaxEntryLifetime,
		Entries:          make(map[string]*SandboxCacheEntry),
		exit:             make(chan bool),
	}
}
func (c *SandboxCache) SetCleanupInterval(i int) error {
	if i < 1 {
		return fmt.Errorf("sandbox cache cleanup interval must be equal to or greater than %d", minSandboxCleanupInternal)
	}
	c.cleanupInternal = i
	return nil
}
func (c *SandboxCache) SetMaxEntryLifetime(i int) error {
	if i < 60 {
		return fmt.Errorf("sandbox cache max entry lifetime must be equal to or greater than %d seconds", minSandboxMaxEntryLifetime)
	}
	c.maxEntryLifetime = i
	return nil
}
func manageSandboxCache(c *SandboxCache) {
	c.managed = true
	intervals := time.NewTicker(time.Second * time.Duration(c.cleanupInternal))
	for range intervals.C {
		if c == nil {
			continue
		}
		c.mu.Lock()
		select {
		case <-c.exit:
			c.managed = false
			break
		default:
			break
		}
		if !c.managed {
			c.mu.Unlock()
			break
		}
		if c.Entries == nil {
			c.mu.Unlock()
			continue
		}
		deleteList := []string{}
		for sandboxID, entry := range c.Entries {
			if err := entry.Valid(c.maxEntryLifetime); err != nil {
				deleteList = append(deleteList, sandboxID)
				continue
			}
		}
		if len(deleteList) > 0 {
			for _, sandboxID := range deleteList {
				delete(c.Entries, sandboxID)
			}
		}
		c.mu.Unlock()
	}
	return
}
func (c *SandboxCache) Run() {
	if c.managed {
		return
	}
	go manageSandboxCache(c)
}
func (c *SandboxCache) Stop() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.managed = false
}
func (c *SandboxCache) GetCleanupInterval() int {
	return c.cleanupInternal
}
func (c *SandboxCache) GetMaxEntryLifetime() int {
	return c.maxEntryLifetime
}
func (c *SandboxCache) Add(sandboxID string, u *user.User) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.Entries == nil {
		return errors.New("sandbox cache is not available")
	}
	c.Entries[sandboxID] = &SandboxCacheEntry{
		sandboxID: sandboxID,
		createdAt: time.Now().UTC(),
		user:      u,
	}
	return nil
}
func (c *SandboxCache) Delete(sandboxID string) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.Entries == nil {
		return errors.New("sandbox cache is not available")
	}
	_, exists := c.Entries[sandboxID]
	if !exists {
		return errors.New("cached sandbox id not found")
	}
	delete(c.Entries, sandboxID)
	return nil
}