mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
feat(web): default --interface to --bind's interface name
When the user passes --bind <iface> and doesn't set --interface, discovery now reuses the same interface name instead of auto-picking. Common single-interface setups stop needing to repeat the flag, while the two flags remain independent for the cases that legitimately want HTTP and discovery on different interfaces. Update the --interface help text to document the default. The --bind text is unchanged: it still describes the HTTP listener address. Refs #264 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
206ef1f665
commit
e496974f0d
@@ -43,7 +43,7 @@ func main() {
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "interface",
|
||||
Usage: "Network interface name (e.g. eth0) for mDNS and UPnP discovery; leave empty to auto-pick",
|
||||
Usage: "Network interface name (e.g. eth0) for mDNS and UPnP device discovery. Defaults to the --bind interface name when one was given; leave empty otherwise to auto-pick",
|
||||
EnvVars: []string{"DISCOVERY_INTERFACE"},
|
||||
},
|
||||
},
|
||||
@@ -60,7 +60,12 @@ func main() {
|
||||
log.Printf("Resolved --bind %q to %s", rawBind, bindAddr)
|
||||
}
|
||||
|
||||
ifaceName := c.String("interface")
|
||||
rawIface := c.String("interface")
|
||||
|
||||
ifaceName := defaultDiscoveryInterface(rawIface, rawBind, bindAddr)
|
||||
if rawIface == "" && ifaceName != "" {
|
||||
log.Printf("Defaulting --interface to %q from --bind", ifaceName)
|
||||
}
|
||||
|
||||
addr := ":" + port
|
||||
if bindAddr != "" {
|
||||
@@ -113,6 +118,24 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// defaultDiscoveryInterface picks the interface name to use for mDNS/UPnP
|
||||
// discovery. An explicit --interface always wins; otherwise, when --bind was
|
||||
// given an interface name (i.e. resolveBindAddr substituted an IP for it),
|
||||
// that name is reused so the common single-interface case "just works".
|
||||
// Returns the empty string when there is nothing to propagate, leaving the
|
||||
// discovery service to auto-pick.
|
||||
func defaultDiscoveryInterface(rawInterface, rawBind, resolvedBind string) string {
|
||||
if rawInterface != "" {
|
||||
return rawInterface
|
||||
}
|
||||
|
||||
if rawBind != "" && rawBind != resolvedBind {
|
||||
return rawBind
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// resolveBindAddr returns the address to bind the HTTP listener to.
|
||||
//
|
||||
// If bindAddr names a local network interface, the interface's single IPv4
|
||||
@@ -126,8 +149,10 @@ func main() {
|
||||
// If bindAddr is not an interface name — including the empty string, a host
|
||||
// name, or a literal IP — it is returned unchanged.
|
||||
func resolveBindAddr(bindAddr string) (string, error) {
|
||||
iface, err := net.InterfaceByName(bindAddr)
|
||||
if err != nil {
|
||||
// A lookup failure here just means bindAddr isn't an interface name
|
||||
// (it's a host, IP, or empty); fall through to pass-through.
|
||||
iface, _ := net.InterfaceByName(bindAddr)
|
||||
if iface == nil {
|
||||
return bindAddr, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,69 @@ func findLoopbackWithSingleIPv4(t *testing.T) (name, addr string, ok bool) {
|
||||
return "", "", false
|
||||
}
|
||||
|
||||
func TestDefaultDiscoveryInterface(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
rawInterface string
|
||||
rawBind string
|
||||
resolvedBind string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "explicit interface wins over bind-derived default",
|
||||
rawInterface: "eth1",
|
||||
rawBind: "eth0",
|
||||
resolvedBind: "192.168.1.5",
|
||||
want: "eth1",
|
||||
},
|
||||
{
|
||||
name: "derive from --bind when --bind was an interface name",
|
||||
rawInterface: "",
|
||||
rawBind: "eth0",
|
||||
resolvedBind: "192.168.1.5",
|
||||
want: "eth0",
|
||||
},
|
||||
{
|
||||
name: "no derivation when --bind was an IP literal",
|
||||
rawInterface: "",
|
||||
rawBind: "192.168.1.5",
|
||||
resolvedBind: "192.168.1.5",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "no derivation when --bind was a hostname (pass-through)",
|
||||
rawInterface: "",
|
||||
rawBind: "localhost",
|
||||
resolvedBind: "localhost",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "both empty stays empty (auto-pick)",
|
||||
rawInterface: "",
|
||||
rawBind: "",
|
||||
resolvedBind: "",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "explicit interface alone, --bind empty",
|
||||
rawInterface: "eth1",
|
||||
rawBind: "",
|
||||
resolvedBind: "",
|
||||
want: "eth1",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got := defaultDiscoveryInterface(tc.rawInterface, tc.rawBind, tc.resolvedBind)
|
||||
if got != tc.want {
|
||||
t.Errorf("got %q, want %q (rawInterface=%q rawBind=%q resolvedBind=%q)",
|
||||
got, tc.want, tc.rawInterface, tc.rawBind, tc.resolvedBind)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func quoted(s string) string {
|
||||
if s == "" {
|
||||
return "(empty)"
|
||||
|
||||
Reference in New Issue
Block a user