mirror of
https://github.com/Gouryella/drip.git
synced 2026-05-02 23:18:47 +00:00
- Implement client bandwidth limitation parameter --bandwidth, supporting 1M, 1MB, 1G and other formats - Added parseBandwidth function to parse bandwidth values and verify them - Added bandwidth limit option in HTTP, HTTPS, TCP commands - Pass bandwidth configuration to the server through protocol - Add relevant test cases to verify the bandwidth analysis function feat(server): implements server-side bandwidth limitation function - Add bandwidth limitation logic in connection processing, using token bucket algorithm - Implement an effective rate limiting strategy that minimizes the bandwidth of the client and server - Added QoS limiter and restricted connection wrapper - Integrated bandwidth throttling in HTTP and WebSocket proxies - Added global bandwidth limit and burst multiplier settings in server configuration docs: Updated documentation to describe bandwidth limiting functionality - Add 2025-02-14 version update instructions in README and README_CN - Add bandwidth limit function description and usage examples - Provide client and server configuration examples and parameter descriptions
113 lines
1.8 KiB
Go
113 lines
1.8 KiB
Go
package qos
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"net"
|
|
)
|
|
|
|
type LimitedConn struct {
|
|
net.Conn
|
|
limiter *Limiter
|
|
ctx context.Context
|
|
}
|
|
|
|
func NewLimitedConn(ctx context.Context, conn net.Conn, limiter *Limiter) *LimitedConn {
|
|
return &LimitedConn{
|
|
Conn: conn,
|
|
limiter: limiter,
|
|
ctx: ctx,
|
|
}
|
|
}
|
|
|
|
func (c *LimitedConn) Read(b []byte) (n int, err error) {
|
|
if c.limiter == nil || !c.limiter.IsLimited() {
|
|
return c.Conn.Read(b)
|
|
}
|
|
|
|
burst := c.limiter.RateLimiter().Burst()
|
|
if len(b) > burst {
|
|
b = b[:burst]
|
|
}
|
|
|
|
n, err = c.Conn.Read(b)
|
|
if n > 0 {
|
|
if waitErr := c.limiter.RateLimiter().WaitN(c.ctx, n); waitErr != nil {
|
|
if err == nil {
|
|
err = waitErr
|
|
}
|
|
}
|
|
}
|
|
return n, err
|
|
}
|
|
|
|
func (c *LimitedConn) Write(b []byte) (n int, err error) {
|
|
if c.limiter == nil || !c.limiter.IsLimited() {
|
|
return c.Conn.Write(b)
|
|
}
|
|
|
|
burst := c.limiter.RateLimiter().Burst()
|
|
total := 0
|
|
|
|
for len(b) > 0 {
|
|
chunk := min(len(b), burst)
|
|
|
|
if err := c.limiter.RateLimiter().WaitN(c.ctx, chunk); err != nil {
|
|
return total, err
|
|
}
|
|
|
|
nw, err := c.Conn.Write(b[:chunk])
|
|
total += nw
|
|
if err != nil {
|
|
return total, err
|
|
}
|
|
b = b[chunk:]
|
|
}
|
|
|
|
return total, nil
|
|
}
|
|
|
|
func (c *LimitedConn) ReadFrom(r io.Reader) (n int64, err error) {
|
|
buf := make([]byte, 32*1024)
|
|
for {
|
|
nr, er := r.Read(buf)
|
|
if nr > 0 {
|
|
nw, ew := c.Write(buf[:nr])
|
|
n += int64(nw)
|
|
if ew != nil {
|
|
err = ew
|
|
break
|
|
}
|
|
}
|
|
if er != nil {
|
|
if er != io.EOF {
|
|
err = er
|
|
}
|
|
break
|
|
}
|
|
}
|
|
return n, err
|
|
}
|
|
|
|
func (c *LimitedConn) WriteTo(w io.Writer) (n int64, err error) {
|
|
buf := make([]byte, 32*1024)
|
|
for {
|
|
nr, er := c.Read(buf)
|
|
if nr > 0 {
|
|
nw, ew := w.Write(buf[:nr])
|
|
n += int64(nw)
|
|
if ew != nil {
|
|
err = ew
|
|
break
|
|
}
|
|
}
|
|
if er != nil {
|
|
if er != io.EOF {
|
|
err = er
|
|
}
|
|
break
|
|
}
|
|
}
|
|
return n, err
|
|
}
|