bwlimit

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 26, 2023 License: Apache-2.0 Imports: 8 Imported by: 7

README

BWLimit

License Test Go Report Card Go Reference

BWLimit lets you configure a bandwidth limit on net.Conn, io.Reader and io.Writer.

Quick Start

BWLimit can be used to throttle the bandwidth (bytes per second) either on the client or server.

See usage examples below:

Server Side

To limit the bandwidth on the server use bwlimit.NewListener.

package main

import (
	"io"
	"log"
	"net"
	"net/http"

	"github.com/conduitio/bwlimit"
)

const (
	writeLimit = 1 * bwlimit.Mebibyte // write limit is 1048576 B/s
	readLimit  = 4 * bwlimit.KB       // read limit is 4000 B/s
)

func main() {
	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Fatalf("Failed to listen: %v", err)
	}
	// limit the listener bandwidth
	ln = bwlimit.NewListener(ln, writeLimit, readLimit)

	http.Handle("/echo", http.HandlerFunc(echoHandler))
	srv := &http.Server{Addr: addr}
	log.Fatalf("Failed to serve: %v", srv.Serve(ln))
}

func echoHandler(w http.ResponseWriter, r *http.Request) {
	body, _ := io.ReadAll(r.Body)
	_, _ = w.Write(body)
}
Client Side

To limit the bandwidth on the client use bwlimit.NewDialer.

package main

import (
	"io"
	"net"
	"net/http"
	"time"

	"github.com/conduitio/bwlimit"
)

const (
	writeLimit = 1 * bwlimit.Mebibyte // write limit is 1048576 B/s
	readLimit  = 4 * bwlimit.KB       // read limit is 4000 B/s
)

func main() {
	// change dialer in the default transport to use a bandwidth limit
	dialer := bwlimit.NewDialer(&net.Dialer{
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
	}, writeLimit, readLimit)
	http.DefaultTransport.(*http.Transport).DialContext = dialer.DialContext

	// requests through the default client respect the bandwidth limit now
	resp, _ := http.DefaultClient.Get("http://localhost:8080/echo")
	_, _ = io.ReadAll(resp.Body)
}
gRPC Client Interceptor

The gRPC interceptor is provided in a separate module, import it with:

go get github.com/conduitio/bwlimit/bwgrpc

To limit the bandwidth on a gRPC client use bwgrpc.WithBandwidthLimitedContextDialer.

package main

import (
	"context"
	"log"

	"github.com/conduitio/bwlimit"
	"github.com/conduitio/bwlimit/bwgrpc"
	"github.com/conduitio/bwlimit/bwgrpc/testproto"
	"google.golang.org/grpc"
)

const (
	writeLimit = 1 * bwlimit.Mebibyte // write limit is 1048576 B/s
	readLimit  = 4 * bwlimit.KB       // read limit is 4000 B/s
)

func main() {
	// open connection with limited bandwidth
	conn, err := grpc.DialContext(
		context.Background(),
		"localhost:8080",
		// limit the bandwidth
		bwgrpc.WithBandwidthLimitedContextDialer(writeLimit, readLimit, nil),
	)
	if err != nil {
		log.Fatalf("Failed to dial: %v", err)
	}
	defer conn.Close()

	// create gRPC client with the limited connection
	c := testproto.NewTestServiceClient(conn)
	
	// use client to send request
	_, err = c.TestRPC(ctx, &testproto.TestRequest{})
	if err != nil {
		log.Fatalf("Failed to send RPC: %v", err)
	}
}

Documentation

Index

Constants

View Source
const (
	Kibibyte Byte = 1024
	KiB           = Kibibyte
	Mebibyte      = Kibibyte * 1024
	MiB           = Mebibyte
	Gibibyte      = Mebibyte * 1024
	GiB           = Gibibyte
)

Base-2 byte units.

View Source
const (
	Kilobyte Byte = 1000
	KB            = Kilobyte
	Megabyte      = Kilobyte * 1000
	MB            = Megabyte
	Gigabyte      = Megabyte * 1000
	GB            = Gigabyte
)

SI base-10 byte units.

Variables

