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  }