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
import (
"crypto/tls"
"fmt"
"time"
server "github.com/nats-io/nats-server/v2/server"
)
// Start launches an embedded nats-server with JetStream enabled, listening on
// the given port and persisting JetStream state under storeDir. The listen host
// is left at the nats-server default ("0.0.0.0", all interfaces). It blocks
// until the server is ready to accept connections (up to 5s) and returns the
// running server. The caller is responsible for calling Shutdown on it.
//
// Start is a thin backward-compatible wrapper over StartHost; callers that need
// to control the bind interface (loopback vs LAN) should use StartHost directly.
// ServerConfig is the full set of knobs for the embedded NATS server. The zero
// value (empty StoreDir aside) yields a dev-friendly server: JetStream on, bound
// to all interfaces, no client auth, no TLS. Secured deployments set Auth and
// TLS; tests set Host to loopback and a free Port.
type ServerConfig struct {
StoreDir string // JetStream store directory
Host string // bind interface; "" = nats-server default ("0.0.0.0")
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) {
return StartHost(storeDir, "", port)
return StartServer(ServerConfig{StoreDir: storeDir, Port: port})
}
// 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
// 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) {
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
// auth is non-nil it is installed as Options.CustomClientAuthentication, so the
// data plane only accepts clients the authenticator approves (nkey signature +
// 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.
// auth is non-nil only clients the authenticator approves may connect; when nil
// the server accepts any client (legacy, network-trusted behavior).
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{
JetStream: true,
StoreDir: storeDir,
Host: host,
Port: port,
StoreDir: cfg.StoreDir,
Host: cfg.Host,
Port: cfg.Port,
DontListen: false,
// Keep the embedded server quiet by default; the host app logs the URLs.
NoLog: true,
NoSigs: true,
}
if auth != nil {
opts.CustomClientAuthentication = auth
if cfg.Auth != nil {
opts.CustomClientAuthentication = cfg.Auth
// 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
// server that does not ("nkeys not supported by the server"). Forcing the
// nonce makes nkey clients sign the challenge our authenticator verifies.
opts.AlwaysEnableNonce = true
}
if cfg.TLS != nil {
opts.TLSConfig = cfg.TLS
opts.TLS = true
}
ns, err := server.NewServer(opts)
if err != nil {