This section is empty.

Functions

This section is empty.

Types

type Byte

type Byte int

Byte represents a number of bytes as an int.

type Conn

type Conn struct {
	net.Conn
	// contains filtered or unexported fields
}

Conn is a net.Conn connection that limits the bandwidth of writes and reads.

func NewConn

func NewConn(conn net.Conn, writeLimitPerSecond, readLimitPerSecond Byte) *Conn

NewConn wraps an existing net.Conn and returns a Conn that limits the bandwidth of writes and reads. A zero value for writeLimitPerSecond or readLimitPerSecond means the corresponding action will not have a bandwidth limit.

func (*Conn) Read

func (c *Conn) Read(b []byte) (n int, err error)

Read reads data from the connection. Read can be made to time out and return an error after a fixed time limit; see SetDeadline and SetReadDeadline. Read will limit the connection bandwidth if a limit is configured. If the size of b is bigger than the rate of bytes per second, reads will be split into smaller chunks. Note that since it's not known in advance how many bytes will be read, the bandwidth can burst up to 2x of the configured limit when reading the first 2 chunks.

func (*Conn) ReadBandwidthLimit

func (c *Conn) ReadBandwidthLimit() Byte

ReadBandwidthLimit returns the current read bandwidth limit.

func (*Conn) SetBandwidthLimit

func (c *Conn) SetBandwidthLimit(bytesPerSecond Byte)

SetBandwidthLimit sets the read and write bandwidth limits associated with the connection. It is equivalent to calling both SetReadBandwidthLimit and SetWriteBandwidthLimit.

func (*Conn) SetDeadline

func (c *Conn) SetDeadline(t time.Time) error

SetDeadline sets the read and write deadlines associated with the connection. It is equivalent to calling both SetReadDeadline and SetWriteDeadline.

A deadline is an absolute time after which I/O operations fail instead of blocking. The deadline applies to all future and pending I/O, not just the immediately following call to Read or Write. After a deadline has been exceeded, the connection can be refreshed by setting a deadline in the future.

If the deadline is exceeded a call to Read or Write or to other I/O methods will return an error that wraps os.ErrDeadlineExceeded. This can be tested using errors.Is(err, os.ErrDeadlineExceeded). The error's Timeout method will return true, but note that there are other possible errors for which the Timeout method will return true even if the deadline has not been exceeded.

An idle timeout can be implemented by repeatedly extending the deadline after successful Read or Write calls.

A zero value for t means I/O operations will not time out.

func (*Conn) SetReadBandwidthLimit

func (c *Conn) SetReadBandwidthLimit(bytesPerSecond Byte)

SetReadBandwidthLimit sets the bandwidth limit for future Read calls and any currently-blocked Read call. A zero value for bytesPerSecond means the bandwidth limit is removed.

func (*Conn) SetReadDeadline

func (c *Conn) SetReadDeadline(t time.Time) error

SetReadDeadline sets the deadline for future Read calls and any currently-blocked Read call. A zero value for t means Read will not time out.

func (*Conn) SetWriteBandwidthLimit

func (c *Conn) SetWriteBandwidthLimit(bytesPerSecond Byte)

SetWriteBandwidthLimit sets the bandwidth limit for future Write calls and any currently-blocked Write call. A zero value for bytesPerSecond means the bandwidth limit is removed.

func (*Conn) SetWriteDeadline

func (c *Conn) SetWriteDeadline(t time.Time) error

SetWriteDeadline sets the deadline for future Write calls and any currently-blocked Write call. Even if write times out, it may return n > 0, indicating that some of the data was successfully written. A zero value for t means Write will not time out.

func (*Conn) Write

func (c *Conn) Write(b []byte) (n int, err error)

Write writes data to the connection. Write can be made to time out and return an error after a fixed time limit; see SetDeadline and SetWriteDeadline. Write will limit the connection bandwidth if a limit is configured. If the size of b is bigger than the rate of bytes per second, writes will be split into smaller chunks.

func (*Conn) WriteBandwidthLimit

func (c *Conn) WriteBandwidthLimit() Byte

WriteBandwidthLimit returns the current write bandwidth limit.

