server

package
v1.36.0 Latest Latest
Warning

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

Go to latest
Published: Sep 10, 2025 License: MIT Imports: 57 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DockerAPIVersion         = "1.24"
	DockerRouterLabelHost    = "mc-router.host"
	DockerRouterLabelPort    = "mc-router.port"
	DockerRouterLabelDefault = "mc-router.default"
	DockerRouterLabelNetwork = "mc-router.network"
)
View Source
const (
	AnnotationExternalServerName = "mc-router.itzg.me/externalServerName"
	AnnotationDefaultServer      = "mc-router.itzg.me/defaultServer"
	AnnotationAutoScaleUp        = "mc-router.itzg.me/autoScaleUp"
	AnnotationAutoScaleDown      = "mc-router.itzg.me/autoScaleDown"
)
View Source
const (
	MetricsBackendExpvar     = "expvar"
	MetricsBackendPrometheus = "prometheus"
	MetricsBackendInfluxDB   = "influxdb"
	MetricsBackendDiscard    = "discard"
)
View Source
const (
	WebhookEventConnecting    = "connect"
	WebhookEventDisconnecting = "disconnect"
)
View Source
const (
	WebhookStatusMissingBackend          = "missing-backend"
	WebhookStatusFailedBackendConnection = "failed-backend-connection"
	WebhookStatusSuccess                 = "success"
)

Variables

View Source
var EmptyScalerFunc = func(ctx context.Context) error { return nil }
View Source
var Routes = NewRoutes()
View Source
var RoutesConfigLoader = &routesConfigLoader{}

Functions

func StartApiServer

func StartApiServer(apiBinding string)

Types

type ActiveConnections

type ActiveConnections struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

func NewActiveConnections

func NewActiveConnections() *ActiveConnections

func (*ActiveConnections) Decrement

func (sm *ActiveConnections) Decrement(serverAddress string)

func (*ActiveConnections) GetCount

func (sm *ActiveConnections) GetCount(serverAddress string) int

func (*ActiveConnections) Increment

func (sm *ActiveConnections) Increment(serverAddress string)

type AllowDenyConfig

type AllowDenyConfig struct {
	Global  AllowDenyLists
	Servers map[string]AllowDenyLists
}

func ParseAllowDenyConfig

func ParseAllowDenyConfig(allowDenyListPath string) (*AllowDenyConfig, error)

func (*AllowDenyConfig) ServerAllowsPlayer

func (allowDenyConfig *AllowDenyConfig) ServerAllowsPlayer(serverAddress string, userInfo *PlayerInfo) bool

type AllowDenyLists

type AllowDenyLists struct {
	Allowlist []PlayerInfo
	Denylist  []PlayerInfo
}

type AutoScale

type AutoScale struct {
	Up        bool   `usage:"Increase Kubernetes StatefulSet Replicas (only) from 0 to 1 on respective backend servers when accessed"`
	Down      bool   `` /* 144-byte string literal not displayed */
	DownAfter string `default:"10m" usage:"Server scale down delay after there are no connections"`
	AllowDeny string `` /* 273-byte string literal not displayed */
}

type ClientFilter

type ClientFilter struct {
	// contains filtered or unexported fields
}

ClientFilter performs allow/deny filtering of client IP addresses

func NewClientFilter

func NewClientFilter(allows []string, denies []string) (*ClientFilter, error)

NewClientFilter provides a mechanism to evaluate client IP addresses and determine if they should be allowed access or not. The allows and denies can each or both be nil or netip.ParseAddr allowed values.

func NewClientFilterAllowAll

func NewClientFilterAllowAll() *ClientFilter

func (*ClientFilter) Allow

func (f *ClientFilter) Allow(addrPort netip.AddrPort) bool

Allow determines if this filter allows the given address where addrStr is a netip.ParseAddr allowed address

type ClientInfo

type ClientInfo struct {
	Host string `json:"host"`
	Port int    `json:"port"`
}

func ClientInfoFromAddr

func ClientInfoFromAddr(addr net.Addr) *ClientInfo

type Config

