refactor(embeddednats): ServerConfig with optional TLS

Collapses Start/StartHost/StartHostAuth onto StartServer(ServerConfig) so
auth and a TLS config can be set without growing the parameter list further.
When TLS is set the server presents the certificate and requires TLS on the
data plane; the wrappers preserve the existing no-auth/no-TLS behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-07 12:44:13 +02:00
parent 217daae472
commit 6d3d6d2562
+39 -20
View File
@@ -6,22 +6,33 @@
package embeddednats package embeddednats
import ( import (
"crypto/tls"
"fmt" "fmt"
"time" "time"
server "github.com/nats-io/nats-server/v2/server" server "github.com/nats-io/nats-server/v2/server"
) )
// Start launches an embedded nats-server with JetStream enabled, listening on // ServerConfig is the full set of knobs for the embedded NATS server. The zero
// the given port and persisting JetStream state under storeDir. The listen host // value (empty StoreDir aside) yields a dev-friendly server: JetStream on, bound
// is left at the nats-server default ("0.0.0.0", all interfaces). It blocks // to all interfaces, no client auth, no TLS. Secured deployments set Auth and
// until the server is ready to accept connections (up to 5s) and returns the // TLS; tests set Host to loopback and a free Port.
// running server. The caller is responsible for calling Shutdown on it. type ServerConfig struct {
// StoreDir string // JetStream store directory
// Start is a thin backward-compatible wrapper over StartHost; callers that need Host string // bind interface; "" = nats-server default ("0.0.0.0")
// to control the bind interface (loopback vs LAN) should use StartHost directly. Port int // listen port
// Auth, when non-nil, is installed as CustomClientAuthentication so the data
// plane only accepts approved clients (nkey signature + bus allowlist).
Auth server.Authentication
// TLS, when non-nil, makes the server present a certificate and require TLS
// on the data plane. Clients must trust the issuing CA (see busauth).
TLS *tls.Config
}
// Start is a thin backward-compatible wrapper: embedded JetStream server on the
// default interface, no auth, no TLS.
func Start(storeDir string, port int) (*server.Server, error) { func Start(storeDir string, port int) (*server.Server, error) {
return StartHost(storeDir, "", port) return StartServer(ServerConfig{StoreDir: storeDir, Port: port})
} }
// StartHost is Start with explicit control over the bind interface. host selects // StartHost is Start with explicit control over the bind interface. host selects
@@ -30,34 +41,42 @@ func Start(storeDir string, port int) (*server.Server, error) {
// to expose it to the LAN so remote peers (phones, other PCs) can connect. An // to expose it to the LAN so remote peers (phones, other PCs) can connect. An
// empty host falls back to the nats-server default ("0.0.0.0", all interfaces). // empty host falls back to the nats-server default ("0.0.0.0", all interfaces).
func StartHost(storeDir, host string, port int) (*server.Server, error) { func StartHost(storeDir, host string, port int) (*server.Server, error) {
return StartHostAuth(storeDir, host, port, nil) return StartServer(ServerConfig{StoreDir: storeDir, Host: host, Port: port})
} }
// StartHostAuth is StartHost with an optional custom client authenticator. When // StartHostAuth is StartHost with an optional custom client authenticator. When
// auth is non-nil it is installed as Options.CustomClientAuthentication, so the // auth is non-nil only clients the authenticator approves may connect; when nil
// data plane only accepts clients the authenticator approves (nkey signature + // the server accepts any client (legacy, network-trusted behavior).
// bus allowlist). When auth is nil the server accepts any client (the legacy,
// network-trusted behavior) — used by dev stacks and tests that have not enabled
// bus auth.
func StartHostAuth(storeDir, host string, port int, auth server.Authentication) (*server.Server, error) { func StartHostAuth(storeDir, host string, port int, auth server.Authentication) (*server.Server, error) {
return StartServer(ServerConfig{StoreDir: storeDir, Host: host, Port: port, Auth: auth})
}
// StartServer launches an embedded nats-server with JetStream from cfg. It
// blocks until the server is ready to accept connections (up to 5s) and returns
// the running server; the caller must Shutdown it.
func StartServer(cfg ServerConfig) (*server.Server, error) {
opts := &server.Options{ opts := &server.Options{
JetStream: true, JetStream: true,
StoreDir: storeDir, StoreDir: cfg.StoreDir,
Host: host, Host: cfg.Host,
Port: port, Port: cfg.Port,
DontListen: false, DontListen: false,
// Keep the embedded server quiet by default; the host app logs the URLs. // Keep the embedded server quiet by default; the host app logs the URLs.
NoLog: true, NoLog: true,
NoSigs: true, NoSigs: true,
} }
if auth != nil { if cfg.Auth != nil {
opts.CustomClientAuthentication = auth opts.CustomClientAuthentication = cfg.Auth
// A CustomClientAuthentication alone does not make the server advertise a // A CustomClientAuthentication alone does not make the server advertise a
// nonce in its INFO line, and nats.go refuses to connect with an nkey to a // nonce in its INFO line, and nats.go refuses to connect with an nkey to a
// server that does not ("nkeys not supported by the server"). Forcing the // server that does not ("nkeys not supported by the server"). Forcing the
// nonce makes nkey clients sign the challenge our authenticator verifies. // nonce makes nkey clients sign the challenge our authenticator verifies.
opts.AlwaysEnableNonce = true opts.AlwaysEnableNonce = true
} }
if cfg.TLS != nil {
opts.TLSConfig = cfg.TLS
opts.TLS = true
}
ns, err := server.NewServer(opts) ns, err := server.NewServer(opts)
if err != nil { if err != nil {