| package common |
|
|
| import ( |
| "sync" |
| "time" |
| ) |
|
|
| type InMemoryRateLimiter struct { |
| store map[string]*[]int64 |
| mutex sync.Mutex |
| expirationDuration time.Duration |
| } |
|
|
| func (l *InMemoryRateLimiter) Init(expirationDuration time.Duration) { |
| if l.store == nil { |
| l.mutex.Lock() |
| if l.store == nil { |
| l.store = make(map[string]*[]int64) |
| l.expirationDuration = expirationDuration |
| if expirationDuration > 0 { |
| go l.clearExpiredItems() |
| } |
| } |
| l.mutex.Unlock() |
| } |
| } |
|
|
| func (l *InMemoryRateLimiter) clearExpiredItems() { |
| for { |
| time.Sleep(l.expirationDuration) |
| l.mutex.Lock() |
| now := time.Now().Unix() |
| for key := range l.store { |
| queue := l.store[key] |
| size := len(*queue) |
| if size == 0 || now-(*queue)[size-1] > int64(l.expirationDuration.Seconds()) { |
| delete(l.store, key) |
| } |
| } |
| l.mutex.Unlock() |
| } |
| } |
|
|
| |
| func (l *InMemoryRateLimiter) Request(key string, maxRequestNum int, duration int64) bool { |
| l.mutex.Lock() |
| defer l.mutex.Unlock() |
| |
| queue, ok := l.store[key] |
| now := time.Now().Unix() |
| if ok { |
| if len(*queue) < maxRequestNum { |
| *queue = append(*queue, now) |
| return true |
| } else { |
| if now-(*queue)[0] >= duration { |
| *queue = (*queue)[1:] |
| *queue = append(*queue, now) |
| return true |
| } else { |
| return false |
| } |
| } |
| } else { |
| s := make([]int64, 0, maxRequestNum) |
| l.store[key] = &s |
| *(l.store[key]) = append(*(l.store[key]), now) |
| } |
| return true |
| } |
|
|