Add svxdr: the live-data backend (nodelist + proxy; astmeta/xlink optional), config example, systemd unit, INSTALL section 9
svxdr sources from the internal repo with AGPL headers; install/svxdr.json.example is a plain-reflector layout (reflector 8099 -> proxy 8090 -> nodelist 8098) with CHANGEME secrets and no site values. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
// svxdr — live-data daemon for SvxPortal (nodelist + proxy + astmeta + xlink)
|
||||
// Copyright (C) 2026 SA7AUX (Björn)
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Affero General Public License as published by the Free
|
||||
// Software Foundation, either version 3 of the License, or (at your option) any
|
||||
// later version. See the LICENSE file for details.
|
||||
|
||||
package nodelist
|
||||
|
||||
// nodes.json — shared bridge map (see svx-web/nodes.README.md). nodelist takes
|
||||
// the friendly reflector names (System) and the Location format strings from it,
|
||||
// so the Location column ("{system} via {node} / {talker}") is driven by the
|
||||
// same one file that configures astmeta and Asterisk. Merged ON TOP of the
|
||||
// existing lastheard.json, so a box with only lastheard.json is unchanged.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type nodesFileNL struct {
|
||||
Lastheard struct {
|
||||
BridgeLocationFormat string `json:"bridge_location_format"`
|
||||
BridgeLocationFormatNoSystem string `json:"bridge_location_format_no_system"`
|
||||
} `json:"lastheard"`
|
||||
Nodes []struct {
|
||||
Allstar int `json:"allstar"`
|
||||
System string `json:"system"`
|
||||
Via string `json:"via"`
|
||||
Callsign string `json:"callsign"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
} `json:"nodes"`
|
||||
}
|
||||
|
||||
// applyNodesRenderConfig merges nodes.json's reflector names + Location formats
|
||||
// over cfg. A missing/invalid file is a no-op (cfg keeps the lastheard.json /
|
||||
// default values). ReflectorNames is keyed the way bridgeIdentity looks it up:
|
||||
// by the bridge label (via/callsign) and, as a fallback, the far AllStar node.
|
||||
func applyNodesRenderConfig(cfg *lastheardRenderCfg, path string) {
|
||||
b, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var nf nodesFileNL
|
||||
if json.Unmarshal(b, &nf) != nil {
|
||||
return
|
||||
}
|
||||
if s := strings.TrimSpace(nf.Lastheard.BridgeLocationFormat); s != "" {
|
||||
cfg.BridgeLocationFormat = s
|
||||
}
|
||||
if s := strings.TrimSpace(nf.Lastheard.BridgeLocationFormatNoSystem); s != "" {
|
||||
cfg.BridgeLocationFormatNoSystem = s
|
||||
}
|
||||
if cfg.ReflectorNames == nil {
|
||||
cfg.ReflectorNames = map[string]string{}
|
||||
}
|
||||
for _, e := range nf.Nodes {
|
||||
if (e.Enabled != nil && !*e.Enabled) || e.System == "" {
|
||||
continue
|
||||
}
|
||||
if e.Via != "" {
|
||||
cfg.ReflectorNames[e.Via] = e.System
|
||||
}
|
||||
if e.Callsign != "" {
|
||||
cfg.ReflectorNames[e.Callsign] = e.System
|
||||
}
|
||||
if e.Allstar != 0 {
|
||||
cfg.ReflectorNames[strconv.Itoa(e.Allstar)] = e.System
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nodesJSONPath returns the nodes.json path (NODES_JSON env, default /etc/nodes.json).
|
||||
func nodesJSONPath() string {
|
||||
if p := os.Getenv("NODES_JSON"); p != "" {
|
||||
return p
|
||||
}
|
||||
return "/etc/nodes.json"
|
||||
}
|
||||
Reference in New Issue
Block a user