@@ -16,18 +16,23 @@ import (
1616)
1717
1818const (
19- envDB = "PSSTD_DB"
20- envHTTP = "PSSTD_HTTP"
21- envGossip = "PSSTD_GOSSIP"
22- envSeeds = "PSSTD_SEEDS"
23- envHTTPAd = "PSSTD_ADVERTISE_HTTP"
24- envWeb = "PSSTD_WEB" // "true" to enable HTTP, default true
25- gossipPort = 7946
26- httpPort = 8080
19+ envDB = "PSSTD_DB"
20+ envHTTP = "PSSTD_HTTP"
21+ envGossip = "PSSTD_GOSSIP"
22+ envSeeds = "PSSTD_SEEDS"
23+ envHTTPAd = "PSSTD_ADVERTISE_HTTP"
24+ envWeb = "PSSTD_WEB" // "true" to enable HTTP, default true
25+ envNodeName = "PSSTD_NODE_NAME"
26+ gossipPort = 7946
27+ httpPort = 8080
2728)
2829
2930func main () {
3031 hostname , _ := os .Hostname ()
32+ nodeName , err := nodeNameFromEnv (hostname )
33+ if err != nil {
34+ log .Fatalf ("node name: %v" , err )
35+ }
3136
3237 dbPath := envOr (envDB , "./data" )
3338 httpAddr := envOr (envHTTP , fmt .Sprintf (":%d" , httpPort ))
@@ -47,7 +52,7 @@ func main() {
4752 if err != nil {
4853 if pebbleLockHeld (err ) {
4954 log .Printf ("psstd already appears to own %s; starting terminal mirror instead" , dbPath )
50- runTerminalMirror (hostname , gossipAddr , seeds )
55+ runTerminalMirror (nodeName , gossipAddr , seeds )
5156 return
5257 }
5358 log .Fatalf ("pebble open: %v" , err )
@@ -65,7 +70,7 @@ func main() {
6570 delegate := newKVDelegate (db , appVersion )
6671
6772 cfg := memberlist .DefaultLANConfig ()
68- cfg .Name = hostname
73+ cfg .Name = nodeName
6974 cfg .BindAddr , cfg .BindPort = splitHostPort (gossipAddr )
7075 cfg .Delegate = delegate
7176 cfg .Events = newEventDelegate (db , appVersion )
@@ -79,7 +84,7 @@ func main() {
7984 }
8085 db = nil
8186 log .Printf ("psstd already appears to be listening on %s; starting terminal mirror instead" , gossipAddr )
82- runTerminalMirror (hostname , gossipAddr , seeds )
87+ runTerminalMirror (nodeName , gossipAddr , seeds )
8388 return
8489 }
8590 log .Fatalf ("memberlist create: %v" , err )
@@ -88,12 +93,23 @@ func main() {
8893
8994 // ── Discovery ────────────────────────────────────────────────────────────
9095 // 1. Register ourselves via mDNS so peers can find us on LAN
91- stopMDNS := registerMDNS (hostname , cfg .BindPort )
96+ stopMDNS := registerMDNS (nodeName , cfg .BindPort )
9297 defer stopMDNS ()
9398
9499 // 2. Scan for existing peers (mDNS + any explicit seeds)
95100 discovered := discoverPeers ()
96101 allSeeds := append (seeds , discovered ... )
102+ logStartupConfig (startupConfig {
103+ NodeName : nodeName ,
104+ DBPath : dbPath ,
105+ HTTPAddr : httpAddr ,
106+ WebURL : webURL ,
107+ GossipAddr : gossipAddr ,
108+ WebEnabled : webEnabled ,
109+ Version : appVersion ,
110+ SeedCount : len (seeds ),
111+ MDNSCount : len (discovered ),
112+ })
97113 if len (allSeeds ) > 0 {
98114 if n , err := list .Join (allSeeds ); err != nil {
99115 log .Printf ("join warning (joined %d): %v" , n , err )
@@ -105,22 +121,37 @@ func main() {
105121 }
106122
107123 // ── Stats heartbeat ─────────────────────────────────────────────────────
108- go statsLoop (hostname , webURL , appVersion , db , delegate )
124+ go statsLoop (nodeName , webURL , appVersion , db , delegate )
109125
110126 // ── HTTP ─────────────────────────────────────────────────────────────────
111127 if webEnabled {
112128 mux := http .NewServeMux ()
113- mux .HandleFunc ("/" , makeHandler (db , hostname ))
114- log .Printf ("psstd version=%s node=%s http=%s advertise=%s gossip=%s web=true" , appVersion , hostname , httpAddr , webURL , gossipAddr )
129+ mux .HandleFunc ("/" , makeHandler (db , nodeName ))
115130 if err := http .ListenAndServe (httpAddr , mux ); err != nil {
116131 log .Fatalf ("http: %v" , err )
117132 }
118133 } else {
119- log .Printf ("psstd version=%s node=%s gossip=%s web=false" , appVersion , hostname , gossipAddr )
120134 select {} // block forever
121135 }
122136}
123137
138+ type startupConfig struct {
139+ NodeName string
140+ DBPath string
141+ HTTPAddr string
142+ WebURL string
143+ GossipAddr string
144+ WebEnabled bool
145+ Version string
146+ SeedCount int
147+ MDNSCount int
148+ }
149+
150+ func logStartupConfig (cfg startupConfig ) {
151+ log .Printf ("psstd startup: version=%s node=%s db=%s web=%t http=%s advertise=%s gossip=%s seeds=%d mdns=%d" ,
152+ cfg .Version , cfg .NodeName , cfg .DBPath , cfg .WebEnabled , cfg .HTTPAddr , cfg .WebURL , cfg .GossipAddr , cfg .SeedCount , cfg .MDNSCount )
153+ }
154+
124155func pebbleLockHeld (err error ) bool {
125156 msg := strings .ToLower (err .Error ())
126157 return strings .Contains (msg , "lock" ) &&
@@ -255,6 +286,23 @@ func envOr(key, def string) string {
255286 return def
256287}
257288
289+ func nodeNameFromEnv (hostname string ) (string , error ) {
290+ override , ok := os .LookupEnv (envNodeName )
291+ if ! ok || override == "" {
292+ if strings .TrimSpace (hostname ) == "" {
293+ return "" , fmt .Errorf ("hostname is empty; set %s" , envNodeName )
294+ }
295+ return hostname , nil
296+ }
297+ if strings .TrimSpace (override ) != override || override == "" {
298+ return "" , fmt .Errorf ("%s must not be empty or have leading/trailing whitespace" , envNodeName )
299+ }
300+ if strings .ContainsAny (override , " \t \r \n " ) {
301+ return "" , fmt .Errorf ("%s must not contain whitespace" , envNodeName )
302+ }
303+ return override , nil
304+ }
305+
258306func splitCSV (s string ) []string {
259307 var out []string
260308 for _ , p := range strings .Split (s , "," ) {
0 commit comments