type Config struct {
	Port                  int               `default:"25565" usage:"The [port] bound to listen for Minecraft client connections"`
	Default               string            `usage:"host:port of a default Minecraft server to use when mapping not found"`
	Mapping               map[string]string `usage:"Comma or newline delimited or repeated mappings of externalHostname=host:port"`
	ApiBinding            string            `usage:"The [host:port] bound for servicing API requests"`
	CpuProfile            string            `usage:"Enables CPU profiling and writes to given path"`
	ConnectionRateLimit   int               `default:"1" usage:"Max number of connections to allow per second"`
	InKubeCluster         bool              `usage:"Use in-cluster Kubernetes config"`
	KubeConfig            string            `usage:"The path to a Kubernetes configuration file"`
	KubeNamespace         string            `usage:"The namespace to watch or blank for all, which is the default"`
	InDocker              bool              `usage:"Use Docker service discovery"`
	InDockerSwarm         bool              `usage:"Use Docker Swarm service discovery"`
	DockerSocket          string            `default:"unix:///var/run/docker.sock" usage:"Path to Docker socket to use"`
	DockerTimeout         int               `default:"0" usage:"Timeout configuration in seconds for the Docker integrations"`
	DockerRefreshInterval int               `default:"15" usage:"Refresh interval in seconds for the Docker integrations"`
	MetricsBackend        string            `default:"discard" usage:"Backend to use for metrics exposure/publishing: discard,expvar,influxdb,prometheus"`
	MetricsBackendConfig  MetricsBackendConfig
	UseProxyProtocol      bool     `default:"false" usage:"Send PROXY protocol to backend servers"`
	ReceiveProxyProtocol  bool     `` /* 190-byte string literal not displayed */
	TrustedProxies        []string `usage:"Comma delimited list of CIDR notation IP blocks to trust when receiving PROXY protocol"`
	RecordLogins          bool     `default:"false" usage:"Log and generate metrics on player logins. Metrics only supported with influxdb or prometheus backend"`
	Routes                RoutesConfig
	Ngrok                 NgrokConfig
	AutoScale             AutoScale

	ClientsToAllow []string `usage:"Zero or more client IP addresses or CIDRs to allow. Takes precedence over deny."`
	ClientsToDeny  []string `usage:"Zero or more client IP addresses or CIDRs to deny. Ignored if any configured to allow"`

	SimplifySRV bool `default:"false" usage:"Simplify fully qualified SRV records for mapping"`

	Webhook WebhookConfig `usage:"Webhook configuration"`
}

type ConnectionNotifier

type ConnectionNotifier interface {
	// NotifyMissingBackend is called when an inbound connection is received for a server that does not have a backend.
	NotifyMissingBackend(ctx context.Context, clientAddr net.Addr, server string, playerInfo *PlayerInfo) error

	// NotifyFailedBackendConnection is called when the backend connection failed.
	NotifyFailedBackendConnection(ctx context.Context,
		clientAddr net.Addr, serverAddress string, playerInfo *PlayerInfo, backendHostPort string, err error) error

	// NotifyConnected is called when the backend connection succeeded.
	NotifyConnected(ctx context.Context,
		clientAddr net.Addr, serverAddress string, playerInfo *PlayerInfo, backendHostPort string) error

	// NotifyDisconnected is called when the backend connection terminates.
	NotifyDisconnected(ctx context.Context,
		clientAddr net.Addr, serverAddress string, playerInfo *PlayerInfo, backendHostPort string) error
}

type Connector

type Connector struct {
	// contains filtered or unexported fields
}

func NewConnector

func NewConnector(ctx context.Context, metrics *ConnectorMetrics, sendProxyProto bool, recordLogins bool, autoScaleUpAllowDenyConfig *AllowDenyConfig) *Connector

func (*Connector) AcceptConnection

func (c *Connector) AcceptConnection(conn net.Conn)

AcceptConnection provides a way to externally supply a connection to consume. Note that this will skip rate limiting.

func (*Connector) HandleConnection

func (c *Connector) HandleConnection(frontendConn net.Conn)

func (*Connector) StartAcceptingConnections

func (c *Connector) StartAcceptingConnections(listenAddress string, connRateLimit int) error

func (*Connector) UseClientFilter

func (c *Connector) UseClientFilter(filter *ClientFilter)

func (*Connector) UseConnectionNotifier

func (c *Connector) UseConnectionNotifier(notifier ConnectionNotifier)

