Let the config choose protocol 2 or 3, and fall back for one session only.
The default stays v2. A reflector that refuses that version and names the other gets one session of it, then the station announces the configured protocol again. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+72
-6
@@ -20,6 +20,7 @@ type loaded struct {
|
||||
callsign string
|
||||
authKey string
|
||||
talkGroup int
|
||||
protocolMajor uint16
|
||||
certificateDir string
|
||||
certFatal string
|
||||
enableLogging bool
|
||||
@@ -33,6 +34,7 @@ type fileShape struct {
|
||||
Callsign jsontext.Value `json:"callsign"`
|
||||
AuthKey jsontext.Value `json:"authKey"`
|
||||
TalkGroup jsontext.Value `json:"talkGroup"`
|
||||
Protocol jsontext.Value `json:"protocol"`
|
||||
CertificateDir jsontext.Value `json:"certificateDir"`
|
||||
EnableLogging jsontext.Value `json:"enableLogging"`
|
||||
LogFile jsontext.Value `json:"logFile"`
|
||||
@@ -44,6 +46,7 @@ type templateFile struct {
|
||||
Callsign string `json:"callsign"`
|
||||
AuthKey string `json:"authKey"`
|
||||
TalkGroup int `json:"talkGroup"`
|
||||
Protocol string `json:"protocol"`
|
||||
CertificateDir string `json:"certificateDir"`
|
||||
EnableLogging bool `json:"enableLogging"`
|
||||
LogFile string `json:"logFile"`
|
||||
@@ -76,13 +79,14 @@ func loadConfig(path string) (configLoad, error) {
|
||||
return parseConfig(path, body, true)
|
||||
}
|
||||
|
||||
// ConfigForm is the eight fields the Config window edits.
|
||||
// ConfigForm is the fields the Config window edits.
|
||||
type ConfigForm struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Callsign string `json:"callsign"`
|
||||
AuthKey string `json:"authKey"`
|
||||
TalkGroup int `json:"talkGroup"`
|
||||
Protocol string `json:"protocol"`
|
||||
CertificateDir string `json:"certificateDir"`
|
||||
EnableLogging bool `json:"enableLogging"`
|
||||
LogFile string `json:"logFile"`
|
||||
@@ -101,7 +105,7 @@ func templateForm() (ConfigForm, error) {
|
||||
if err != nil {
|
||||
return ConfigForm{}, err
|
||||
}
|
||||
return ConfigForm{CertificateDir: "./funknetz", LogFile: logFile}, nil
|
||||
return ConfigForm{Protocol: "v2", CertificateDir: "./funknetz", LogFile: logFile}, nil
|
||||
}
|
||||
|
||||
func parseConfig(path string, body []byte, rewrite bool) (configLoad, error) {
|
||||
@@ -114,7 +118,8 @@ func parseConfig(path string, body []byte, rewrite bool) (configLoad, error) {
|
||||
return configLoad{form: form, detail: fmt.Errorf("the file could not be read: %w", err).Error()}, nil
|
||||
}
|
||||
certBad := present(shape.CertificateDir) && shape.CertificateDir.Kind() != jsontext.KindString
|
||||
if block, notice := blockedLog(shape); block || certBad {
|
||||
protoBad := present(shape.Protocol) && shape.Protocol.Kind() != jsontext.KindString
|
||||
if block, notice := blockedLog(shape); block || certBad || protoBad {
|
||||
cfg, err := parseOperational(shape)
|
||||
if err != nil {
|
||||
return refused(shape, err)
|
||||
@@ -125,7 +130,7 @@ func parseConfig(path string, body []byte, rewrite bool) (configLoad, error) {
|
||||
}
|
||||
return finish(shape, applyCertificate(cfg, shape, path))
|
||||
}
|
||||
if missingCertificate(shape) || missingLog(shape) {
|
||||
if missingCertificate(shape) || missingLog(shape) || missingProtocol(shape) {
|
||||
if !operationalKindsOK(shape) {
|
||||
_, err := parseOperational(shape)
|
||||
if err != nil {
|
||||
@@ -165,7 +170,7 @@ func refused(shape fileShape, cause error) (configLoad, error) {
|
||||
func formFromShape(shape fileShape) ConfigForm {
|
||||
fallback, err := templateForm()
|
||||
if err != nil {
|
||||
fallback = ConfigForm{CertificateDir: "./funknetz"}
|
||||
fallback = ConfigForm{Protocol: "v2", CertificateDir: "./funknetz"}
|
||||
}
|
||||
return mergeSalvage(shape, fallback)
|
||||
}
|
||||
@@ -192,6 +197,11 @@ func mergeSalvage(shape fileShape, fallback ConfigForm) ConfigForm {
|
||||
fallback.TalkGroup = n
|
||||
}
|
||||
}
|
||||
if s, err := stringField("protocol", shape.Protocol); err == nil && present(shape.Protocol) {
|
||||
if label, ok := protocolLabel(s); ok {
|
||||
fallback.Protocol = label
|
||||
}
|
||||
}
|
||||
if s, err := stringField("certificateDir", shape.CertificateDir); err == nil && present(shape.CertificateDir) {
|
||||
fallback.CertificateDir = s
|
||||
}
|
||||
@@ -225,6 +235,10 @@ func parseOperational(shape fileShape) (loaded, error) {
|
||||
if err != nil {
|
||||
return loaded{}, err
|
||||
}
|
||||
protocolMajor, err := protocolField(shape.Protocol)
|
||||
if err != nil {
|
||||
return loaded{}, err
|
||||
}
|
||||
|
||||
host = strings.TrimSpace(host)
|
||||
if host == "" {
|
||||
@@ -237,7 +251,45 @@ func parseOperational(shape fileShape) (loaded, error) {
|
||||
if !callsignPattern.MatchString(call) {
|
||||
return loaded{}, fmt.Errorf("callsign is invalid")
|
||||
}
|
||||
return loaded{host: host, port: port, callsign: call, authKey: key, talkGroup: tg}, nil
|
||||
return loaded{host: host, port: port, callsign: call, authKey: key, talkGroup: tg, protocolMajor: protocolMajor}, nil
|
||||
}
|
||||
|
||||
func protocolField(v jsontext.Value) (uint16, error) {
|
||||
if !present(v) {
|
||||
return 2, nil
|
||||
}
|
||||
s, err := stringField("protocol", v)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if strings.TrimSpace(s) == "" {
|
||||
return 2, nil
|
||||
}
|
||||
if _, ok := protocolLabel(s); !ok {
|
||||
return 0, fmt.Errorf("protocol is invalid")
|
||||
}
|
||||
if strings.TrimSpace(s) == "v3" {
|
||||
return 3, nil
|
||||
}
|
||||
return 2, nil
|
||||
}
|
||||
|
||||
func protocolLabel(s string) (string, bool) {
|
||||
switch strings.TrimSpace(s) {
|
||||
case "v2":
|
||||
return "v2", true
|
||||
case "v3":
|
||||
return "v3", true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
func protocolName(major uint16) string {
|
||||
if major == 3 {
|
||||
return "v3"
|
||||
}
|
||||
return "v2"
|
||||
}
|
||||
|
||||
func stringField(name string, v jsontext.Value) (string, error) {
|
||||
@@ -306,6 +358,14 @@ func missingCertificate(shape fileShape) bool {
|
||||
return !present(shape.CertificateDir)
|
||||
}
|
||||
|
||||
func missingProtocol(shape fileShape) bool {
|
||||
if !present(shape.Protocol) {
|
||||
return true
|
||||
}
|
||||
s, err := stringField("protocol", shape.Protocol)
|
||||
return err == nil && strings.TrimSpace(s) == ""
|
||||
}
|
||||
|
||||
func operationalKindsOK(shape fileShape) bool {
|
||||
if present(shape.Host) && shape.Host.Kind() != jsontext.KindString {
|
||||
return false
|
||||
@@ -322,6 +382,9 @@ func operationalKindsOK(shape fileShape) bool {
|
||||
if present(shape.TalkGroup) && shape.TalkGroup.Kind() != jsontext.KindNumber {
|
||||
return false
|
||||
}
|
||||
if present(shape.Protocol) && shape.Protocol.Kind() != jsontext.KindString {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -348,6 +411,9 @@ func withLogDefaults(shape fileShape) (fileShape, error) {
|
||||
shape.Callsign = rawOr(shape.Callsign, `""`)
|
||||
shape.AuthKey = rawOr(shape.AuthKey, `""`)
|
||||
shape.TalkGroup = rawOr(shape.TalkGroup, "0")
|
||||
if missingProtocol(shape) {
|
||||
shape.Protocol = jsontext.Value(`"v2"`)
|
||||
}
|
||||
shape.CertificateDir = rawOr(shape.CertificateDir, `"./funknetz"`)
|
||||
shape.EnableLogging = rawOr(shape.EnableLogging, "false")
|
||||
if !present(shape.LogFile) {
|
||||
|
||||
Reference in New Issue
Block a user