diff --git a/artnet/receiver.go b/artnet/receiver.go index 1d31c1b..b2681f5 100644 --- a/artnet/receiver.go +++ b/artnet/receiver.go @@ -20,12 +20,7 @@ type Receiver struct { } // NewReceiver creates a new ArtNet receiver -func NewReceiver(port int, handler PacketHandler) (*Receiver, error) { - addr := &net.UDPAddr{ - Port: port, - IP: net.IPv4zero, - } - +func NewReceiver(addr *net.UDPAddr, handler PacketHandler) (*Receiver, error) { conn, err := net.ListenUDP("udp4", addr) if err != nil { return nil, err diff --git a/config.example.toml b/config.example.toml index e359ed8..877eee5 100644 --- a/config.example.toml +++ b/config.example.toml @@ -1,5 +1,5 @@ # artmap configuration -# Run with: go run . -config config.toml [-port 6454] [-broadcast 2.255.255.255] +# Run with: go run . -config config.toml [-listen :6454] [-broadcast 2.255.255.255] # Address format: # from: universe[:channels] - range specifies which channels to read diff --git a/main.go b/main.go index bbc9598..4f24f41 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,8 @@ import ( "net" "os" "os/signal" + "strconv" + "strings" "syscall" "github.com/gopatchy/artmap/artnet" @@ -25,11 +27,17 @@ type App struct { func main() { configPath := flag.String("config", "config.toml", "path to config file") - listenPort := flag.Int("port", artnet.Port, "ArtNet listen port") + listenAddr := flag.String("listen", ":6454", "listen address (host:port, host, or :port)") broadcastAddr := flag.String("broadcast", "2.255.255.255", "ArtNet broadcast address") debug := flag.Bool("debug", false, "log ArtNet packets") flag.Parse() + // Parse listen address + addr, err := parseListenAddr(*listenAddr) + if err != nil { + log.Fatalf("invalid listen address: %v", err) + } + // Load config cfg, err := config.Load(*configPath) if err != nil { @@ -70,7 +78,7 @@ func main() { } // Create receiver - receiver, err := artnet.NewReceiver(*listenPort, app) + receiver, err := artnet.NewReceiver(addr, app) if err != nil { log.Fatalf("failed to create receiver: %v", err) } @@ -80,7 +88,7 @@ func main() { receiver.Start() discovery.Start() - log.Printf("listening on port %d", *listenPort) + log.Printf("listening on %s", addr) log.Printf("broadcasting to %s", *broadcastAddr) // Wait for interrupt @@ -155,3 +163,43 @@ func init() { fmt.Println("artmap - ArtNet Remapping Proxy") fmt.Println() } + +// parseListenAddr parses listen address formats: +// - "host:port" -> bind to specific host and port +// - "host" -> bind to specific host, default port +// - ":port" -> bind to all interfaces, specific port +func parseListenAddr(s string) (*net.UDPAddr, error) { + var host string + var port int + + if strings.Contains(s, ":") { + h, p, err := net.SplitHostPort(s) + if err != nil { + return nil, err + } + host = h + if p == "" { + port = artnet.Port + } else { + port, err = strconv.Atoi(p) + if err != nil { + return nil, err + } + } + } else { + host = s + port = artnet.Port + } + + var ip net.IP + if host == "" { + ip = net.IPv4zero + } else { + ip = net.ParseIP(host) + if ip == nil { + return nil, fmt.Errorf("invalid IP address: %s", host) + } + } + + return &net.UDPAddr{IP: ip, Port: port}, nil +}