Help us shape the future of Go! Take the 2026 Go Developer Survey

nxs

package module
v0.0.0-...-066380b Latest Latest
Warning

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

Go to latest
Published: Oct 3, 2026 License: MIT Imports: 44 Imported by: 0

README

go-nxs

A Go implementation of NetherNet External Signaling (NXS) for hosts, built on go-nethernet. NXS lets a signaling provider such as Warden handle HTTPS signaling with players, while game traffic flows directly between players and the host.

The provider answers each player with a short-lived NXS1 token in the ICE ufrag. The host validates the token from the player's first STUN request and admits the connection into a nethernet.Listener, without seeing the player's SDP.

Usage

nxs.Provider implements nethernet.Signaling:

p, err := nxs.New(ctx, nxs.Config{
	Origin:   "https://provider.example",
	Token:    token,      // Optional: anonymous proof of work is used otherwise.
	StateDir: "nxs",      // One directory per instance. It holds secrets.
	Address:  ":19133",   // The UDP port players connect to.
})
if err != nil {
	panic(err)
}
defer p.Close()

l, err := nethernet.ListenConfig{}.Listen(p)

With gophertunnel, pass the Provider as minecraft.NetherNet{Signaling: p} to minecraft.ListenConfig.ListenNetwork. After login, gophertunnel checks the login identity against the admission through nethernet.Conn.VerifyPublicKey. See examples/gophertunnel.

The host advertises its local addresses and STUN mappings of Address, and withholds public endpoints that fail the regional checks of the provider. Set Config.Endpoints if players must reach it through a forwarded port instead.

Options
  • WebSocket carries operations over the WebSocket control transport of the provider, falling back to HTTPS.
  • AssistedJoins lets the provider forward the offers of players over the WebSocket, for players that cannot be admitted statelessly.
  • Diagnostics answers the connectivity checks of the provider on the gameplay socket. They never reach the Listener.
  • GameOutcomes reports that the application calls GameJoined and GameRejected.

Pause and Resume stop and resume admitting players without closing established connections.

RotateAdmissionKey, RotateMachineKey, Deregister and ExtensionRequest expose the remaining operations. Registrations are recovered in a new generation after a restart, or when the provider fences the current one.

Documentation

Overview

Package nxs implements a NetherNet host for providers of NetherNet External Signaling (NXS), such as Warden. The provider handles signaling with players and routes them to the host, which admits connections from stateless tokens carried in their first STUN request.

A Provider implements nethernet.Signaling and is used to listen with a nethernet.ListenConfig:

p, err := nxs.New(ctx, nxs.Config{Origin: "https://provider.example", StateDir: "nxs", Address: ":19133"})
...
l, err := nethernet.ListenConfig{}.Listen(p)

Index

Constants

View Source
const (
	// Protocol is the NXS protocol identifier.
	Protocol = "nethernet-external-signaling-v1"
	// SignatureVersion is the machine request signature identifier.
	SignatureVersion = "nxs-es384-v1"
	// Profile is the operational profile identifier.
	Profile = "nxs-admission-v1"
	// Capability is the stateless admission capability published in host profiles.
	Capability = "nethernet.stateless-admission.v1"
)
View Source
const (

	// ModeAutomatic lets the provider choose between creating a service and attaching an instance.
	ModeAutomatic = "automatic"
	// ModeNewService creates a new service with this instance.
	ModeNewService = "new-service"
	// ModeAttachInstance attaches this instance to an existing service. It requires a token and Placement.
	ModeAttachInstance = "attach-instance"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Origin is the HTTPS origin of the provider, such as https://provider.example.
	Origin string
	// StateDir is the directory holding the durable state of this instance, including its
	// machine key and admission keys. Each instance needs its own directory.
	StateDir string
	// Token is the bearer token used to register this instance. If empty, the instance is
	// registered anonymously with proof of work, if the provider allows it.
	Token string
	// Mode is the registration mode. It defaults to ModeAutomatic.
	Mode string
	// Label is an optional label for a new registration.
	Label string
	// Placement is the optional region and pool of the instance.
	Placement *Placement

	// Address is the UDP address that players connect to. It defaults to ":0", which
	// should only be used if the port is reachable through STUN mappings.
	Address string
	// Endpoints are the public UDP endpoints advertised to players. If empty, local and
	// STUN-mapped addresses of Address are advertised.
	Endpoints []netip.AddrPort
	// Capacity is the maximum number of players admitted. If zero, the maximum player
	// count of the listener is used.
	Capacity int
	// Build is an optional build identifier reported to the provider.
	Build string

	// WebSocket enables the WebSocket control transport if the provider advertises it.
	// Operations fall back to HTTPS while it is unavailable.
	WebSocket bool
	// AssistedJoins lets the provider forward the offers of players that cannot be
	// admitted statelessly. It requires the WebSocket control transport.
	AssistedJoins bool
	// Diagnostics lets the provider check the connectivity of the host with single
	// exchanges on the gameplay socket, which never reach the Listener.
	Diagnostics bool
	// GameOutcomes reports that the application calls GameJoined and GameRejected for
	// admitted connections.
	GameOutcomes bool

	// Log is used for logging. It defaults to [slog.Default].
	Log *slog.Logger
	// HTTPClient is used for provider requests. Redirects are always disabled.
	HTTPClient *http.Client
}

