package rcmgr

import (
	
	
	
	

	
	
	

	
)

type baseLimitConfig struct {
	BaseLimit         BaseLimit
	BaseLimitIncrease BaseLimitIncrease
}

// ScalingLimitConfig is a struct for configuring default limits.
// {}BaseLimit is the limits that Apply for a minimal node (128 MB of memory for libp2p) and 256 file descriptors.
// {}LimitIncrease is the additional limit granted for every additional 1 GB of RAM.
type ScalingLimitConfig struct {
	SystemBaseLimit     BaseLimit
	SystemLimitIncrease BaseLimitIncrease

	TransientBaseLimit     BaseLimit
	TransientLimitIncrease BaseLimitIncrease

	AllowlistedSystemBaseLimit     BaseLimit
	AllowlistedSystemLimitIncrease BaseLimitIncrease

	AllowlistedTransientBaseLimit     BaseLimit
	AllowlistedTransientLimitIncrease BaseLimitIncrease

	ServiceBaseLimit     BaseLimit
	ServiceLimitIncrease BaseLimitIncrease
	ServiceLimits        map[string]baseLimitConfig // use AddServiceLimit to modify

	ServicePeerBaseLimit     BaseLimit
	ServicePeerLimitIncrease BaseLimitIncrease
	ServicePeerLimits        map[string]baseLimitConfig // use AddServicePeerLimit to modify

	ProtocolBaseLimit     BaseLimit
	ProtocolLimitIncrease BaseLimitIncrease
	ProtocolLimits        map[protocol.ID]baseLimitConfig // use AddProtocolLimit to modify

	ProtocolPeerBaseLimit     BaseLimit
	ProtocolPeerLimitIncrease BaseLimitIncrease
	ProtocolPeerLimits        map[protocol.ID]baseLimitConfig // use AddProtocolPeerLimit to modify

	PeerBaseLimit     BaseLimit
	PeerLimitIncrease BaseLimitIncrease
	PeerLimits        map[peer.ID]baseLimitConfig // use AddPeerLimit to modify

	ConnBaseLimit     BaseLimit
	ConnLimitIncrease BaseLimitIncrease

	StreamBaseLimit     BaseLimit
	StreamLimitIncrease BaseLimitIncrease
}

func ( *ScalingLimitConfig) ( string,  BaseLimit,  BaseLimitIncrease) {
	if .ServiceLimits == nil {
		.ServiceLimits = make(map[string]baseLimitConfig)
	}
	.ServiceLimits[] = baseLimitConfig{
		BaseLimit:         ,
		BaseLimitIncrease: ,
	}
}

func ( *ScalingLimitConfig) ( protocol.ID,  BaseLimit,  BaseLimitIncrease) {
	if .ProtocolLimits == nil {
		.ProtocolLimits = make(map[protocol.ID]baseLimitConfig)
	}
	.ProtocolLimits[] = baseLimitConfig{
		BaseLimit:         ,
		BaseLimitIncrease: ,
	}
}

func ( *ScalingLimitConfig) ( peer.ID,  BaseLimit,  BaseLimitIncrease) {
	if .PeerLimits == nil {
		.PeerLimits = make(map[peer.ID]baseLimitConfig)
	}
	.PeerLimits[] = baseLimitConfig{
		BaseLimit:         ,
		BaseLimitIncrease: ,
	}
}

func ( *ScalingLimitConfig) ( string,  BaseLimit,  BaseLimitIncrease) {
	if .ServicePeerLimits == nil {
		.ServicePeerLimits = make(map[string]baseLimitConfig)
	}
	.ServicePeerLimits[] = baseLimitConfig{
		BaseLimit:         ,
		BaseLimitIncrease: ,
	}
}

func ( *ScalingLimitConfig) ( protocol.ID,  BaseLimit,  BaseLimitIncrease) {
	if .ProtocolPeerLimits == nil {
		.ProtocolPeerLimits = make(map[protocol.ID]baseLimitConfig)
	}
	.ProtocolPeerLimits[] = baseLimitConfig{
		BaseLimit:         ,
		BaseLimitIncrease: ,
	}
}

