Struct's fields made private. expireScanInterval made into a field. SetExpiry() removed. Now go routine for expiry check is in a cleanExpired() private method and being called by a constructor. Implemented a constructor for InMemoryCaptchaDB.
This commit is contained in:
parent
b7ba27b613
commit
7737c360d0
@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
var errorNotFound = errors.New("captcha not found")
|
var errorNotFound = errors.New("captcha not found")
|
||||||
|
|
||||||
var expiredScanInterval = 60 * time.Second
|
var defaultExpiredScanInterval = 60 * time.Second
|
||||||
|
|
||||||
type ID string
|
type ID string
|
||||||
|
|
||||||
@ -29,19 +29,36 @@ func NewID(additionalData string, answer Answer) ID {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CaptchaDB interface {
|
type CaptchaDB interface {
|
||||||
New(data string) (Captcha, ID)
|
New(data string, captcha Captcha) (Captcha, ID)
|
||||||
SetExpiry(expiry time.Duration)
|
|
||||||
GetExpiry() time.Duration
|
GetExpiry() time.Duration
|
||||||
Image(id ID) (*image.Image, error)
|
Image(id ID, style string) (*image.Image, error)
|
||||||
Solve(id ID, answer Answer) (bool, error)
|
Solve(id ID, answer Answer) (bool, error)
|
||||||
IsSolved(id ID) bool
|
IsSolved(id ID) (bool, error)
|
||||||
|
cleanExpired()
|
||||||
}
|
}
|
||||||
|
|
||||||
type InMemoryCaptchaDB struct {
|
type InMemoryCaptchaDB struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
|
||||||
DB map[ID]Captcha
|
db map[ID]Captcha
|
||||||
ExpireIn time.Duration
|
expireIn time.Duration
|
||||||
|
expireScanInterval time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInMemoryCaptchaDB(expire time.Duration) *InMemoryCaptchaDB {
|
||||||
|
db := &InMemoryCaptchaDB{
|
||||||
|
db: make(map[ID]Captcha),
|
||||||
|
expireIn: expire}
|
||||||
|
|
||||||
|
if expire < defaultExpiredScanInterval {
|
||||||
|
db.expireScanInterval = expire
|
||||||
|
} else {
|
||||||
|
db.expireScanInterval = defaultExpiredScanInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
db.cleanExpired()
|
||||||
|
|
||||||
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
// New accepts an Captcha instance, generates an ID and store it in a database.
|
// New accepts an Captcha instance, generates an ID and store it in a database.
|
||||||
@ -51,29 +68,23 @@ func (cdb *InMemoryCaptchaDB) New(data string, captcha Captcha) (Captcha, ID) {
|
|||||||
id := NewID(data, captcha.GetAnswer())
|
id := NewID(data, captcha.GetAnswer())
|
||||||
|
|
||||||
cdb.Lock()
|
cdb.Lock()
|
||||||
cdb.DB[id] = captcha
|
cdb.db[id] = captcha
|
||||||
cdb.Unlock()
|
cdb.Unlock()
|
||||||
|
|
||||||
return captcha, id
|
return captcha, id
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetExpiry stores expire value and starts a goroutine
|
// cleanExpired starts a goroutine that deletes expired CAPTCHAs.
|
||||||
// that checks for expired CAPTCHAs.
|
func (cdb *InMemoryCaptchaDB) cleanExpired() {
|
||||||
func (cdb *InMemoryCaptchaDB) SetExpiry(expire time.Duration) {
|
|
||||||
cdb.ExpireIn = expire
|
|
||||||
if expire < expiredScanInterval {
|
|
||||||
expiredScanInterval = expire
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
sleepFor := expiredScanInterval - (time.Duration(time.Now().Second()) % expiredScanInterval)
|
sleepFor := cdb.expireScanInterval - (time.Duration(time.Now().Second()) % cdb.expireScanInterval)
|
||||||
time.Sleep(sleepFor)
|
time.Sleep(sleepFor)
|
||||||
|
|
||||||
cdb.Lock()
|
cdb.Lock()
|
||||||
for id, captcha := range cdb.DB {
|
for id, captcha := range cdb.db {
|
||||||
if time.Since(captcha.Expiry()) >= cdb.ExpireIn {
|
if time.Since(captcha.Expiry()) >= cdb.expireIn {
|
||||||
delete(cdb.DB, id)
|
delete(cdb.db, id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cdb.Unlock()
|
cdb.Unlock()
|
||||||
@ -83,14 +94,14 @@ func (cdb *InMemoryCaptchaDB) SetExpiry(expire time.Duration) {
|
|||||||
|
|
||||||
// GetExpiry returns time for how long captcha will last.
|
// GetExpiry returns time for how long captcha will last.
|
||||||
func (cdb *InMemoryCaptchaDB) GetExpiry() time.Duration {
|
func (cdb *InMemoryCaptchaDB) GetExpiry() time.Duration {
|
||||||
return cdb.ExpireIn
|
return cdb.expireIn
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image returns image for a captcha.
|
// Image returns image for a captcha.
|
||||||
func (cdb *InMemoryCaptchaDB) Image(id ID, style string) (*image.Image, error) {
|
func (cdb *InMemoryCaptchaDB) Image(id ID, style string) (*image.Image, error) {
|
||||||
cdb.Lock()
|
cdb.Lock()
|
||||||
defer cdb.Unlock()
|
defer cdb.Unlock()
|
||||||
if c, ok := cdb.DB[id]; ok {
|
if c, ok := cdb.db[id]; ok {
|
||||||
return c.Image(style), nil
|
return c.Image(style), nil
|
||||||
}
|
}
|
||||||
return nil, errorNotFound
|
return nil, errorNotFound
|
||||||
@ -101,10 +112,10 @@ func (cdb *InMemoryCaptchaDB) Image(id ID, style string) (*image.Image, error) {
|
|||||||
func (cdb *InMemoryCaptchaDB) Solve(id ID, answer Answer) (bool, error) {
|
func (cdb *InMemoryCaptchaDB) Solve(id ID, answer Answer) (bool, error) {
|
||||||
cdb.Lock()
|
cdb.Lock()
|
||||||
defer cdb.Unlock()
|
defer cdb.Unlock()
|
||||||
if c, ok := cdb.DB[id]; ok {
|
if c, ok := cdb.db[id]; ok {
|
||||||
ok = c.Solve(answer)
|
ok = c.Solve(answer)
|
||||||
if !ok {
|
if !ok {
|
||||||
delete(cdb.DB, id)
|
delete(cdb.db, id)
|
||||||
}
|
}
|
||||||
return ok, nil
|
return ok, nil
|
||||||
}
|
}
|
||||||
@ -116,9 +127,9 @@ func (cdb *InMemoryCaptchaDB) Solve(id ID, answer Answer) (bool, error) {
|
|||||||
func (cdb *InMemoryCaptchaDB) IsSolved(id ID) (bool, error) {
|
func (cdb *InMemoryCaptchaDB) IsSolved(id ID) (bool, error) {
|
||||||
cdb.Lock()
|
cdb.Lock()
|
||||||
defer cdb.Unlock()
|
defer cdb.Unlock()
|
||||||
if c, ok := cdb.DB[id]; ok {
|
if c, ok := cdb.db[id]; ok {
|
||||||
ok = c.IsSolved()
|
ok = c.IsSolved()
|
||||||
delete(cdb.DB, id)
|
delete(cdb.db, id)
|
||||||
return ok, nil
|
return ok, nil
|
||||||
}
|
}
|
||||||
return false, errorNotFound
|
return false, errorNotFound
|
||||||
|
Loading…
Reference in New Issue
Block a user