ratelimit

package
v0.0.11 Latest Latest
Warning

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

Go to latest
Published: Apr 30, 2024 License: MIT Imports: 3 Imported by: 2

Documentation

Overview

Package ratelimit provides a simple window-based rate limiter.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Limiter

type Limiter struct {
	sync.Mutex
	WindowLimits []WindowLimit
	// contains filtered or unexported fields
}

Limiter is a simple rate limiter with one or more fixed windows, e.g. the last minute/hour/day/week, working on three classes/subnets of an IP.

Example
package main

import (
	"fmt"
	"net"
	"time"

	"github.com/mjl-/mox/ratelimit"
)

func main() {
	// Make a new rate limit that has maxima per minute, hour and day. The maxima are
	// tracked per ipmasked1 (ipv4 /32 or ipv6 /64), ipmasked2 (ipv4 /26 or ipv6 /48)
	// and ipmasked3 (ipv4 /21 or ipv6 /32).
	//
	// It is common to allow short bursts (with a narrow window), but not allow a high
	// sustained rate (with wide window).
	limit := ratelimit.Limiter{
		WindowLimits: []ratelimit.WindowLimit{
			{Window: time.Minute, Limits: [...]int64{2, 3, 4}},
			{Window: time.Hour, Limits: [...]int64{4, 6, 8}},
			{Window: 24 * time.Hour, Limits: [...]int64{20, 40, 60}},
		},
	}

	tm, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")

	fmt.Println("1:", limit.Add(net.ParseIP("127.0.0.1"), tm, 1))                    // Success.
	fmt.Println("2:", limit.Add(net.ParseIP("127.0.0.1"), tm, 1))                    // Success.
	fmt.Println("3:", limit.Add(net.ParseIP("127.0.0.1"), tm, 1))                    // Failure, too many from same ip.
	fmt.Println("4:", limit.Add(net.ParseIP("127.0.0.2"), tm, 1))                    // Success, different IP, though nearby.
	fmt.Println("5:", limit.Add(net.ParseIP("127.0.0.2"), tm, 1))                    // Failure, hits ipmasked2 check.
	fmt.Println("6:", limit.Add(net.ParseIP("127.0.0.1"), tm.Add(time.Minute), 1))   // Success, in next minute.
	fmt.Println("7:", limit.Add(net.ParseIP("127.0.0.1"), tm.Add(2*time.Minute), 1)) // Success, in another minute.
	fmt.Println("8:", limit.Add(net.ParseIP("127.0.0.1"), tm.Add(3*time.Minute), 1)) // Failure, hitting hourly window for ipmasked1.
	limit.Reset(net.ParseIP("127.0.0.1"), tm.Add(3*time.Minute))
	fmt.Println("9:", limit.Add(net.ParseIP("127.0.0.1"), tm.Add(3*time.Minute), 1)) // Success.

}
Output:

1: true
2: true
3: false
4: true
5: false
6: true
7: true
8: false
9: true

func (*Limiter) Add

func (l *Limiter) Add(ip net.IP, tm time.Time, n int64) bool

Add attempts to consume "n" items from the rate limiter. If the total for this key and this interval would exceed limit, "n" is not counted and false is returned. If now represents a different time interval, all counts are reset.

func (*Limiter) CanAdd

func (l *Limiter) CanAdd(ip net.IP, tm time.Time, n int64) bool

CanAdd returns if n could be added to the limiter.

func (*Limiter) Reset

func (l *Limiter) Reset(ip net.IP, tm time.Time)

Reset sets the counter to 0 for key and ip, and subtracts from the ipmasked counts.

type WindowLimit

type WindowLimit struct {
	Window time.Duration
	Limits [3]int64 // For "ipmasked1" through "ipmasked3".
	Time   uint32   // Time/Window.
	Counts map[struct {
		Index    uint8
		IPMasked [16]byte
	}]int64
}

WindowLimit holds counters for one window, with limits for each IP class/subnet.

Jump to

Keyboard shortcuts

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