package storage import ( "math/rand/v2" "sync" "time" ) func NewRamStore(clearInterval time.Duration) Store { store := &ram{ clearInterval: clearInterval, passwords: make(map[string]entry), lock: sync.Mutex{}, close: make(chan bool), } go store.clearExpired() return store } type ram struct { clearInterval time.Duration passwords map[string]entry lock sync.Mutex close chan bool } func (store *ram) CreatePassword(password []byte, expiresAt time.Time) (string, error) { store.lock.Lock() defer store.lock.Unlock() for range 1000 { id := store.generateId(24) _, found := store.passwords[id] if found { continue } store.passwords[id] = entry{ password: password, expiresAt: expiresAt, } return id, nil } return "", ErrFull } func (store *ram) GetPassword(id string) ([]byte, error) { store.lock.Lock() defer store.lock.Unlock() password, found := store.passwords[id] if !found { return nil, ErrNotFound } delete(store.passwords, id) return password.password, nil } func (store *ram) HasPassword(id string) (bool, error) { store.lock.Lock() defer store.lock.Unlock() _, found := store.passwords[id] return found, nil } func (store *ram) Close() error { store.close <- true return nil } func (store *ram) clearExpired() error { ticker := time.NewTicker(store.clearInterval) defer ticker.Stop() for { select { case <-store.close: return nil case <-ticker.C: store.lock.Lock() time := time.Now() for id, password := range store.passwords { if time.After(password.expiresAt) { delete(store.passwords, id) } } store.lock.Unlock() } } } func (store *ram) generateId(length int) string { runes := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") str := make([]rune, length) for i := range str { str[i] = runes[rand.IntN(len(runes))] } return string(str) }