内存键值对存储
场景 验证码
package base64Captcha// Store An object implementing Store interface can be registered with SetCustomStore // function to handle storage and retrieval of captcha ids and solutions for // them, replacing the default memory store. // // It is the responsibility of an object to delete expired and used captchas // when necessary (for example, the default memory store collects them in Set // method after the certain amount of captchas has been stored.) type Store interface { // Set sets the digits for the captcha id. Set(id string, value string) error
// Get returns stored digits for the captcha id. Clear indicates // whether the captcha must be deleted from the store. Get(id string, clear bool) string
//Verify captcha's answer directly Verify(id, answer string, clear bool) bool }
github.com\mojocn\base64!captcha@v1.3.5\interface_store.go
github.com\mojocn\base64!captcha@v1.3.5\store_memory.go
package base64Captcha import ( "container/list" "sync" "time" ) // expValue stores timestamp and id of captchas. It is used in the list inside // memoryStore for indexing generated captchas by timestamp to enable garbage // collection of expired captchas. type idByTimeValue struct { timestamp time.Time id string } // memoryStore is an internal store for captcha ids and their values. type memoryStore struct { sync.RWMutex digitsById map[string]string idByTime *list.List // Number of items stored since last collection. numStored int // Number of saved items that triggers collection. collectNum int // Expiration time of captchas. expiration time.Duration } // NewMemoryStore returns a new standard memory store for captchas with the // given collection threshold and expiration time (duration). The returned // store must be registered with SetCustomStore to replace the default one. func NewMemoryStore(collectNum int, expiration time.Duration) Store { s := new(memoryStore) s.digitsById = make(map[string]string) s.idByTime = list.New() s.collectNum = collectNum s.expiration = expiration return s } func (s *memoryStore) Set(id string, value string) error { s.Lock() s.digitsById[id] = value s.idByTime.PushBack(idByTimeValue{time.Now(), id}) s.numStored++ s.Unlock() if s.numStored > s.collectNum { go s.collect() } return nil } func (s *memoryStore) Verify(id, answer string, clear bool) bool { v := s.Get(id, clear) return v == answer } func (s *memoryStore) Get(id string, clear bool) (value string) { if !clear { // When we don't need to clear captcha, acquire read lock. s.RLock() defer s.RUnlock() } else { s.Lock() defer s.Unlock() } value, ok := s.digitsById[id] if !ok { return } if clear { delete(s.digitsById, id) } return } func (s *memoryStore) collect() { now := time.Now() s.Lock() defer s.Unlock() for e := s.idByTime.Front(); e != nil; { e = s.collectOne(e, now) } } func (s *memoryStore) collectOne(e *list.Element, specifyTime time.Time) *list.Element { ev, ok := e.Value.(idByTimeValue) if !ok { return nil } if ev.timestamp.Add(s.expiration).Before(specifyTime) { delete(s.digitsById, ev.id) next := e.Next() s.idByTime.Remove(e) s.numStored-- return next } return nil }Go进阶37:重构我的base64Captcha图形验证码项目 | ?????? https://mojotv.cn/go/refactor-base64-captcha