feat(channels/qq_obv11): OneBot v11 渠道插件(正/反 WS 双模式 + CQ 媒体 + 限频,stdlib 自研 WS)
This commit is contained in:
1 parent
f9f5a78a02
commit
7831b0ea1b
11 files changed
+2526
No files matched your search
@@ -0,0 +1,52 @@
|
||||
package qq_obv11
|
||||
|
||||
// This file implements the sliding-window send rate limiter that keeps QQ
|
||||
// OneBot proactive/reply traffic from bursting (see DevDocs/design/08 section
|
||||
// 3, "注意风控").
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ErrRateLimited is returned by SendMessage/SendProactive when the configured
|
||||
// per-window send quota is exhausted.
|
||||
var ErrRateLimited = errors.New("qq-obv11: send rate limit exceeded")
|
||||
|
||||
// rateLimiter enforces a maximum number of events within a sliding window. It
|
||||
// is disabled when max is non-positive.
|
||||
type rateLimiter struct {
|
||||
max int
|
||||
window time.Duration
|
||||
mu sync.Mutex
|
||||
times []time.Time
|
||||
}
|
||||
|
||||
func newRateLimiter(max int, window time.Duration) *rateLimiter {
|
||||
return &rateLimiter{max: max, window: window}
|
||||
}
|
||||
|
||||
// allow records a send at now and reports whether it fits within the window
|
||||
// quota. A disabled limiter (max <= 0) always allows. The timestamp is only
|
||||
// recorded when the send is accepted.
|
||||
func (r *rateLimiter) allow(now time.Time) bool {
|
||||
if r == nil || r.max <= 0 {
|
||||
return true
|
||||
}
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
cutoff := now.Add(-r.window)
|
||||
i := 0
|
||||
for i < len(r.times) && !r.times[i].After(cutoff) {
|
||||
i++
|
||||
}
|
||||
r.times = r.times[i:]
|
||||
|
||||
if len(r.times) >= r.max {
|
||||
return false
|
||||
}
|
||||
r.times = append(r.times, now)
|
||||
return true
|
||||
}
|
||||
Reference in new issue
Block a user