func (*Connector) UseNgrok

func (c *Connector) UseNgrok(config NgrokConfig)

func (*Connector) UseReceiveProxyProto

func (c *Connector) UseReceiveProxyProto(trustedProxyNets []*net.IPNet)

func (*Connector) WaitForConnections

func (c *Connector) WaitForConnections()

type ConnectorMetrics

type ConnectorMetrics struct {
	Errors                  metrics.Counter
	BytesTransmitted        metrics.Counter
	ConnectionsFrontend     metrics.Counter
	ConnectionsBackend      metrics.Counter
	ActiveConnections       metrics.Gauge
	ServerActivePlayer      metrics.Gauge
	ServerLogins            metrics.Counter
	ServerActiveConnections metrics.Gauge
}

type IDockerWatcher

type IDockerWatcher interface {
	Start(ctx context.Context, socket string, timeoutSeconds int, refreshIntervalSeconds int, autoScaleUp bool, autoScaleDown bool) error
}
var DockerSwarmWatcher IDockerWatcher = &dockerSwarmWatcherImpl{}
var DockerWatcher IDockerWatcher = &dockerWatcherImpl{}

type IDownScaler

type IDownScaler interface {
	Reset()
	Begin(serverAddress string)
	Cancel(serverAddress string)
}
var DownScaler IDownScaler

func NewDownScaler

func NewDownScaler(ctx context.Context, enabled bool, delay time.Duration) IDownScaler

type IRoutes

type IRoutes interface {
	RoutesHandler

	Reset()
	RegisterAll(mappings map[string]string)
	// FindBackendForServerAddress returns the host:port for the external server address, if registered.
	// Otherwise, an empty string is returned. Also returns the normalized version of the given serverAddress.
	// The 3rd value returned is an (optional) "waker" function which a caller must invoke to wake up serverAddress.
	// The 4th value returned is an (optional) "sleeper" function which a caller must invoke to shut down serverAddress.
	FindBackendForServerAddress(ctx context.Context, serverAddress string) (string, string, ScalerFunc, ScalerFunc)
	GetMappings() map[string]string
	GetDefaultRoute() string
	SimplifySRV(srvEnabled bool)
}

func NewRoutes

func NewRoutes() IRoutes

type K8sWatcher

type K8sWatcher struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

K8sWatcher is a RouteFinder that can find routes from kubernetes services. It also watches for stateful sets to auto scale up/down, if enabled.

func NewK8sWatcherInCluster

func NewK8sWatcherInCluster() (*K8sWatcher, error)

func NewK8sWatcherWithConfig

func NewK8sWatcherWithConfig(kubeConfigFile string) (*K8sWatcher, error)

func (*K8sWatcher) Start

func (w *K8sWatcher) Start(ctx context.Context, handler RoutesHandler) error

func (*K8sWatcher) String

func (w *K8sWatcher) String() string

func (*K8sWatcher) WithAutoScale

func (w *K8sWatcher) WithAutoScale(autoScaleUp bool, autoScaleDown bool) *K8sWatcher

func (*K8sWatcher) WithNamespace

func (w *K8sWatcher) WithNamespace(namespace string) *K8sWatcher

type MetricsBackendConfig

type MetricsBackendConfig struct {
	Influxdb struct {
		Interval        time.Duration     `default:"1m"`
		Tags            map[string]string `usage:"any extra tags to be included with all reported metrics"`
		Addr            string
		Username        string
		Password        string
		Database        string
		RetentionPolicy string
	}
}

type MetricsBuilder

type MetricsBuilder interface {
	BuildConnectorMetrics() *ConnectorMetrics
	Start(ctx context.Context) error
}

func NewMetricsBuilder

func NewMetricsBuilder(backend string, config *MetricsBackendConfig) MetricsBuilder

NewMetricsBuilder creates a new MetricsBuilder based on the specified backend. If the backend is not recognized, a discard builder is returned. config can be nil if the backend is not influxdb.

type NgrokConfig

type NgrokConfig struct {
	Token      string `usage:"If set, an ngrok tunnel will be established. It is HIGHLY recommended to pass as an environment variable."`
	RemoteAddr string `usage:"If set, the TCP address to request for this edge"`
}

