Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alist-org
GitHub Repository: alist-org/alist
Path: blob/main/internal/stream/limit.go
1560 views
1
package stream
2
3
import (
4
"context"
5
"github.com/alist-org/alist/v3/internal/model"
6
"github.com/alist-org/alist/v3/pkg/http_range"
7
"github.com/alist-org/alist/v3/pkg/utils"
8
"golang.org/x/time/rate"
9
"io"
10
"time"
11
)
12
13
type Limiter interface {
14
Limit() rate.Limit
15
Burst() int
16
TokensAt(time.Time) float64
17
Tokens() float64
18
Allow() bool
19
AllowN(time.Time, int) bool
20
Reserve() *rate.Reservation
21
ReserveN(time.Time, int) *rate.Reservation
22
Wait(context.Context) error
23
WaitN(context.Context, int) error
24
SetLimit(rate.Limit)
25
SetLimitAt(time.Time, rate.Limit)
26
SetBurst(int)
27
SetBurstAt(time.Time, int)
28
}
29
30
var (
31
ClientDownloadLimit Limiter
32
ClientUploadLimit Limiter
33
ServerDownloadLimit Limiter
34
ServerUploadLimit Limiter
35
)
36
37
type RateLimitReader struct {
38
io.Reader
39
Limiter Limiter
40
Ctx context.Context
41
}
42
43
func (r *RateLimitReader) Read(p []byte) (n int, err error) {
44
if r.Ctx != nil && utils.IsCanceled(r.Ctx) {
45
return 0, r.Ctx.Err()
46
}
47
n, err = r.Reader.Read(p)
48
if err != nil {
49
return
50
}
51
if r.Limiter != nil {
52
if r.Ctx == nil {
53
r.Ctx = context.Background()
54
}
55
err = r.Limiter.WaitN(r.Ctx, n)
56
}
57
return
58
}
59
60
func (r *RateLimitReader) Close() error {
61
if c, ok := r.Reader.(io.Closer); ok {
62
return c.Close()
63
}
64
return nil
65
}
66
67
type RateLimitWriter struct {
68
io.Writer
69
Limiter Limiter
70
Ctx context.Context
71
}
72
73
func (w *RateLimitWriter) Write(p []byte) (n int, err error) {
74
if w.Ctx != nil && utils.IsCanceled(w.Ctx) {
75
return 0, w.Ctx.Err()
76
}
77
n, err = w.Writer.Write(p)
78
if err != nil {
79
return
80
}
81
if w.Limiter != nil {
82
if w.Ctx == nil {
83
w.Ctx = context.Background()
84
}
85
err = w.Limiter.WaitN(w.Ctx, n)
86
}
87
return
88
}
89
90
func (w *RateLimitWriter) Close() error {
91
if c, ok := w.Writer.(io.Closer); ok {
92
return c.Close()
93
}
94
return nil
95
}
96
97
type RateLimitFile struct {
98
model.File
99
Limiter Limiter
100
Ctx context.Context
101
}
102
103
func (r *RateLimitFile) Read(p []byte) (n int, err error) {
104
if r.Ctx != nil && utils.IsCanceled(r.Ctx) {
105
return 0, r.Ctx.Err()
106
}
107
n, err = r.File.Read(p)
108
if err != nil {
109
return
110
}
111
if r.Limiter != nil {
112
if r.Ctx == nil {
113
r.Ctx = context.Background()
114
}
115
err = r.Limiter.WaitN(r.Ctx, n)
116
}
117
return
118
}
119
120
func (r *RateLimitFile) ReadAt(p []byte, off int64) (n int, err error) {
121
if r.Ctx != nil && utils.IsCanceled(r.Ctx) {
122
return 0, r.Ctx.Err()
123
}
124
n, err = r.File.ReadAt(p, off)
125
if err != nil {
126
return
127
}
128
if r.Limiter != nil {
129
if r.Ctx == nil {
130
r.Ctx = context.Background()
131
}
132
err = r.Limiter.WaitN(r.Ctx, n)
133
}
134
return
135
}
136
137
type RateLimitRangeReadCloser struct {
138
model.RangeReadCloserIF
139
Limiter Limiter
140
}
141
142
func (rrc *RateLimitRangeReadCloser) RangeRead(ctx context.Context, httpRange http_range.Range) (io.ReadCloser, error) {
143
rc, err := rrc.RangeReadCloserIF.RangeRead(ctx, httpRange)
144
if err != nil {
145
return nil, err
146
}
147
return &RateLimitReader{
148
Reader: rc,
149
Limiter: rrc.Limiter,
150
Ctx: ctx,
151
}, nil
152
}
153
154