configbuilder

package
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 14, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package configbuilder holds the HTTP-free core shared by the web Config Builder (internal/api) and the terminal Config Builder (internal/configtui): talkgroup CSV sidecar IO, the RadioReference→config projection, the canonical section list + validation-error section bucketing, frequency formatting, and the AdvancedJSON field allow-list. Keeping these here means the two builders cannot disagree on behaviour.

Index

Constants

This section is empty.

Variables

View Source
var AdvancedFields = map[string][]string{
	"DeviceConfig": {
		"BlogV4", "BlogV4Lite", "IQCorrect", "IQInvert", "DCAvoid", "DCAvoidOffsetHz",
	},
	"SystemConfig": {

		"TETRAColourCode", "TETRAChannel", "TETRAChannelCoding", "TETRAClockMode",

		"LTRFCSMode", "LTRManchesterMode",

		"P25Phase1DemodMode",

		"P25Phase2TrellisMode", "P25Phase2RSMode", "P25Phase2InterleaveMode",
		"P25Phase2ScramblerMode", "P25Phase2ClockMode",

		"DMRInterleavedVoice",

		"NXDNViterbiMode", "NXDNDeviationHz",

		"EDACSBCHMode",

		"MPT1327BCHMode", "MPT1327CWSCTolerance",

		"MotorolaBCHMode",

		"DStarFECMode",
	},
}

AdvancedFields lists the config fields that the builders intentionally do NOT give a bespoke widget: they round-trip through an "Advanced (JSON)" editor (web) / a raw-JSON or generic editor (TUI). Keyed by Go struct name. This is the single definition mirrored by the web's PROTOCOL_KNOBS (Trunking.tsx) + DEVICE_ADVANCED (SDR.tsx) and verified by the schema-drift tests, so adding a protocol knob is a one-line, reviewed decision.

Functions

func DefaultConfigPath

func DefaultConfigPath() string

DefaultConfigPath picks a sensible default config.yaml location:

  1. $GOPHERTRUNK_CONFIG (the Windows installer sets this);
  2. ./config.yaml when the cwd is writable;
  3. <os.UserConfigDir()>/GopherTrunk/config.yaml otherwise.

func ExpandConfigPath

func ExpandConfigPath(p string) string

ExpandConfigPath resolves ~, $VAR/${VAR}, and %VAR% references in a config-file path (relocated from the old CLI wizard so the terminal Config Builder accepts the same operator-typed paths). Unknown vars are preserved. It delegates to pathutil.Expand, the shared leaf helper the daemon's config loader uses for the same resolution.

func FieldMetas

func FieldMetas() map[string]FieldMeta

FieldMetas returns the whole registry (the web builder serves it over /api/v1/config/fieldmeta). The returned map is the live registry; callers must not mutate it.

func HzToDisplay

func HzToDisplay(hz uint32) string

HzToDisplay renders an integer-Hz value as trimmed MHz (e.g. 851037500 → "851.0375 MHz", 852000000 → "852 MHz"). Mirrors hzToDisplay in web/configbuilder/src/components/fields.tsx.

func IsAdvanced

func IsAdvanced(structName, field string) bool

IsAdvanced reports whether structName.field is in the AdvancedFields set.

func ParseFreqList

func ParseFreqList(text string) []uint32

ParseFreqList parses a comma/semicolon/newline-separated list of frequencies, each MHz (values < 10000) or Hz, into integer Hz. Mirrors parseFreqList in web/configbuilder/src/components/fields.tsx. Used by the freq-list widget and, taking element [0], the single-Hz widget.

func ParseHz

func ParseHz(text string) uint32

ParseHz parses a single frequency (MHz or Hz) to integer Hz, returning 0 when nothing parses — the single-field analogue of ParseFreqList.

func SectionOf

func SectionOf(msg string) string

SectionOf extracts the top-level config section key from a validation error message (everything before the first '.', ':', '[', or ' ' in the leading token). E.g. "trunking.systems[0]: name required" → "trunking".