type NgrokConnector

type NgrokConnector struct {
	// contains filtered or unexported fields
}

type PlayerInfo

type PlayerInfo struct {
	Name string    `json:"name"`
	Uuid uuid.UUID `json:"uuid"`
}

func (*PlayerInfo) String

func (p *PlayerInfo) String() string

type RouteFinder

type RouteFinder interface {
	Start(ctx context.Context, handler RoutesHandler) error
	String() string
}

RouteFinder implementations find new routes in the system that can be tracked by a RoutesHandler

type RoutesConfig

type RoutesConfig struct {
	Config      string `usage:"Name or full [path] to routes config file"`
	ConfigWatch bool   `usage:"Watch for config file changes"`
}

type RoutesConfigSchema

type RoutesConfigSchema struct {
	DefaultServer string            `json:"default-server"`
	Mappings      map[string]string `json:"mappings"`
}

RoutesConfigSchema declares the schema of the json file that can provide routes to serve

type RoutesHandler

type RoutesHandler interface {
	CreateMapping(serverAddress string, backend string, waker ScalerFunc, sleeper ScalerFunc)
	SetDefaultRoute(backend string)
	// DeleteMapping requests that the serverAddress be removed from routes.
	// Returns true if the route existed.
	DeleteMapping(serverAddress string) bool
}

type ScalerFunc

type ScalerFunc func(ctx context.Context) error

type Server

type Server struct {
	// contains filtered or unexported fields
}

func NewServer

func NewServer(ctx context.Context, config *Config) (*Server, error)

func (*Server) AcceptConnection

func (s *Server) AcceptConnection(conn net.Conn)

AcceptConnection provides a way to externally supply a connection to consume Note that this will skip rate limiting.

func (*Server) Done

func (s *Server) Done() <-chan struct{}

Done provides a channel notified when the server has closed all connections, etc

func (*Server) ReloadConfig

func (s *Server) ReloadConfig()

ReloadConfig indicates that an external request, such as a SIGHUP, is requesting the routes config file to be reloaded, if enabled

func (*Server) Run

func (s *Server) Run()

Run will run the server until the context is done or a fatal error occurs, so this should be in a go routine.

type WebhookConfig

type WebhookConfig struct {
	Url         string `usage:"If set, a POST request that contains connection status notifications will be sent to this HTTP address"`
	RequireUser bool   `` /* 126-byte string literal not displayed */
}

type WebhookNotifier

type WebhookNotifier struct {
	// contains filtered or unexported fields
}

WebhookNotifier implements ConnectionNotifier by sending a POST request to a webhook URL. The payload is a JSON object defined by WebhookNotifierPayload.

func NewWebhookNotifier

func NewWebhookNotifier(url string, requireUser bool) *WebhookNotifier

func (*WebhookNotifier) NotifyConnected

func (w *WebhookNotifier) NotifyConnected(ctx context.Context, clientAddr net.Addr, serverAddress string, playerInfo *PlayerInfo, backendHostPort string) error

func (*WebhookNotifier) NotifyDisconnected

func (w *WebhookNotifier) NotifyDisconnected(ctx context.Context, clientAddr net.Addr, serverAddress string, playerInfo *PlayerInfo, backendHostPort string) error

func (*WebhookNotifier) NotifyFailedBackendConnection

func (w *WebhookNotifier) NotifyFailedBackendConnection(ctx context.Context, clientAddr net.Addr, server string,
	playerInfo *PlayerInfo, backendHostPort string, err error) error

func (*WebhookNotifier) NotifyMissingBackend

func (w *WebhookNotifier) NotifyMissingBackend(ctx context.Context, clientAddr net.Addr, server string, playerInfo *PlayerInfo) error

type WebhookNotifierPayload

type WebhookNotifierPayload struct {
	Event           string      `json:"event"`
	Timestamp       time.Time   `json:"timestamp"`
	Status          string      `json:"status"`
	Client          *ClientInfo `json:"client"`
	Server          string      `json:"server"`
	PlayerInfo      *PlayerInfo `json:"player,omitempty"`
	BackendHostPort string      `json:"backend,omitempty"`
	Error           string      `json:"error,omitempty"`
}

Jump to

Keyboard shortcuts

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