|
|
|
@@ -14,6 +14,16 @@ type Server struct { |
|
|
|
cfg config.Config |
|
|
|
} |
|
|
|
|
|
|
|
type ConfigPatch struct { |
|
|
|
FrequencyMHz *float64 `json:"frequencyMHz,omitempty"` |
|
|
|
OutputDrive *float64 `json:"outputDrive,omitempty"` |
|
|
|
ToneLeftHz *float64 `json:"toneLeftHz,omitempty"` |
|
|
|
ToneRightHz *float64 `json:"toneRightHz,omitempty"` |
|
|
|
ToneAmplitude *float64 `json:"toneAmplitude,omitempty"` |
|
|
|
PS *string `json:"ps,omitempty"` |
|
|
|
RadioText *string `json:"radioText,omitempty"` |
|
|
|
} |
|
|
|
|
|
|
|
func NewServer(cfg config.Config) *Server { return &Server{cfg: cfg} } |
|
|
|
|
|
|
|
func (s *Server) Handler() http.Handler { |
|
|
|
@@ -21,6 +31,7 @@ func (s *Server) Handler() http.Handler { |
|
|
|
mux.HandleFunc("/healthz", s.handleHealth) |
|
|
|
mux.HandleFunc("/status", s.handleStatus) |
|
|
|
mux.HandleFunc("/dry-run", s.handleDryRun) |
|
|
|
mux.HandleFunc("/config", s.handleConfig) |
|
|
|
return mux |
|
|
|
} |
|
|
|
|
|
|
|
@@ -41,6 +52,8 @@ func (s *Server) handleStatus(w http.ResponseWriter, _ *http.Request) { |
|
|
|
"frequencyMHz": cfg.FM.FrequencyMHz, |
|
|
|
"stereoEnabled": cfg.FM.StereoEnabled, |
|
|
|
"rdsEnabled": cfg.RDS.Enabled, |
|
|
|
"toneLeftHz": cfg.Audio.ToneLeftHz, |
|
|
|
"toneRightHz": cfg.Audio.ToneRightHz, |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
@@ -52,3 +65,56 @@ func (s *Server) handleDryRun(w http.ResponseWriter, _ *http.Request) { |
|
|
|
w.Header().Set("Content-Type", "application/json") |
|
|
|
_ = json.NewEncoder(w).Encode(drypkg.Generate(cfg)) |
|
|
|
} |
|
|
|
|
|
|
|
func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) { |
|
|
|
switch r.Method { |
|
|
|
case http.MethodGet: |
|
|
|
s.mu.RLock() |
|
|
|
cfg := s.cfg |
|
|
|
s.mu.RUnlock() |
|
|
|
w.Header().Set("Content-Type", "application/json") |
|
|
|
_ = json.NewEncoder(w).Encode(cfg) |
|
|
|
case http.MethodPost: |
|
|
|
var patch ConfigPatch |
|
|
|
if err := json.NewDecoder(r.Body).Decode(&patch); err != nil { |
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
s.mu.Lock() |
|
|
|
next := s.cfg |
|
|
|
if patch.FrequencyMHz != nil { |
|
|
|
next.FM.FrequencyMHz = *patch.FrequencyMHz |
|
|
|
} |
|
|
|
if patch.OutputDrive != nil { |
|
|
|
next.FM.OutputDrive = *patch.OutputDrive |
|
|
|
} |
|
|
|
if patch.ToneLeftHz != nil { |
|
|
|
next.Audio.ToneLeftHz = *patch.ToneLeftHz |
|
|
|
} |
|
|
|
if patch.ToneRightHz != nil { |
|
|
|
next.Audio.ToneRightHz = *patch.ToneRightHz |
|
|
|
} |
|
|
|
if patch.ToneAmplitude != nil { |
|
|
|
next.Audio.ToneAmplitude = *patch.ToneAmplitude |
|
|
|
} |
|
|
|
if patch.PS != nil { |
|
|
|
next.RDS.PS = *patch.PS |
|
|
|
} |
|
|
|
if patch.RadioText != nil { |
|
|
|
next.RDS.RadioText = *patch.RadioText |
|
|
|
} |
|
|
|
if err := next.Validate(); err != nil { |
|
|
|
s.mu.Unlock() |
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest) |
|
|
|
return |
|
|
|
} |
|
|
|
s.cfg = next |
|
|
|
s.mu.Unlock() |
|
|
|
|
|
|
|
w.Header().Set("Content-Type", "application/json") |
|
|
|
_ = json.NewEncoder(w).Encode(map[string]any{"ok": true}) |
|
|
|
default: |
|
|
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed) |
|
|
|
} |
|
|
|
} |