type Dialer

type Dialer struct {
	*net.Dialer
	// contains filtered or unexported fields
}

Dialer is a net.Dialer that limits the bandwidth of the connections it creates.

func NewDialer

func NewDialer(d *net.Dialer, writeLimitPerSecond, readLimitPerSecond Byte) *Dialer

NewDialer wraps an existing net.Dialer and returns a Dialer that limits the bandwidth of the connections it creates. A zero value for writeLimitPerSecond or readLimitPerSecond means the corresponding action will not have a bandwidth limit.

func (*Dialer) Dial

func (d *Dialer) Dial(network, address string) (net.Conn, error)

Dial connects to the address on the named network. It returns a connection with the configured bandwidth limits. Each connection tracks its own bandwidth.

func (*Dialer) DialContext

func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error)

DialContext connects to the address on the named network using the provided context. It returns a connection with the configured bandwidth limits.

func (*Dialer) ReadBandwidthLimit

func (d *Dialer) ReadBandwidthLimit() Byte

ReadBandwidthLimit returns the current read bandwidth limit.

func (*Dialer) SetReadBandwidthLimit

func (d *Dialer) SetReadBandwidthLimit(bytesPerSecond Byte)

SetReadBandwidthLimit sets the bandwidth limit for reads on future connections opened in Accept. It has no effect on already opened connections. A zero value for bytesPerSecond means the bandwidth limit is removed.

func (*Dialer) SetWriteBandwidthLimit

func (d *Dialer) SetWriteBandwidthLimit(bytesPerSecond Byte)

SetWriteBandwidthLimit sets the bandwidth limit for writes on future connections opened in Accept. It has no effect on already opened connections. A zero value for bytesPerSecond means the bandwidth limit is removed.

func (*Dialer) WriteBandwidthLimit

func (d *Dialer) WriteBandwidthLimit() Byte

WriteBandwidthLimit returns the current write bandwidth limit.

type Listener

type Listener struct {
	net.Listener
	// contains filtered or unexported fields
}

Listener is a net.Listener that limits the bandwidth of the connections it creates.

func NewListener

func NewListener(lis net.Listener, writeLimitPerSecond, readLimitPerSecond Byte) *Listener

NewListener wraps an existing net.Listener and returns a Listener that limits the bandwidth of the connections it creates. A zero value for writeLimitPerSecond or readLimitPerSecond means the corresponding action will not have a bandwidth limit.

func (*Listener) Accept

func (l *Listener) Accept() (net.Conn, error)

Accept waits for and returns the next connection to the listener. It returns a connection with a configured bandwidth limit. Each connection tracks its own bandwidth.

func (*Listener) ReadBandwidthLimit

func (l *Listener) ReadBandwidthLimit() Byte

ReadBandwidthLimit returns the current read bandwidth limit.

func (*Listener) SetReadBandwidthLimit

func (l *Listener) SetReadBandwidthLimit(bytesPerSecond Byte)

SetReadBandwidthLimit sets the bandwidth limit for reads on future connections opened in Accept. It has no effect on already opened connections. A zero value for bytesPerSecond means the bandwidth limit is removed.

func (*Listener) SetWriteBandwidthLimit

func (l *Listener) SetWriteBandwidthLimit(bytesPerSecond Byte)

SetWriteBandwidthLimit sets the bandwidth limit for writes on future connections opened in Accept. It has no effect on already opened connections. A zero value for bytesPerSecond means the bandwidth limit is removed.

func (*Listener) WriteBandwidthLimit

func (l *Listener) WriteBandwidthLimit() Byte

WriteBandwidthLimit returns the current write bandwidth limit.

type Reader

type Reader struct {
	io.Reader
	// contains filtered or unexported fields
}

Reader wraps an io.Reader and imposes a bandwidth limit on calls to Read.

func NewReader

func NewReader(r io.Reader, bytesPerSecond Byte) *Reader

NewReader wraps an existing io.Reader and returns a Reader that limits the bandwidth of reads. A zero value for bytesPerSecond means that Read will not have a bandwidth limit.

func (*Reader) BandwidthLimit

