mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
Fix WebSocket connection issues and add special message parsing
- Fix WebSocket URL construction by properly extracting hostname from base URL - Add 'gabbo' protocol requirement as specified in SoundTouch API docs - Add parsing for SoundTouchSdkInfo and UserActivityUpdate messages - Add proper filtering support for special message types (sdkInfo, userActivity) - Fix nil pointer dereference by ensuring WebSocket client always has a logger - Add SilentLogger for non-verbose mode to prevent crashes - Update README and help text to include new special message types - Clean up logging to only show unknown message types, not known special messages Fixes the original WebSocket connection error: 'parse "ws://http:%2F%2F192.168.178.28:8090:8080/": invalid URL escape "%2F"'
This commit is contained in:
+52
-2
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -153,6 +154,14 @@ func (ws *WebSocketClient) OnUnknownEvent(handler models.EventHandler) {
|
||||
ws.handlers.OnUnknownEvent = handler
|
||||
}
|
||||
|
||||
// OnSpecialMessage sets a handler for special (non-updates) messages
|
||||
func (ws *WebSocketClient) OnSpecialMessage(handler models.SpecialMessageHandler) {
|
||||
ws.mu.Lock()
|
||||
defer ws.mu.Unlock()
|
||||
|
||||
ws.handlers.OnSpecialMessage = handler
|
||||
}
|
||||
|
||||
// Connect establishes a WebSocket connection to the SoundTouch device
|
||||
func (ws *WebSocketClient) Connect() error {
|
||||
return ws.connectWithConfig(DefaultWebSocketConfig())
|
||||
@@ -172,19 +181,26 @@ func (ws *WebSocketClient) connectWithConfig(config *WebSocketConfig) error {
|
||||
}
|
||||
|
||||
// Build WebSocket URL
|
||||
// Parse the base URL to extract just the hostname
|
||||
baseURL, err := url.Parse(ws.client.BaseURL())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse base URL: %w", err)
|
||||
}
|
||||
|
||||
wsURL := url.URL{
|
||||
Scheme: "ws",
|
||||
Host: fmt.Sprintf("%s:%d", ws.client.Host(), 8080), // SoundTouch WebSocket port is typically 8080
|
||||
Host: fmt.Sprintf("%s:8080", baseURL.Hostname()), // SoundTouch WebSocket port is typically 8080
|
||||
Path: "/",
|
||||
}
|
||||
|
||||
ws.logger.Printf("Connecting to %s", wsURL.String())
|
||||
|
||||
// Create dialer with custom buffer sizes
|
||||
// Create dialer with custom buffer sizes and "gabbo" protocol
|
||||
dialer := websocket.Dialer{
|
||||
HandshakeTimeout: 10 * time.Second,
|
||||
ReadBufferSize: config.ReadBufferSize,
|
||||
WriteBufferSize: config.WriteBufferSize,
|
||||
Subprotocols: []string{"gabbo"}, // Required by SoundTouch API
|
||||
}
|
||||
|
||||
// Establish connection
|
||||
@@ -357,6 +373,12 @@ func (ws *WebSocketClient) attemptReconnect(config *WebSocketConfig) {
|
||||
|
||||
// handleMessage processes incoming WebSocket messages
|
||||
func (ws *WebSocketClient) handleMessage(data []byte) {
|
||||
// Check if this is a SoundTouchSdkInfo or other non-updates message
|
||||
if !ws.isUpdatesMessage(data) {
|
||||
ws.handleSpecialMessage(data)
|
||||
return
|
||||
}
|
||||
|
||||
// Parse the WebSocket event
|
||||
event, err := models.ParseWebSocketEvent(data)
|
||||
if err != nil {
|
||||
@@ -368,6 +390,34 @@ func (ws *WebSocketClient) handleMessage(data []byte) {
|
||||
ws.handleEvent(event)
|
||||
}
|
||||
|
||||
// handleSpecialMessage processes special (non-updates) WebSocket messages
|
||||
func (ws *WebSocketClient) handleSpecialMessage(data []byte) {
|
||||
specialMessage, err := models.ParseSpecialMessage(data)
|
||||
if err != nil {
|
||||
ws.logger.Printf("Unknown special message type: %v", err)
|
||||
ws.logger.Printf("Raw message: %s", string(data))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Call handler if set
|
||||
ws.mu.RLock()
|
||||
handler := ws.handlers.OnSpecialMessage
|
||||
ws.mu.RUnlock()
|
||||
|
||||
if handler != nil {
|
||||
handler(specialMessage)
|
||||
}
|
||||
}
|
||||
|
||||
// isUpdatesMessage checks if the message contains an <updates> element
|
||||
func (ws *WebSocketClient) isUpdatesMessage(data []byte) bool {
|
||||
// Simple check for <updates> element - this avoids full XML parsing
|
||||
// for messages we want to ignore like <SoundTouchSdkInfo>
|
||||
dataStr := string(data)
|
||||
return strings.Contains(dataStr, "<updates") && strings.Contains(dataStr, "deviceID=")
|
||||
}
|
||||
|
||||
func (ws *WebSocketClient) dispatchTypedEvent(handlers *models.WebSocketEventHandlers, eventType models.WebSocketEventType, event *models.WebSocketEvent) bool {
|
||||
switch eventType {
|
||||
case models.EventTypeNowPlaying:
|
||||
|
||||
Reference in New Issue
Block a user