InMemoryCaptchaDB is now within its own package alongside with an instance.
This commit is contained in:
parent
0e0c91b5c2
commit
4078bb03bc
157
pkg/captcha/inmemdb/inmemdb.go
Normal file
157
pkg/captcha/inmemdb/inmemdb.go
Normal file
@ -0,0 +1,157 @@
|
||||
package inmemdb
|
||||
|
||||
import (
|
||||
"image"
|
||||
"justcaptcha/pkg/captcha"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type InMemoryCaptchaDB struct {
|
||||
sync.Mutex
|
||||
|
||||
db map[captcha.ID]captcha.Captcha
|
||||
expiry time.Duration
|
||||
expiryScanInterval time.Duration
|
||||
}
|
||||
|
||||
// NewInMemoryCaptchaDB returns an initialised instance of an InMemoryCaptchaDB.
|
||||
// An expiry duration is a time for how long CAPTCHA will be valid.
|
||||
func NewInMemoryCaptchaDB(expiry time.Duration) *InMemoryCaptchaDB {
|
||||
db := &InMemoryCaptchaDB{
|
||||
db: make(map[captcha.ID]captcha.Captcha),
|
||||
expiry: expiry}
|
||||
|
||||
if expiry < captcha.DefaultExpiredScanInterval {
|
||||
db.expiryScanInterval = expiry
|
||||
} else {
|
||||
db.expiryScanInterval = captcha.DefaultExpiredScanInterval
|
||||
}
|
||||
|
||||
go db.cleanExpired()
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
// New accepts a CAPTHA instance, generates an ID and store it in a database.
|
||||
// A data string is an additional random data used to generate an ID,
|
||||
// e.g. an IP-address.
|
||||
func (imcdb *InMemoryCaptchaDB) New(data string, cptcha captcha.Captcha) (captcha.Captcha, captcha.ID) {
|
||||
id := captcha.NewID(data, cptcha.Answer())
|
||||
|
||||
imcdb.Lock()
|
||||
imcdb.db[id] = cptcha
|
||||
imcdb.Unlock()
|
||||
|
||||
return cptcha, id
|
||||
}
|
||||
|
||||
// GetExpiry returns time for how long CAPTCHA will last.
|
||||
func (imcdb *InMemoryCaptchaDB) GetExpiry() time.Duration {
|
||||
return imcdb.expiry
|
||||
}
|
||||
|
||||
// SetExpiry changes an expiry duration to a new one.
|
||||
func (imcdb *InMemoryCaptchaDB) SetExpiry(expiry time.Duration) {
|
||||
if expiry < captcha.DefaultExpiredScanInterval {
|
||||
imcdb.expiryScanInterval = expiry
|
||||
} else {
|
||||
imcdb.expiryScanInterval = captcha.DefaultExpiredScanInterval
|
||||
}
|
||||
}
|
||||
|
||||
// Image returns a freshly generated image for a CAPTCHA.
|
||||
func (imcdb *InMemoryCaptchaDB) Image(id captcha.ID, style string) (*image.Image, error) {
|
||||
imcdb.Lock()
|
||||
defer imcdb.Unlock()
|
||||
if c, ok := imcdb.db[id]; ok {
|
||||
return c.Image(style), nil
|
||||
}
|
||||
return nil, captcha.ErrorNotFound
|
||||
}
|
||||
|
||||
// Solve compares given answer with a stored one and if failed
|
||||
// deletes a CAPTCHA from database.
|
||||
func (imcdb *InMemoryCaptchaDB) Solve(id captcha.ID, answer captcha.Answer) (bool, error) {
|
||||
imcdb.Lock()
|
||||
defer imcdb.Unlock()
|
||||
if c, ok := imcdb.db[id]; ok {
|
||||
ok = c.Solve(answer)
|
||||
if !ok {
|
||||
delete(imcdb.db, id)
|
||||
}
|
||||
return ok, nil
|
||||
}
|
||||
return false, captcha.ErrorNotFound
|
||||
}
|
||||
|
||||
// IsSolved checks if CAPTCHA was solved and removes it
|
||||
// from a database.
|
||||
func (imcdb *InMemoryCaptchaDB) IsSolved(id captcha.ID) (bool, error) {
|
||||
imcdb.Lock()
|
||||
defer imcdb.Unlock()
|
||||
if c, ok := imcdb.db[id]; ok {
|
||||
delete(imcdb.db, id)
|
||||
return c.IsSolved(), nil
|
||||
}
|
||||
return false, captcha.ErrorNotFound
|
||||
}
|
||||
|
||||
// Remove a CAPTCHA from a database.
|
||||
func (imcdb *InMemoryCaptchaDB) Remove(id captcha.ID) error {
|
||||
imcdb.Lock()
|
||||
defer imcdb.Unlock()
|
||||
if _, ok := imcdb.db[id]; ok {
|
||||
delete(imcdb.db, id)
|
||||
return nil
|
||||
}
|
||||
return captcha.ErrorNotFound
|
||||
}
|
||||
|
||||
// cleanExpired removes expired CAPTCHAs in a loop.
|
||||
func (imcdb *InMemoryCaptchaDB) cleanExpired() {
|
||||
for {
|
||||
sleepFor := imcdb.expiryScanInterval - (time.Duration(time.Now().Second()) % imcdb.expiryScanInterval)
|
||||
time.Sleep(sleepFor)
|
||||
|
||||
imcdb.Lock()
|
||||
for id, captcha := range imcdb.db {
|
||||
if time.Since(captcha.Expiry()) >= imcdb.expiry {
|
||||
delete(imcdb.db, id)
|
||||
}
|
||||
}
|
||||
imcdb.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// An instance of InMemoryCaptchaDB
|
||||
|
||||
var imcdb = NewInMemoryCaptchaDB(captcha.DefaultExpiredScanInterval)
|
||||
|
||||
func GetExpiry() time.Duration {
|
||||
return imcdb.GetExpiry()
|
||||
}
|
||||
|
||||
func SetExpiry(expiry time.Duration) {
|
||||
imcdb.SetExpiry(expiry)
|
||||
}
|
||||
|
||||
func New(data string, captcha captcha.Captcha) (captcha.Captcha, captcha.ID) {
|
||||
return imcdb.New(data, captcha)
|
||||
}
|
||||
|
||||
func Image(id captcha.ID, style string) (*image.Image, error) {
|
||||
return imcdb.Image(id, style)
|
||||
}
|
||||
|
||||
func Solve(id captcha.ID, answer captcha.Answer) (bool, error) {
|
||||
return imcdb.Solve(id, answer)
|
||||
}
|
||||
|
||||
func IsSolved(id captcha.ID) (bool, error) {
|
||||
return imcdb.IsSolved(id)
|
||||
}
|
||||
|
||||
func Remove(id captcha.ID) error {
|
||||
return imcdb.Remove(id)
|
||||
}
|
Loading…
Reference in New Issue
Block a user