Add HTTP API endpoint for config export

This commit is contained in:
Ian Gulliver
2026-01-30 11:45:09 -08:00
parent fd0d482380
commit 3018c75fa2
2 changed files with 38 additions and 13 deletions

View File

@@ -18,8 +18,8 @@ const (
// Universe represents a DMX universe with its protocol // Universe represents a DMX universe with its protocol
type Universe struct { type Universe struct {
Protocol Protocol Protocol Protocol `json:"protocol"`
Number uint16 Number uint16 `json:"number"`
} }
func NewUniverse(proto Protocol, num any) (Universe, error) { func NewUniverse(proto Protocol, num any) (Universe, error) {
@@ -104,27 +104,27 @@ func makeUniverse(proto Protocol, n uint16) (Universe, error) {
// Config represents the application configuration // Config represents the application configuration
type Config struct { type Config struct {
Targets []Target `toml:"target"` Targets []Target `toml:"target" json:"targets"`
Mappings []Mapping `toml:"mapping"` Mappings []Mapping `toml:"mapping" json:"mappings"`
} }
// Target represents a target address for an output universe // Target represents a target address for an output universe
type Target struct { type Target struct {
Universe Universe `toml:"universe"` Universe Universe `toml:"universe" json:"universe"`
Address string `toml:"address"` Address string `toml:"address" json:"address"`
} }
// Mapping represents a single channel mapping rule // Mapping represents a single channel mapping rule
type Mapping struct { type Mapping struct {
From FromAddr `toml:"from"` From FromAddr `toml:"from" json:"from"`
To ToAddr `toml:"to"` To ToAddr `toml:"to" json:"to"`
} }
// FromAddr represents a source universe address with channel range // FromAddr represents a source universe address with channel range
type FromAddr struct { type FromAddr struct {
Universe Universe Universe Universe `json:"universe"`
ChannelStart int // 1-indexed ChannelStart int `json:"channel_start"` // 1-indexed
ChannelEnd int // 1-indexed ChannelEnd int `json:"channel_end"` // 1-indexed
} }
func (a *FromAddr) UnmarshalTOML(data any) error { func (a *FromAddr) UnmarshalTOML(data any) error {
@@ -210,8 +210,8 @@ func (a *FromAddr) Count() int {
// ToAddr represents a destination universe address with starting channel // ToAddr represents a destination universe address with starting channel
type ToAddr struct { type ToAddr struct {
Universe Universe Universe Universe `json:"universe"`
ChannelStart int // 1-indexed ChannelStart int `json:"channel_start"` // 1-indexed
} }
func (a *ToAddr) UnmarshalTOML(data any) error { func (a *ToAddr) UnmarshalTOML(data any) error {

25
main.go
View File

@@ -1,10 +1,12 @@
package main package main
import ( import (
"encoding/json"
"flag" "flag"
"fmt" "fmt"
"log" "log"
"net" "net"
"net/http"
"os" "os"
"os/signal" "os/signal"
"strconv" "strconv"
@@ -35,6 +37,7 @@ func main() {
artnetListen := flag.String("artnet-listen", ":6454", "artnet listen address (empty to disable)") artnetListen := flag.String("artnet-listen", ":6454", "artnet listen address (empty to disable)")
artnetBroadcast := flag.String("artnet-broadcast", "auto", "artnet broadcast addresses (comma-separated, or 'auto')") artnetBroadcast := flag.String("artnet-broadcast", "auto", "artnet broadcast addresses (comma-separated, or 'auto')")
sacnInterface := flag.String("sacn-interface", "", "network interface for sACN multicast") sacnInterface := flag.String("sacn-interface", "", "network interface for sACN multicast")
apiListen := flag.String("api-listen", ":8080", "HTTP API listen address (empty to disable)")
debug := flag.Bool("debug", false, "log incoming/outgoing dmx packets") debug := flag.Bool("debug", false, "log incoming/outgoing dmx packets")
flag.Parse() flag.Parse()
@@ -190,6 +193,22 @@ func main() {
discovery.Start() discovery.Start()
} }
// Start HTTP API server
if *apiListen != "" {
go func() {
mux := http.NewServeMux()
mux.HandleFunc("/api/config", app.handleConfig)
server := &http.Server{
Addr: *apiListen,
Handler: mux,
}
log.Printf("[api] listening addr=%s", *apiListen)
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Printf("[api] server error: %v", err)
}
}()
}
// Wait for interrupt // Wait for interrupt
sigChan := make(chan os.Signal, 1) sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
@@ -288,6 +307,12 @@ func (a *App) sendOutputs(outputs []remap.Output) {
} }
} }
func (a *App) handleConfig(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Server", "artmap")
json.NewEncoder(w).Encode(a.cfg)
}
func init() { func init() {
log.SetFlags(log.Ltime | log.Lmicroseconds) log.SetFlags(log.Ltime | log.Lmicroseconds)
} }