Config configures a Provider.

type Error

type Error struct {
	// Status is the HTTP status code.
	Status int
	// Code is the machine-readable error code, if any.
	Code string
	// RetryAfter is the delay requested by the provider, if any.
	RetryAfter time.Duration
}

Error is an error returned by the provider.

func (*Error) Error

func (e *Error) Error() string

type Placement

type Placement struct {
	Region string            `json:"region"`
	Pool   string            `json:"pool"`
	Tags   map[string]string `json:"tags,omitempty"`
}

Placement selects the region and pool of an instance.

type Provider

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

Provider maintains the registration of a host with an NXS provider and admits connections routed to it. It implements nethernet.Signaling.

func New

func New(ctx context.Context, conf Config) (*Provider, error)

New registers the host with the provider, or resumes its saved registration, and binds the gameplay socket. The Provider must be closed after use.

func (*Provider) Addr

func (p *Provider) Addr() net.Addr

Addr returns the local address of the gameplay socket.

func (*Provider) Close

func (p *Provider) Close() error

Close stops accepting players, reports this to the provider and closes the gameplay socket. Established connections are closed with it.

func (*Provider) Context

func (p *Provider) Context() context.Context

Context returns a context that is canceled when the Provider is closed.

func (*Provider) Credentials

func (p *Provider) Credentials(context.Context) (*nethernet.Credentials, error)

Credentials returns nil, as no ICE servers are used.

func (*Provider) Deregister

func (p *Provider) Deregister(ctx context.Context) error

Deregister permanently ends the registration of this instance and closes the Provider, even if deregistration fails. A later Provider using the same StateDir registers as a new instance.

func (*Provider) ExtensionRequest

func (p *Provider) ExtensionRequest(ctx context.Context, namespace, operation, method string, body, v any) error

ExtensionRequest performs an operation advertised by a provider extension in discovery, such as refreshing a claim link. It is signed with the machine key. The operation URL must be on the provider origin. body may be nil, and the response is decoded into v.

func (*Provider) Extensions

func (p *Provider) Extensions() map[string]json.RawMessage

Extensions returns the optional provider metadata returned with the registration, such as a link to claim the service. Its keys are reverse-DNS namespaces.

func (*Provider) GameJoined

func (p *Provider) GameJoined(conn interface{ RemoteAddr() net.Addr })

GameJoined reports that the player of an admitted connection joined the game. It must only be called if Config.GameOutcomes is set. conn is typically a gophertunnel minecraft.Conn or a nethernet.Conn.

func (*Provider) GameRejected

func (p *Provider) GameRejected(conn interface{ RemoteAddr() net.Addr }, reason string)

GameRejected reports that the game rejected the player of an admitted connection, with a short reason code. It must only be called if Config.GameOutcomes is set.

func (*Provider) NetworkID

func (p *Provider) NetworkID() string

NetworkID returns the instance ID of the host.

func (*Provider) Notify

func (p *Provider) Notify(n nethernet.Notifier) (stop func())

Notify attaches a nethernet.Listener that admitted connections are delivered to.

func (*Provider) Pause

func (p *Provider) Pause()

Pause stops admitting players and reports this to the provider with the next heartbeat. Established connections and admissions already in progress are not affected.

func (*Provider) PongData

func (p *Provider) PongData(b []byte)

PongData updates the listing metadata reported to the provider from the RakNet-format pong data of the listener.

func (*Provider) PublicAddress

func (p *Provider) PublicAddress() string

PublicAddress returns the public address players may use to join, if the provider assigned one.

func (*Provider) Readiness

func (p *Provider) Readiness() Readiness

Readiness returns the latest readiness observation of the provider.

func (*Provider) Resume

func (p *Provider) Resume()

Resume admits players again after Pause.

func (*Provider) RotateAdmissionKey

func (p *Provider) RotateAdmissionKey() error

RotateAdmissionKey requests a replacement admission key with the next heartbeat. Older keys remain installed until the provider retires them.

func (*Provider) RotateMachineKey

func (p *Provider) RotateMachineKey(ctx context.Context) error

RotateMachineKey replaces the machine key that authenticates this instance, then retires the previous one. The replacement is saved before the provider is asked to install it.

func (*Provider) Signal

Signal always returns an error, as players are signaled by the provider.

type Readiness

type Readiness struct {
	Routable bool     `json:"routable"`
	Reasons  []string `json:"reasons"`
}

Readiness is the provider's latest observation of whether players can be routed to the host.

Directories

Path Synopsis
Package admission implements the NXS1 stateless admission carrier.
Package admission implements the NXS1 stateless admission carrier.
internal
canon
Package canon encodes the canonical JSON arrays that NXS signs and hashes.
Package canon encodes the canonical JSON arrays that NXS signs and hashes.

Jump to

Keyboard shortcuts

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