func (r *RateLimiter) withinLimit(ip string, clientType int) bool {
	reqLimiter := r.fetchLimiter(ip)
	if reqLimiter == nil {
		var err error
		reqLimiter, err = r.addRequestLimiter(ip, clientType)
		if err != nil {
			log.Error(err)
			return false
		}
	}
	return reqLimiter.Allow()
}
withinLimit asserts that the client referenced by the provided IP
address is within the limits of the rate limiter, therefore can make
further requests. If no request limiter is found for the provided IP
address a new one is created. withinLimit returns false if an unknown
client type is provided.
package pool
import (
	"fmt"
	"sync"
	"golang.org/x/time/rate"
)
const (
	GUIClient = iota
	PoolClient
)
const (
	clientTokenRate = 5
	clientBurst = 5
	guiTokenRate = 3
	guiBurst = 7
)
type RateLimiter struct {
	mutex    sync.RWMutex
	limiters map[string]*rate.Limiter
}
func NewRateLimiter() *RateLimiter {
	limiters := &RateLimiter{
		limiters: make(map[string]*rate.Limiter),
	}
	return limiters
}
func (r *RateLimiter) addRequestLimiter(ip string, clientType int) (*rate.Limiter, error) {
	var limiter *rate.Limiter
	switch clientType {
	case GUIClient:
		limiter = rate.NewLimiter(guiTokenRate, guiBurst)
	case PoolClient:
		limiter = rate.NewLimiter(clientTokenRate, clientBurst)
	default:
		return nil, fmt.Errorf("unknown client type provided: %d", clientType)
	}
	r.mutex.Lock()
	r.limiters[ip] = limiter
	r.mutex.Unlock()
	return limiter, nil
}
func (r *RateLimiter) fetchLimiter(ip string) *rate.Limiter {
	r.mutex.RLock()
	limiter := r.limiters[ip]
	r.mutex.RUnlock()
	return limiter
}
func (r *RateLimiter) removeLimiter(ip string) {
	r.mutex.Lock()
	delete(r.limiters, ip)
	r.mutex.Unlock()
}