type LimitVal int

const (
	// DefaultLimit is the default value for resources. The exact value depends on the context, but will get values from `DefaultLimits`.
	DefaultLimit LimitVal = 0
	// Unlimited is the value for unlimited resources. An arbitrarily high number will also work.
	Unlimited LimitVal = -1
	// BlockAllLimit is the LimitVal for allowing no amount of resources.
	BlockAllLimit LimitVal = -2
)

func ( LimitVal) () ([]byte, error) {
	if  == Unlimited {
		return json.Marshal("unlimited")
	} else if  == DefaultLimit {
		return json.Marshal("default")
	} else if  == BlockAllLimit {
		return json.Marshal("blockAll")
	}
	return json.Marshal(int())
}

func ( *LimitVal) ( []byte) error {
	if string() == `"default"` {
		* = DefaultLimit
		return nil
	} else if string() == `"unlimited"` {
		* = Unlimited
		return nil
	} else if string() == `"blockAll"` {
		* = BlockAllLimit
		return nil
	}

	var  int
	if  := json.Unmarshal(, &);  != nil {
		return 
	}

	if  == 0 {
		// If there is an explicit 0 in the JSON we should interpret this as block all.
		* = BlockAllLimit
		return nil
	}

	* = LimitVal()
	return nil
}

func ( LimitVal) ( int) int {
	if  == DefaultLimit {
		return 
	}
	if  == Unlimited {
		return math.MaxInt
	}
	if  == BlockAllLimit {
		return 0
	}
	return int()
}

type LimitVal64 int64

const (
	// Default is the default value for resources.
	DefaultLimit64 LimitVal64 = 0
	// Unlimited is the value for unlimited resources.
	Unlimited64 LimitVal64 = -1
	// BlockAllLimit64 is the LimitVal for allowing no amount of resources.
	BlockAllLimit64 LimitVal64 = -2
)

func ( LimitVal64) () ([]byte, error) {
	if  == Unlimited64 {
		return json.Marshal("unlimited")
	} else if  == DefaultLimit64 {
		return json.Marshal("default")
	} else if  == BlockAllLimit64 {
		return json.Marshal("blockAll")
	}

	// Convert this to a string because JSON doesn't support 64-bit integers.
	return json.Marshal(strconv.FormatInt(int64(), 10))
}

func ( *LimitVal64) ( []byte) error {
	if string() == `"default"` {
		* = DefaultLimit64
		return nil
	} else if string() == `"unlimited"` {
		* = Unlimited64
		return nil
	} else if string() == `"blockAll"` {
		* = BlockAllLimit64
		return nil
	}

	var  string
	if  := json.Unmarshal(, &);  != nil {
		// Is this an integer? Possible because of backwards compatibility.
		var  int
		if  := json.Unmarshal(, &);  != nil {
			return fmt.Errorf("failed to unmarshal limit value: %w", )
		}

		if  == 0 {
			// If there is an explicit 0 in the JSON we should interpret this as block all.
			* = BlockAllLimit64
			return nil
		}

		* = LimitVal64()
		return nil
	}

	,  := strconv.ParseInt(, 10, 64)
	if  != nil {
		return 
	}

	if  == 0 {
		// If there is an explicit 0 in the JSON we should interpret this as block all.
		* = BlockAllLimit64
		return nil
	}

	* = LimitVal64()
	return nil
}

func ( LimitVal64) ( int64) int64 {
	if  == DefaultLimit64 {
		return 
	}
	if  == Unlimited64 {
		return math.MaxInt64
	}
	if  == BlockAllLimit64 {
		return 0
	}
	return int64()
}

// ResourceLimits is the type for basic resource limits.
type ResourceLimits struct {
	Streams         LimitVal   `json:",omitempty"`
	StreamsInbound  LimitVal   `json:",omitempty"`
	StreamsOutbound LimitVal   `json:",omitempty"`
	Conns           LimitVal   `json:",omitempty"`
	ConnsInbound    LimitVal   `json:",omitempty"`
	ConnsOutbound   LimitVal   `json:",omitempty"`
	FD              LimitVal   `json:",omitempty"`
	Memory          LimitVal64 `json:",omitempty"`
}

func ( *ResourceLimits) () bool {
	if  == nil {
		return true
	}

	if .Streams == DefaultLimit &&
		.StreamsInbound == DefaultLimit &&
		.StreamsOutbound == DefaultLimit &&
		.Conns == DefaultLimit &&
		.ConnsInbound == DefaultLimit &&
		.ConnsOutbound == DefaultLimit &&
		.FD == DefaultLimit &&
		.Memory == DefaultLimit64 {
		return true
	}
	return false
}

func ( *ResourceLimits) () *ResourceLimits {
	if .IsDefault() {
		return nil
	}
	return 
}

// Apply overwrites all default limits with the values of l2
func ( *ResourceLimits) ( ResourceLimits) {
	if .Streams == DefaultLimit {
		.Streams = .Streams
	}
	if .StreamsInbound == DefaultLimit {
		.StreamsInbound = .StreamsInbound
	}
	if .StreamsOutbound == DefaultLimit {
		.StreamsOutbound = .StreamsOutbound
	}
	if .Conns == DefaultLimit {
		.Conns = .Conns
	}
	if .ConnsInbound == DefaultLimit {
		.ConnsInbound = .ConnsInbound
	}
	if .ConnsOutbound == DefaultLimit {
		.ConnsOutbound = .ConnsOutbound
	}
	if .FD == DefaultLimit {
		.FD = .FD
	}
	if .Memory == DefaultLimit64 {
		.Memory = .Memory
	}
}

func ( *ResourceLimits) ( Limit) BaseLimit {
	if  == nil {
		return BaseLimit{
			Streams:         .GetStreamTotalLimit(),
			StreamsInbound:  .GetStreamLimit(network.DirInbound),
			StreamsOutbound: .GetStreamLimit(network.DirOutbound),
			Conns:           .GetConnTotalLimit(),
			ConnsInbound:    .GetConnLimit(network.DirInbound),
			ConnsOutbound:   .GetConnLimit(network.DirOutbound),
			FD:              .GetFDLimit(),
			Memory:          .GetMemoryLimit(),
		}
	}

	return BaseLimit{
		Streams:         .Streams.Build(.GetStreamTotalLimit()),
		StreamsInbound:  .StreamsInbound.Build(.GetStreamLimit(network.DirInbound)),
		StreamsOutbound: .StreamsOutbound.Build(.GetStreamLimit(network.DirOutbound)),
		Conns:           .Conns.Build(.GetConnTotalLimit()),
		ConnsInbound:    .ConnsInbound.Build(.GetConnLimit(network.DirInbound)),
		ConnsOutbound:   .ConnsOutbound.Build(.GetConnLimit(network.DirOutbound)),
		FD:              .FD.Build(.GetFDLimit()),
		Memory:          .Memory.Build(.GetMemoryLimit()),
	}
}

type PartialLimitConfig struct {
	System    ResourceLimits `json:",omitempty"`
	Transient ResourceLimits `json:",omitempty"`

	// Limits that are applied to resources with an allowlisted multiaddr.
	// These will only be used if the normal System & Transient limits are
	// reached.
	AllowlistedSystem    ResourceLimits `json:",omitempty"`
	AllowlistedTransient ResourceLimits `json:",omitempty"`

	ServiceDefault ResourceLimits            `json:",omitempty"`
	Service        map[string]ResourceLimits `json:",omitempty"`

	ServicePeerDefault ResourceLimits            `json:",omitempty"`
	ServicePeer        map[string]ResourceLimits `json:",omitempty"`

	ProtocolDefault ResourceLimits                 `json:",omitempty"`
	Protocol        map[protocol.ID]ResourceLimits `json:",omitempty"`

	ProtocolPeerDefault ResourceLimits                 `json:",omitempty"`
	ProtocolPeer        map[protocol.ID]ResourceLimits `json:",omitempty"`

	PeerDefault ResourceLimits             `json:",omitempty"`
	Peer        map[peer.ID]ResourceLimits `json:",omitempty"`

	Conn   ResourceLimits `json:",omitempty"`
	Stream ResourceLimits `json:",omitempty"`
}

func ( *PartialLimitConfig) () ([]byte, error) {
	// we want to marshal the encoded peer id
	 := make(map[string]ResourceLimits, len(.Peer))
	for ,  := range .Peer {
		[.String()] = 
	}

	type  PartialLimitConfig
	return json.Marshal(&struct {
		*
		// String so we can have the properly marshalled peer id
		 map[string]ResourceLimits `json:",omitempty"`

		// The rest of the fields as pointers so that we omit empty values in the serialized result
		               *ResourceLimits `json:",omitempty"`
		            *ResourceLimits `json:",omitempty"`
		    *ResourceLimits `json:",omitempty"`
		 *ResourceLimits `json:",omitempty"`

		 *ResourceLimits `json:",omitempty"`

		 *ResourceLimits `json:",omitempty"`

		 *ResourceLimits `json:",omitempty"`

		 *ResourceLimits `json:",omitempty"`

		 *ResourceLimits `json:",omitempty"`

		   *ResourceLimits `json:",omitempty"`
		 *ResourceLimits `json:",omitempty"`
	}{
		: (*)(),
		:  ,

		:               .System.ToMaybeNilPtr(),
		:            .Transient.ToMaybeNilPtr(),
		:    .AllowlistedSystem.ToMaybeNilPtr(),
		: .AllowlistedTransient.ToMaybeNilPtr(),
		:       .ServiceDefault.ToMaybeNilPtr(),
		:   .ServicePeerDefault.ToMaybeNilPtr(),
		:      .ProtocolDefault.ToMaybeNilPtr(),
		:  .ProtocolPeerDefault.ToMaybeNilPtr(),
		:          .PeerDefault.ToMaybeNilPtr(),
		:                 .Conn.ToMaybeNilPtr(),
		:               .Stream.ToMaybeNilPtr(),
	})
}

func applyResourceLimitsMap[ comparable]( *map[]ResourceLimits,  map[]ResourceLimits,  ResourceLimits) {
	for ,  := range * {
		 := 
		if ,  := [];  {
			 = 
		}
		.Apply()
		(*)[] = 
	}
	if * == nil &&  != nil {
		* = make(map[]ResourceLimits)
	}
	for ,  := range  {
		if ,  := (*)[]; ! {
			(*)[] = 
		}
	}
}

func ( *PartialLimitConfig) ( PartialLimitConfig) {
	.System.Apply(.System)
	.Transient.Apply(.Transient)
	.AllowlistedSystem.Apply(.AllowlistedSystem)
	.AllowlistedTransient.Apply(.AllowlistedTransient)
	.ServiceDefault.Apply(.ServiceDefault)
	.ServicePeerDefault.Apply(.ServicePeerDefault)
	.ProtocolDefault.Apply(.ProtocolDefault)
	.ProtocolPeerDefault.Apply(.ProtocolPeerDefault)
	.PeerDefault.Apply(.PeerDefault)
	.Conn.Apply(.Conn)
	.Stream.Apply(.Stream)

	applyResourceLimitsMap(&.Service, .Service, .ServiceDefault)
	applyResourceLimitsMap(&.ServicePeer, .ServicePeer, .ServicePeerDefault)
	applyResourceLimitsMap(&.Protocol, .Protocol, .ProtocolDefault)
	applyResourceLimitsMap(&.ProtocolPeer, .ProtocolPeer, .ProtocolPeerDefault)
	applyResourceLimitsMap(&.Peer, .Peer, .PeerDefault)
}

func ( PartialLimitConfig) ( ConcreteLimitConfig) ConcreteLimitConfig {
	 := 

	.system = .System.Build(.system)
	.transient = .Transient.Build(.transient)
	.allowlistedSystem = .AllowlistedSystem.Build(.allowlistedSystem)
	.allowlistedTransient = .AllowlistedTransient.Build(.allowlistedTransient)
	.serviceDefault = .ServiceDefault.Build(.serviceDefault)
	.servicePeerDefault = .ServicePeerDefault.Build(.servicePeerDefault)
	.protocolDefault = .ProtocolDefault.Build(.protocolDefault)
	.protocolPeerDefault = .ProtocolPeerDefault.Build(.protocolPeerDefault)
	.peerDefault = .PeerDefault.Build(.peerDefault)
	.conn = .Conn.Build(.conn)
	.stream = .Stream.Build(.stream)

	.service = buildMapWithDefault(.Service, .service, .serviceDefault)
	.servicePeer = buildMapWithDefault(.ServicePeer, .servicePeer, .servicePeerDefault)
	.protocol = buildMapWithDefault(.Protocol, .protocol, .protocolDefault)
	.protocolPeer = buildMapWithDefault(.ProtocolPeer, .protocolPeer, .protocolPeerDefault)
	.peer = buildMapWithDefault(.Peer, .peer, .peerDefault)

	return 
}

func buildMapWithDefault[ comparable]( map[]ResourceLimits,  map[]BaseLimit,  BaseLimit) map[]BaseLimit {
	if  == nil &&  == nil {
		return nil
	}

	 := make(map[]BaseLimit)
	for ,  := range  {
		[] = 
	}

	for ,  := range  {
		if ,  := [];  {
			[] = .Build()
		} else {
			[] = .Build()
		}
	}

	return 
}

// ConcreteLimitConfig is similar to PartialLimitConfig, but all values are defined.
// There is no unset "default" value. Commonly constructed by calling
// PartialLimitConfig.Build(rcmgr.DefaultLimits.AutoScale())
type ConcreteLimitConfig struct {
	system    BaseLimit
	transient BaseLimit

	// Limits that are applied to resources with an allowlisted multiaddr.
	// These will only be used if the normal System & Transient limits are
	// reached.
	allowlistedSystem    BaseLimit
	allowlistedTransient BaseLimit

	serviceDefault BaseLimit
	service        map[string]BaseLimit

	servicePeerDefault BaseLimit
	servicePeer        map[string]BaseLimit

	protocolDefault BaseLimit
	protocol        map[protocol.ID]BaseLimit

	protocolPeerDefault BaseLimit
	protocolPeer        map[protocol.ID]BaseLimit

	peerDefault BaseLimit
	peer        map[peer.ID]BaseLimit

	conn   BaseLimit
	stream BaseLimit
}

func resourceLimitsMapFromBaseLimitMap[ comparable]( map[]BaseLimit) map[]ResourceLimits {
	if  == nil {
		return nil
	}

	 := make(map[]ResourceLimits)
	for ,  := range  {
		[] = .ToResourceLimits()
	}

	return 
}

// ToPartialLimitConfig converts a ConcreteLimitConfig to a PartialLimitConfig.
// The returned PartialLimitConfig will have no default values.
func ( ConcreteLimitConfig) () PartialLimitConfig {
	return PartialLimitConfig{
		System:               .system.ToResourceLimits(),
		Transient:            .transient.ToResourceLimits(),
		AllowlistedSystem:    .allowlistedSystem.ToResourceLimits(),
		AllowlistedTransient: .allowlistedTransient.ToResourceLimits(),
		ServiceDefault:       .serviceDefault.ToResourceLimits(),
		Service:              resourceLimitsMapFromBaseLimitMap(.service),
		ServicePeerDefault:   .servicePeerDefault.ToResourceLimits(),
		ServicePeer:          resourceLimitsMapFromBaseLimitMap(.servicePeer),
		ProtocolDefault:      .protocolDefault.ToResourceLimits(),
		Protocol:             resourceLimitsMapFromBaseLimitMap(.protocol),
		ProtocolPeerDefault:  .protocolPeerDefault.ToResourceLimits(),
		ProtocolPeer:         resourceLimitsMapFromBaseLimitMap(.protocolPeer),
		PeerDefault:          .peerDefault.ToResourceLimits(),
		Peer:                 resourceLimitsMapFromBaseLimitMap(.peer),
		Conn:                 .conn.ToResourceLimits(),
		Stream:               .stream.ToResourceLimits(),
	}
}

// Scale scales up a limit configuration.
// memory is the amount of memory that the stack is allowed to consume,
// for a dedicated node it's recommended to use 1/8 of the installed system memory.
// If memory is smaller than 128 MB, the base configuration will be used.
func ( *ScalingLimitConfig) ( int64,  int) ConcreteLimitConfig {
	 := ConcreteLimitConfig{
		system:               scale(.SystemBaseLimit, .SystemLimitIncrease, , ),
		transient:            scale(.TransientBaseLimit, .TransientLimitIncrease, , ),
		allowlistedSystem:    scale(.AllowlistedSystemBaseLimit, .AllowlistedSystemLimitIncrease, , ),
		allowlistedTransient: scale(.AllowlistedTransientBaseLimit, .AllowlistedTransientLimitIncrease, , ),
		serviceDefault:       scale(.ServiceBaseLimit, .ServiceLimitIncrease, , ),
		servicePeerDefault:   scale(.ServicePeerBaseLimit, .ServicePeerLimitIncrease, , ),
		protocolDefault:      scale(.ProtocolBaseLimit, .ProtocolLimitIncrease, , ),
		protocolPeerDefault:  scale(.ProtocolPeerBaseLimit, .ProtocolPeerLimitIncrease, , ),
		peerDefault:          scale(.PeerBaseLimit, .PeerLimitIncrease, , ),
		conn:                 scale(.ConnBaseLimit, .ConnLimitIncrease, , ),
		stream:               scale(.StreamBaseLimit, .ConnLimitIncrease, , ),
	}
	if .ServiceLimits != nil {
		.service = make(map[string]BaseLimit)
		for ,  := range .ServiceLimits {
			.service[] = scale(.BaseLimit, .BaseLimitIncrease, , )
		}
	}
	if .ProtocolLimits != nil {
		.protocol = make(map[protocol.ID]BaseLimit)
		for ,  := range .ProtocolLimits {
			.protocol[] = scale(.BaseLimit, .BaseLimitIncrease, , )
		}
	}
	if .PeerLimits != nil {
		.peer = make(map[peer.ID]BaseLimit)
		for ,  := range .PeerLimits {
			.peer[] = scale(.BaseLimit, .BaseLimitIncrease, , )
		}
	}
	if .ServicePeerLimits != nil {
		.servicePeer = make(map[string]BaseLimit)
		for ,  := range .ServicePeerLimits {
			.servicePeer[] = scale(.BaseLimit, .BaseLimitIncrease, , )
		}
	}
	if .ProtocolPeerLimits != nil {
		.protocolPeer = make(map[protocol.ID]BaseLimit)
		for ,  := range .ProtocolPeerLimits {
			.protocolPeer[] = scale(.BaseLimit, .BaseLimitIncrease, , )
		}
	}
	return 
}

func ( *ScalingLimitConfig) () ConcreteLimitConfig {
	return .Scale(
		int64(memory.TotalMemory())/8,
		getNumFDs()/2,
	)
}