func WriteTalkgroupCSV

func WriteTalkgroupCSV(path string, rows []TalkgroupCSVRow) error

WriteTalkgroupCSV writes a Trunk Recorder–style talkgroup CSV that trunking.TalkGroup loads (header columns it recognises).

Types

type FieldMeta

type FieldMeta struct {
	Label    string         `json:"label,omitempty"`
	Help     string         `json:"help,omitempty"`
	Options  []SelectOption `json:"options,omitempty"`
	Hz       bool           `json:"hz,omitempty"`
	FreqList bool           `json:"freqList,omitempty"`
}

FieldMeta is the shared, per-field metadata BOTH Config Builders consume: the terminal builder (internal/configtui) reads it directly; the web builder reads it over GET /api/v1/config/fieldmeta. It is keyed "StructName.FieldName" in the registry below.

  • Label overrides the humanized Go field name (empty ⇒ humanize).
  • Help is the comprehensive per-field help shown under the focused row (TUI) / beside the widget (web). Every config leaf has one; the fieldmeta coverage test fails if a new field lands without it, so a schema change can't ship without updating the shared help (and thus both editors).
  • Options turns a string/number into a select with these choices.
  • Hz renders a uint/int as an MHz/Hz frequency widget.
  • FreqList renders a []uint32 as a frequency-list widget.

func FieldMetaFor

func FieldMetaFor(structName, field string) FieldMeta

FieldMetaFor returns the shared metadata for structName.field. An absent entry yields the zero FieldMeta (humanized label, plain widget).

type SectionMeta

type SectionMeta struct {
	Key          string
	CfgField     string
	Label        string
	Instructions string
	DocTitle     string
	DocURL       string
}

SectionMeta names a top-level config section and carries its builder help: Key is the snake/lowercase id (nav, docs, validator buckets); CfgField is the Go config.Config field name; Label is the display name; Instructions is the section help text; DocTitle/DocURL are the "open docs" link. This is the Go source of truth that BOTH the web Config Builder (via /api/v1/config/docs) and the terminal builder consume, so their section help stays identical.

func SectionByKey

func SectionByKey(key string) (SectionMeta, bool)

SectionByKey returns the section metadata for a snake/lowercase key.

func Sections

func Sections() []SectionMeta

Sections returns the canonical ordered section list (matching the web builder's order) with help + docs.

type SelectOption

type SelectOption struct {
	Value string `json:"value"`
	Label string `json:"label"`
}

SelectOption is one choice in a select / dropdown field (stored value + display label).

type TalkgroupCSVRow

type TalkgroupCSVRow struct {
	Decimal     uint32 `json:"decimal"`
	AlphaTag    string `json:"alpha_tag,omitempty"`
	Description string `json:"description,omitempty"`
	Tag         string `json:"tag,omitempty"`
	Group       string `json:"group,omitempty"`
	Mode        string `json:"mode,omitempty"`
}

TalkgroupCSVRow is one row of a Trunk Recorder–style talkgroup CSV sidecar. The json tags are the wire shape the web builder exchanges, so internal/api aliases this type to keep its responses byte-identical.

func RRToSystemConfig

func RRToSystemConfig(full radioreference.FullSystem) (config.SystemConfig, []TalkgroupCSVRow)

RRToSystemConfig projects a RadioReference FullSystem into a config-ready SystemConfig (control channels collapsed + de-duplicated across sites) plus the talkgroup rows for its CSV sidecar. Shared by the web builder's /rr/system handler and the TUI's RadioReference import.

func ReadTalkgroupCSV

func ReadTalkgroupCSV(path string) ([]TalkgroupCSVRow, error)

ReadTalkgroupCSV parses a Trunk Recorder–style talkgroup CSV into rows, mapping columns by (case/space-insensitive) header name so column order and extra columns are tolerated. Rows without a numeric Decimal are skipped.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL