mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2025-09-19 04:06:18 +08:00

* fix(aliyundrive_open): limit rate for `Remove` and `MakeDir`; reduce limit for `List` and `Link` (close #724) * Update drivers/aliyundrive_open/driver.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: 火星大王 <34576789+huoxingdawang@users.noreply.github.com> * Update drivers/aliyundrive_open/driver.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: 火星大王 <34576789+huoxingdawang@users.noreply.github.com> * fix(aliyundrive_open): limit rate for every request * fix(aliyundrive_open): fix limiter not work on reference driver * fix(aliyundrive_open): typo * fix(aliyundrive_open): limiter not set to nil after free * fix(aliyundrive_share): limit rate for every request --------- Signed-off-by: 火星大王 <34576789+huoxingdawang@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
97 lines
2.3 KiB
Go
97 lines
2.3 KiB
Go
package aliyundrive_open
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"golang.org/x/time/rate"
|
|
)
|
|
|
|
// See document https://www.yuque.com/aliyundrive/zpfszx/mqocg38hlxzc5vcd
|
|
// See issue https://github.com/OpenListTeam/OpenList/issues/724
|
|
// We got limit per user per app, so the limiter should be global.
|
|
|
|
type limiterType int
|
|
|
|
const (
|
|
limiterList limiterType = iota
|
|
limiterLink
|
|
limiterOther
|
|
)
|
|
|
|
const (
|
|
listRateLimit = 3.9 // 4 per second in document, but we use 3.9 per second to be safe
|
|
linkRateLimit = 0.9 // 1 per second in document, but we use 0.9 per second to be safe
|
|
otherRateLimit = 14.9 // 15 per second in document, but we use 14.9 per second to be safe
|
|
globalLimiterUserID = "" // Global limiter user ID, used to limit the initial requests.
|
|
)
|
|
|
|
type limiter struct {
|
|
usedBy int
|
|
list *rate.Limiter
|
|
link *rate.Limiter
|
|
other *rate.Limiter
|
|
}
|
|
|
|
var limiters = make(map[string]*limiter)
|
|
var limitersLock = &sync.Mutex{}
|
|
|
|
func getLimiterForUser(userid string) *limiter {
|
|
limitersLock.Lock()
|
|
defer limitersLock.Unlock()
|
|
defer func() {
|
|
// Clean up limiters that are no longer used.
|
|
for id, lim := range limiters {
|
|
if lim.usedBy <= 0 && id != globalLimiterUserID { // Do not delete the global limiter.
|
|
delete(limiters, id)
|
|
}
|
|
}
|
|
}()
|
|
if lim, ok := limiters[userid]; ok {
|
|
lim.usedBy++
|
|
return lim
|
|
}
|
|
lim := &limiter{
|
|
usedBy: 1,
|
|
list: rate.NewLimiter(rate.Limit(listRateLimit), 1),
|
|
link: rate.NewLimiter(rate.Limit(linkRateLimit), 1),
|
|
other: rate.NewLimiter(rate.Limit(otherRateLimit), 1),
|
|
}
|
|
limiters[userid] = lim
|
|
return lim
|
|
}
|
|
|
|
func (l *limiter) wait(ctx context.Context, typ limiterType) error {
|
|
if l == nil {
|
|
return fmt.Errorf("driver not init")
|
|
}
|
|
switch typ {
|
|
case limiterList:
|
|
return l.list.Wait(ctx)
|
|
case limiterLink:
|
|
return l.link.Wait(ctx)
|
|
case limiterOther:
|
|
return l.other.Wait(ctx)
|
|
default:
|
|
return fmt.Errorf("unknown limiter type")
|
|
}
|
|
}
|
|
func (l *limiter) free() {
|
|
if l == nil {
|
|
return
|
|
}
|
|
limitersLock.Lock()
|
|
defer limitersLock.Unlock()
|
|
l.usedBy--
|
|
}
|
|
func (d *AliyundriveOpen) wait(ctx context.Context, typ limiterType) error {
|
|
if d == nil {
|
|
return fmt.Errorf("driver not init")
|
|
}
|
|
if d.ref != nil {
|
|
return d.ref.wait(ctx, typ) // If this is a reference driver, wait on the reference driver.
|
|
}
|
|
return d.limiter.wait(ctx, typ)
|
|
}
|