mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-09-07 15:07:17 +00:00
fix(player): retry configured devices during discovery
This commit is contained in:
committed by
Tobias Gesellchen
parent
d3c5ad2d8e
commit
7015e04556
@@ -88,7 +88,7 @@ go build -o soundtouch-player
|
||||
./soundtouch-player -port 8888
|
||||
|
||||
# Connect to specific device
|
||||
./soundtouch-player -host 192.0.2.100
|
||||
./soundtouch-player --devices 192.0.2.100
|
||||
```
|
||||
|
||||
### Command Line Options
|
||||
@@ -137,7 +137,7 @@ device datastore).
|
||||
The application automatically discovers SoundTouch devices using:
|
||||
- **mDNS discovery** for local network devices
|
||||
- **UPnP/SSDP discovery** as fallback
|
||||
- **Manual device addition** via IP address
|
||||
- **Configured devices** via `--devices`, retried whenever discovery runs
|
||||
|
||||
### Real-time Updates
|
||||
The interface maintains WebSocket connections to each device for instant updates of:
|
||||
|
||||
@@ -161,7 +161,7 @@ func main() {
|
||||
log.Printf("Trusting AfterTouch service CA from %s", sanitizeLog(caPath))
|
||||
}
|
||||
|
||||
discoveryService := soundtouchweb.NewDiscoveryService(ifaceName)
|
||||
discoveryService := soundtouchweb.NewDiscoveryService(ifaceName, manualHosts...)
|
||||
|
||||
// Discover devices on startup
|
||||
go func() {
|
||||
@@ -170,10 +170,6 @@ func main() {
|
||||
|
||||
webApp.BroadcastDiscoveryStatus("starting", webApp.DeviceCount())
|
||||
|
||||
for _, host := range manualHosts {
|
||||
webApp.AddDeviceByHost(host, 8090, "manual")
|
||||
}
|
||||
|
||||
webApp.DiscoverDevices(ctx, discoveryService)
|
||||
|
||||
webApp.BroadcastDiscoveryStatus("completed", webApp.DeviceCount())
|
||||
|
||||
@@ -10,12 +10,13 @@ import (
|
||||
"github.com/gesellix/bose-soundtouch/pkg/config"
|
||||
"github.com/gesellix/bose-soundtouch/pkg/discovery"
|
||||
"github.com/gesellix/bose-soundtouch/pkg/service/soundtouchweb/webtypes"
|
||||
"github.com/gesellix/bose-soundtouch/pkg/speaker"
|
||||
)
|
||||
|
||||
// NewDiscoveryService loads config and returns a unified discovery service
|
||||
// preconfigured for the web UI's use (10 s discovery timeout, cache on).
|
||||
// When discoveryInterface is non-empty, mDNS/UPnP are pinned to that NIC.
|
||||
func NewDiscoveryService(discoveryInterface string) *discovery.UnifiedDiscoveryService {
|
||||
func NewDiscoveryService(discoveryInterface string, configuredHosts ...string) *discovery.UnifiedDiscoveryService {
|
||||
cfg, err := config.LoadFromEnv()
|
||||
if err != nil {
|
||||
log.Printf("Failed to load config: %v, using defaults", err)
|
||||
@@ -30,6 +31,17 @@ func NewDiscoveryService(discoveryInterface string) *discovery.UnifiedDiscoveryS
|
||||
cfg.DiscoveryInterface = discoveryInterface
|
||||
}
|
||||
|
||||
for _, host := range configuredHosts {
|
||||
if host == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
cfg.PreferredDevices = append(cfg.PreferredDevices, config.DeviceConfig{
|
||||
Host: host,
|
||||
Port: speaker.HTTPPort,
|
||||
})
|
||||
}
|
||||
|
||||
return discovery.NewUnifiedDiscoveryService(cfg)
|
||||
}
|
||||
|
||||
@@ -164,6 +176,11 @@ func (app *WebApp) DiscoverDevices(ctx context.Context, discoveryService *discov
|
||||
log.Printf("Found %d devices", len(devices))
|
||||
|
||||
for _, device := range devices {
|
||||
app.AddDeviceByHost(device.Host, device.Port, "discovered")
|
||||
source := "discovered"
|
||||
if device.DiscoveryMethod == "Configuration" {
|
||||
source = "manual"
|
||||
}
|
||||
|
||||
app.AddDeviceByHost(device.Host, device.Port, source)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package soundtouchweb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDiscoverDevicesRetriesConfiguredHosts(t *testing.T) {
|
||||
var available atomic.Bool
|
||||
var infoRequests atomic.Int32
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/info" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
infoRequests.Add(1)
|
||||
if !available.Load() {
|
||||
http.Error(w, "offline", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/xml")
|
||||
_, _ = w.Write([]byte(`<info deviceID="TESTDEVICE"><name>Configured speaker</name><type>SoundTouch 10</type></info>`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
t.Setenv("UPNP_ENABLED", "false")
|
||||
t.Setenv("MDNS_ENABLED", "false")
|
||||
t.Setenv("PREFERRED_DEVICES", "")
|
||||
|
||||
configuredHost := strings.TrimPrefix(server.URL, "http://")
|
||||
discoveryService := NewDiscoveryService("", configuredHost)
|
||||
app := NewWebApp()
|
||||
|
||||
app.DiscoverDevices(context.Background(), discoveryService)
|
||||
if got := app.DeviceCount(); got != 0 {
|
||||
t.Fatalf("device count after offline probe = %d, want 0", got)
|
||||
}
|
||||
|
||||
available.Store(true)
|
||||
app.DiscoverDevices(context.Background(), discoveryService)
|
||||
if got := app.DeviceCount(); got != 1 {
|
||||
t.Fatalf("device count after retry = %d, want 1", got)
|
||||
}
|
||||
if got := infoRequests.Load(); got != 2 {
|
||||
t.Fatalf("/info request count = %d, want 2", got)
|
||||
}
|
||||
|
||||
if !app.RemoveDevice(configuredHost) {
|
||||
t.Fatal("configured device was not registered under its host")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user