func (r *Reader) BandwidthLimit() Byte

BandwidthLimit returns the current bandwidth limit.

func (*Reader) Close

func (r *Reader) Close() error

Close forwards the call to the wrapped io.Reader if it implements io.Closer, otherwise it is a noop.

func (*Reader) Deadline

func (r *Reader) Deadline() time.Time

Deadline returns the configured deadline (see SetDeadline).

func (*Reader) Read

func (r *Reader) Read(p []byte) (n int, err error)

Read reads up to len(p) bytes into p. It returns the number of bytes read (0 <= n <= len(p)) and any error encountered.

Read will limit the speed of the reads if a bandwidth limit is configured. If the size of p is bigger than the rate of bytes per second, reads will be split into smaller chunks. Note that since it's not known in advance how many bytes will be read, the bandwidth can burst up to 2x of the configured limit when reading the first 2 chunks.

func (*Reader) SetBandwidthLimit

func (r *Reader) SetBandwidthLimit(bytesPerSecond Byte)

SetBandwidthLimit sets the bandwidth limit for future Read calls and any currently-blocked Read call. A zero value for bytesPerSecond means the bandwidth limit is removed.

func (*Reader) SetDeadline

func (r *Reader) SetDeadline(t time.Time)

SetDeadline sets the read deadline associated with the reader.

A deadline is an absolute time after which Read fails instead of blocking. The deadline applies to all future and pending calls to Read, not just the immediately following call to Read. After a deadline has been exceeded, the reader can be refreshed by setting a deadline in the future.

If the deadline is exceeded a call to Read will return an error that wraps os.ErrDeadlineExceeded. This can be tested using errors.Is(err, os.ErrDeadlineExceeded).

An idle timeout can be implemented by repeatedly extending the deadline after successful Read calls.

A zero value for t means that calls to Read will not time out.

type Writer

type Writer struct {
	io.Writer
	// contains filtered or unexported fields
}

Writer wraps an io.Writer and imposes a bandwidth limit on calls to Write.

func NewWriter

func NewWriter(w io.Writer, bytesPerSecond Byte) *Writer

NewWriter wraps an existing io.Writer and returns a Writer that limits the bandwidth of writes. A zero value for bytesPerSecond means that Write will not have a bandwidth limit.

func (*Writer) BandwidthLimit

func (w *Writer) BandwidthLimit() Byte

BandwidthLimit returns the current bandwidth limit.

func (*Writer) Close

func (w *Writer) Close() error

Close forwards the call to the wrapped io.Writer if it implements io.Closer, otherwise it is a noop.

func (*Writer) Deadline

func (w *Writer) Deadline() time.Time

Deadline returns the configured deadline (see SetDeadline).

func (*Writer) SetBandwidthLimit

func (w *Writer) SetBandwidthLimit(bytesPerSecond Byte)

SetBandwidthLimit sets the bandwidth limit for future Write calls and any currently-blocked Write call. A zero value for bytesPerSecond means the bandwidth limit is removed.

func (*Writer) SetDeadline

func (w *Writer) SetDeadline(t time.Time)

SetDeadline sets the write deadline associated with the writer.

A deadline is an absolute time after which Write fails instead of blocking. The deadline applies to all future and pending calls to Write, not just the immediately following call to Write. After a deadline has been exceeded, the writer can be refreshed by setting a deadline in the future.

If the deadline is exceeded a call to Write will return an error that wraps os.ErrDeadlineExceeded. This can be tested using errors.Is(err, os.ErrDeadlineExceeded).

An idle timeout can be implemented by repeatedly extending the deadline after successful Write calls.

A zero value for t means that calls to Write will not time out.

func (*Writer) Write

func (w *Writer) Write(p []byte) (n int, err error)

Write writes len(p) bytes from p to the underlying data stream. It returns the number of bytes written from p (0 <= n <= len(p)) and any error encountered that caused the write to stop early.

Write will limit the speed of the writes if a bandwidth limit is configured. If the size of p is bigger than the rate of bytes per second, writes will be split into smaller chunks.

Directories

Path Synopsis
bwgrpc module
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL