github.com/TeaOSLab/EdgeNode@v1.3.8/internal/utils/writers/writer_rate_limit.go (about) 1 // Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved. 2 3 package writers 4 5 import ( 6 "context" 7 "github.com/iwind/TeaGo/types" 8 "io" 9 "time" 10 ) 11 12 // RateLimitWriter 限速写入 13 type RateLimitWriter struct { 14 rawWriter io.WriteCloser 15 ctx context.Context 16 17 rateBytes int 18 19 written int 20 before time.Time 21 } 22 23 func NewRateLimitWriter(ctx context.Context, rawWriter io.WriteCloser, rateBytes int64) io.WriteCloser { 24 return &RateLimitWriter{ 25 rawWriter: rawWriter, 26 ctx: ctx, 27 rateBytes: types.Int(rateBytes), 28 before: time.Now(), 29 } 30 } 31 32 func (this *RateLimitWriter) Write(p []byte) (n int, err error) { 33 if this.rateBytes <= 0 { 34 return this.write(p) 35 } 36 37 var size = len(p) 38 if size == 0 { 39 return 0, nil 40 } 41 42 if size <= this.rateBytes { 43 return this.write(p) 44 } 45 46 for { 47 size = len(p) 48 49 var limit = this.rateBytes 50 if limit > size { 51 limit = size 52 } 53 n1, wErr := this.write(p[:limit]) 54 n += n1 55 if wErr != nil { 56 return n, wErr 57 } 58 59 if size > limit { 60 p = p[limit:] 61 } else { 62 break 63 } 64 } 65 66 return 67 } 68 69 func (this *RateLimitWriter) Close() error { 70 return this.rawWriter.Close() 71 } 72 73 func (this *RateLimitWriter) write(p []byte) (n int, err error) { 74 n, err = this.rawWriter.Write(p) 75 76 if err == nil { 77 select { 78 case <-this.ctx.Done(): 79 err = io.EOF 80 return 81 default: 82 } 83 84 this.written += n 85 86 if this.written >= this.rateBytes { 87 var duration = 1*time.Second - time.Since(this.before) 88 if duration > 0 { 89 time.Sleep(duration) 90 } 91 this.before = time.Now() 92 this.written = 0 93 } 94 } 95 96 return 97 }