内存键值对存储

 

场景  验证码

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

 

posted @ 2022-01-20 11:17  papering  阅读(67)  评论(0编辑  收藏  举报