func scale( BaseLimit,  BaseLimitIncrease,  int64,  int) BaseLimit {
	// mebibytesAvailable represents how many MiBs we're allowed to use. Used to
	// scale the limits. If this is below 128MiB we set it to 0 to just use the
	// base amounts.
	var  int
	if  > 128<<20 {
		 = int(() >> 20)
	}
	 := BaseLimit{
		StreamsInbound:  .StreamsInbound + (.StreamsInbound*)>>10,
		StreamsOutbound: .StreamsOutbound + (.StreamsOutbound*)>>10,
		Streams:         .Streams + (.Streams*)>>10,
		ConnsInbound:    .ConnsInbound + (.ConnsInbound*)>>10,
		ConnsOutbound:   .ConnsOutbound + (.ConnsOutbound*)>>10,
		Conns:           .Conns + (.Conns*)>>10,
		Memory:          .Memory + (.Memory*int64())>>10,
		FD:              .FD,
	}
	if .FDFraction > 0 &&  > 0 {
		.FD = int(.FDFraction * float64())
		if .FD < .FD {
			// Use at least the base amount
			.FD = .FD
		}
	}
	return 
}

// DefaultLimits are the limits used by the default limiter constructors.
var DefaultLimits = ScalingLimitConfig{
	SystemBaseLimit: BaseLimit{
		ConnsInbound:    64,
		ConnsOutbound:   128,
		Conns:           128,
		StreamsInbound:  64 * 16,
		StreamsOutbound: 128 * 16,
		Streams:         128 * 16,
		Memory:          128 << 20,
		FD:              256,
	},

	SystemLimitIncrease: BaseLimitIncrease{
		ConnsInbound:    64,
		ConnsOutbound:   128,
		Conns:           128,
		StreamsInbound:  64 * 16,
		StreamsOutbound: 128 * 16,
		Streams:         128 * 16,
		Memory:          1 << 30,
		FDFraction:      1,
	},

	TransientBaseLimit: BaseLimit{
		ConnsInbound:    32,
		ConnsOutbound:   64,
		Conns:           64,
		StreamsInbound:  128,
		StreamsOutbound: 256,
		Streams:         256,
		Memory:          32 << 20,
		FD:              64,
	},

	TransientLimitIncrease: BaseLimitIncrease{
		ConnsInbound:    16,
		ConnsOutbound:   32,
		Conns:           32,
		StreamsInbound:  128,
		StreamsOutbound: 256,
		Streams:         256,
		Memory:          128 << 20,
		FDFraction:      0.25,
	},

	// Setting the allowlisted limits to be the same as the normal limits. The
	// allowlist only activates when you reach your normal system/transient
	// limits. So it's okay if these limits err on the side of being too big,
	// since most of the time you won't even use any of these. Tune these down
	// if you want to manage your resources against an allowlisted endpoint.
	AllowlistedSystemBaseLimit: BaseLimit{
		ConnsInbound:    64,
		ConnsOutbound:   128,
		Conns:           128,
		StreamsInbound:  64 * 16,
		StreamsOutbound: 128 * 16,
		Streams:         128 * 16,
		Memory:          128 << 20,
		FD:              256,
	},

	AllowlistedSystemLimitIncrease: BaseLimitIncrease{
		ConnsInbound:    64,
		ConnsOutbound:   128,
		Conns:           128,
		StreamsInbound:  64 * 16,
		StreamsOutbound: 128 * 16,
		Streams:         128 * 16,
		Memory:          1 << 30,
		FDFraction:      1,
	},

	AllowlistedTransientBaseLimit: BaseLimit{
		ConnsInbound:    32,
		ConnsOutbound:   64,
		Conns:           64,
		StreamsInbound:  128,
		StreamsOutbound: 256,
		Streams:         256,
		Memory:          32 << 20,
		FD:              64,
	},

	AllowlistedTransientLimitIncrease: BaseLimitIncrease{
		ConnsInbound:    16,
		ConnsOutbound:   32,
		Conns:           32,
		StreamsInbound:  128,
		StreamsOutbound: 256,
		Streams:         256,
		Memory:          128 << 20,
		FDFraction:      0.25,
	},

	ServiceBaseLimit: BaseLimit{
		StreamsInbound:  1024,
		StreamsOutbound: 4096,
		Streams:         4096,
		Memory:          64 << 20,
	},

	ServiceLimitIncrease: BaseLimitIncrease{
		StreamsInbound:  512,
		StreamsOutbound: 2048,
		Streams:         2048,
		Memory:          128 << 20,
	},

	ServicePeerBaseLimit: BaseLimit{
		StreamsInbound:  128,
		StreamsOutbound: 256,
		Streams:         256,
		Memory:          16 << 20,
	},

	ServicePeerLimitIncrease: BaseLimitIncrease{
		StreamsInbound:  4,
		StreamsOutbound: 8,
		Streams:         8,
		Memory:          4 << 20,
	},

	ProtocolBaseLimit: BaseLimit{
		StreamsInbound:  512,
		StreamsOutbound: 2048,
		Streams:         2048,
		Memory:          64 << 20,
	},

	ProtocolLimitIncrease: BaseLimitIncrease{
		StreamsInbound:  256,
		StreamsOutbound: 512,
		Streams:         512,
		Memory:          164 << 20,
	},

	ProtocolPeerBaseLimit: BaseLimit{
		StreamsInbound:  64,
		StreamsOutbound: 128,
		Streams:         256,
		Memory:          16 << 20,
	},

	ProtocolPeerLimitIncrease: BaseLimitIncrease{
		StreamsInbound:  4,
		StreamsOutbound: 8,
		Streams:         16,
		Memory:          4,
	},

	PeerBaseLimit: BaseLimit{
		// 8 for now so that it matches the number of concurrent dials we may do
		// in swarm_dial.go. With future smart dialing work we should bring this
		// down
		ConnsInbound:    8,
		ConnsOutbound:   8,
		Conns:           8,
		StreamsInbound:  256,
		StreamsOutbound: 512,
		Streams:         512,
		Memory:          64 << 20,
		FD:              4,
	},

	PeerLimitIncrease: BaseLimitIncrease{
		StreamsInbound:  128,
		StreamsOutbound: 256,
		Streams:         256,
		Memory:          128 << 20,
		FDFraction:      1.0 / 64,
	},

	ConnBaseLimit: BaseLimit{
		ConnsInbound:  1,
		ConnsOutbound: 1,
		Conns:         1,
		FD:            1,
		Memory:        32 << 20,
	},

	StreamBaseLimit: BaseLimit{
		StreamsInbound:  1,
		StreamsOutbound: 1,
		Streams:         1,
		Memory:          16 << 20,
	},
}

var infiniteBaseLimit = BaseLimit{
	Streams:         math.MaxInt,
	StreamsInbound:  math.MaxInt,
	StreamsOutbound: math.MaxInt,
	Conns:           math.MaxInt,
	ConnsInbound:    math.MaxInt,
	ConnsOutbound:   math.MaxInt,
	FD:              math.MaxInt,
	Memory:          math.MaxInt64,
}

// InfiniteLimits are a limiter configuration that uses unlimited limits, thus effectively not limiting anything.
// Keep in mind that the operating system limits the number of file descriptors that an application can use.
var InfiniteLimits = ConcreteLimitConfig{
	system:               infiniteBaseLimit,
	transient:            infiniteBaseLimit,
	allowlistedSystem:    infiniteBaseLimit,
	allowlistedTransient: infiniteBaseLimit,
	serviceDefault:       infiniteBaseLimit,
	servicePeerDefault:   infiniteBaseLimit,
	protocolDefault:      infiniteBaseLimit,
	protocolPeerDefault:  infiniteBaseLimit,
	peerDefault:          infiniteBaseLimit,
	conn:                 infiniteBaseLimit,
	stream:               infiniteBaseLimit,
}