96 lines
1.6 KiB
Go
96 lines
1.6 KiB
Go
package main
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
func init() {
|
|
db = NewDB()
|
|
}
|
|
|
|
type DB struct {
|
|
data map[string]map[string]time.Time
|
|
lock *sync.Mutex
|
|
timeout time.Duration
|
|
}
|
|
|
|
func (db *DB) Lookup(name string) []string {
|
|
now := time.Now()
|
|
db.lock.Lock()
|
|
defer db.lock.Unlock()
|
|
|
|
if domain, ok := db.data[name]; ok {
|
|
if len(domain) > 0 {
|
|
rv := make([]string, 0, len(domain))
|
|
for value, expiresAt := range domain {
|
|
if expiresAt.After(now) {
|
|
rv = append(rv, value)
|
|
} else {
|
|
delete(domain, value)
|
|
}
|
|
}
|
|
return rv
|
|
} else {
|
|
delete(db.data, name)
|
|
}
|
|
}
|
|
return []string{}
|
|
}
|
|
|
|
func (db *DB) Add(name, value string) {
|
|
expiresAt := time.Now().Add(db.timeout)
|
|
db.lock.Lock()
|
|
defer db.lock.Unlock()
|
|
|
|
if _, ok := db.data[name]; ok {
|
|
db.data[name][value] = expiresAt
|
|
} else {
|
|
db.data[name] = map[string]time.Time{value: expiresAt}
|
|
}
|
|
}
|
|
|
|
func (db *DB) Remove(name, value string) {
|
|
db.lock.Lock()
|
|
defer db.lock.Unlock()
|
|
|
|
if domain, ok := db.data[name]; ok {
|
|
if _, ok := domain[value]; ok && len(domain) == 1 {
|
|
delete(db.data, name)
|
|
} else {
|
|
delete(domain, value)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (db *DB) GC() {
|
|
now := time.Now()
|
|
db.lock.Lock()
|
|
defer db.lock.Unlock()
|
|
for name, domain := range db.data {
|
|
for value, expiresAt := range domain {
|
|
if expiresAt.Before(now) {
|
|
delete(domain, value)
|
|
}
|
|
}
|
|
if len(domain) == 0 {
|
|
delete(db.data, name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func NewDB() *DB {
|
|
db := &DB{
|
|
data: map[string]map[string]time.Time{},
|
|
lock: &sync.Mutex{},
|
|
timeout: 2 * time.Minute,
|
|
}
|
|
go func() {
|
|
for {
|
|
time.Sleep(5 * db.timeout)
|
|
db.GC()
|
|
}
|
|
}()
|
|
return db
|
|
}
|