feat: add SproutWorkCollect apps
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// rateLimits defines minimum seconds between the same action by the same user on the same work.
|
||||
var rateLimits = map[string]int64{
|
||||
"view": 60,
|
||||
"download": 300,
|
||||
"like": 3600,
|
||||
}
|
||||
|
||||
// RateLimiter provides per-user, per-action, per-work rate limiting backed by an in-memory store.
|
||||
// The store is never persisted; it resets on service restart (same behaviour as the Python version).
|
||||
type RateLimiter struct {
|
||||
mu sync.Mutex
|
||||
// fingerprint → actionType → workID → last unix timestamp
|
||||
actions map[string]map[string]map[string]int64
|
||||
}
|
||||
|
||||
// NewRateLimiter allocates a new empty RateLimiter.
|
||||
func NewRateLimiter() *RateLimiter {
|
||||
return &RateLimiter{
|
||||
actions: make(map[string]map[string]map[string]int64),
|
||||
}
|
||||
}
|
||||
|
||||
// CanPerform returns true and records the timestamp if the rate limit window has elapsed.
|
||||
// Returns false if the action is too frequent.
|
||||
func (rl *RateLimiter) CanPerform(fingerprint, actionType, workID string) bool {
|
||||
rl.mu.Lock()
|
||||
defer rl.mu.Unlock()
|
||||
|
||||
limit, ok := rateLimits[actionType]
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
|
||||
if rl.actions[fingerprint] == nil {
|
||||
rl.actions[fingerprint] = make(map[string]map[string]int64)
|
||||
}
|
||||
if rl.actions[fingerprint][actionType] == nil {
|
||||
rl.actions[fingerprint][actionType] = make(map[string]int64)
|
||||
}
|
||||
|
||||
last := rl.actions[fingerprint][actionType][workID]
|
||||
if now-last >= limit {
|
||||
rl.actions[fingerprint][actionType][workID] = now
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Fingerprint creates an MD5 hex string from IP and User-Agent for rate-limit keying.
|
||||
func Fingerprint(ip, userAgent string) string {
|
||||
h := md5.Sum([]byte(ip + ":" + userAgent))
|
||||
return fmt.Sprintf("%x", h)
|
||||
}
|
||||
Reference in New Issue
Block a user