1+ local api_version = require " version" .api
12local cosock = require " cosock"
23local json = require " st.json"
34local log = require " log"
@@ -74,7 +75,13 @@ local _update_subscriptions_helper = function(
7475 {},
7576 }
7677 local payload = json .encode (payload_table )
77- Router .send_message_to_player (utils .sonos_unique_key (householdId , playerId ), payload , reply_tx )
78+ local unique_key , bad_key_part = utils .sonos_unique_key (householdId , playerId )
79+ if not unique_key then
80+ local err_msg = string.format (" Invalid Sonos Unique Key Part: %s" , bad_key_part )
81+ reply_tx :send (table.pack (nil , err_msg ))
82+ return
83+ end
84+ Router .send_message_to_player (unique_key , payload , reply_tx )
7885 end
7986end
8087
@@ -168,10 +175,13 @@ local function _open_coordinator_socket(sonos_conn, household_id, self_player_id
168175 end
169176
170177 local listener_id
171- listener_id , err = Router .register_listener_for_socket (
172- sonos_conn ,
173- utils .sonos_unique_key (household_id , coordinator_id )
174- )
178+ local unique_key , bad_key_part = utils .sonos_unique_key (household_id , coordinator_id )
179+
180+ if not unique_key then
181+ log .error (string.format (" Invalid Sonos Unique Key Part: %s" , bad_key_part ))
182+ end
183+
184+ listener_id , err = Router .register_listener_for_socket (sonos_conn , unique_key )
175185 if err ~= nil or not listener_id then
176186 log .error (err )
177187 else
@@ -208,7 +218,22 @@ local function backoff_builder(max, inc, rand)
208218end
209219
210220--- @param sonos_conn SonosConnection
211- local function _spawn_reconnect_task (sonos_conn )
221+ local function _legacy_reconnect_task (sonos_conn )
222+ log .debug (" Spawning reconnect task for " , sonos_conn .device .label )
223+ cosock .spawn (function ()
224+ local backoff = backoff_builder (60 , 1 , 0.1 )
225+ while not sonos_conn :is_running () do
226+ local start_success = sonos_conn :start ()
227+ if start_success then
228+ return
229+ end
230+ cosock .socket .sleep (backoff ())
231+ end
232+ end , string.format (" %s Reconnect Task" , sonos_conn .device .label ))
233+ end
234+
235+ --- @param sonos_conn SonosConnection
236+ local function _oauth_reconnect_task (sonos_conn )
212237 log .debug (" Spawning reconnect task for " , sonos_conn .device .label )
213238 if not sonos_conn .driver :is_waiting_for_oauth_token () then
214239 sonos_conn .driver :request_oauth_token ()
@@ -243,6 +268,15 @@ local function _spawn_reconnect_task(sonos_conn)
243268 end , string.format (" %s Reconnect Task" , sonos_conn .device .label ))
244269end
245270
271+ --- @param sonos_conn SonosConnection
272+ local function _spawn_reconnect_task (sonos_conn )
273+ if type (api_version ) == " number" and api_version >= 14 then
274+ _oauth_reconnect_task (sonos_conn )
275+ else
276+ _legacy_reconnect_task (sonos_conn )
277+ end
278+ end
279+
246280--- Create a new Sonos connection to manage the given device
247281--- @param driver SonosDriver
248282--- @param device SonosDevice
@@ -276,15 +310,29 @@ function SonosConnection.new(driver, device)
276310 local header , body = table.unpack (table.unpack (json_result ))
277311 if header .type == " globalError" then
278312 if body .errorCode == " ERROR_NOT_AUTHORIZED" then
279- local household_id , player_id = driver .sonos :get_player_for_device (device )
280- device .log .warn (string.format (" WebSocket connection no longer authorized, disconnecting" ))
281- local _ , security_err = driver :request_oauth_token ()
282- if security_err then
283- log .warn (string.format (" Error during request for oauth token: %s" , security_err ))
313+ if api_version < 14 then
314+ log .error (
315+ " Unable to authenticate Sonos WebSocket Connection, and current API does not support Sonos OAuth"
316+ )
317+ self :stop ()
318+ else
319+ local household_id , player_id = driver .sonos :get_player_for_device (device )
320+ device .log .warn (
321+ string.format (" WebSocket connection no longer authorized, disconnecting" )
322+ )
323+ local _ , security_err = driver :request_oauth_token ()
324+ if security_err then
325+ log .warn (string.format (" Error during request for oauth token: %s" , security_err ))
326+ end
327+ -- closing the socket directly without calling `:stop()` triggers the reconnect loop,
328+ -- which is where we wait for the token to come in.
329+ local unique_key , bad_key_part = utils .sonos_unique_key (household_id , player_id )
330+ if not unique_key then
331+ log .error (string.format (" Invalid Sonos Unique Key Part: %s" , bad_key_part ))
332+ else
333+ Router .close_socket_for_player (unique_key )
334+ end
284335 end
285- -- closing the socket directly without calling `:stop()` triggers the reconnect loop,
286- -- which is where we wait for the token to come in.
287- Router .close_socket_for_player (utils .sonos_unique_key (household_id , player_id ))
288336 end
289337 elseif header .type == " groups" then
290338 log .trace (string.format (" Groups type message for %s" , device_name ))
@@ -494,15 +542,32 @@ end
494542function SonosConnection :self_running ()
495543 local household_id = self .device :get_field (PlayerFields .HOUSEHOLD_ID )
496544 local player_id = self .device :get_field (PlayerFields .PLAYER_ID )
497- return Router .is_connected (utils .sonos_unique_key (household_id , player_id )) and self ._initialized
545+ local unique_key , bad_key_part = utils .sonos_unique_key (household_id , player_id )
546+ if bad_key_part then
547+ self .device .log .warn (
548+ string.format (
549+ " Bad Unique Key Part While Inspecting Connections in 'self_running': %s" ,
550+ bad_key_part
551+ )
552+ )
553+ end
554+ return type (unique_key ) == " string" and Router .is_connected (unique_key ) and self ._initialized
498555end
499556
500557--- Whether or not the connection has a live websocket connection to its coordinator
501558--- @return boolean
502559function SonosConnection :coordinator_running ()
503560 local household_id , coordinator_id = self .driver .sonos :get_coordinator_for_device (self .device )
504- return Router .is_connected (utils .sonos_unique_key (household_id , coordinator_id ))
505- and self ._initialized
561+ local unique_key , bad_key_part = utils .sonos_unique_key (household_id , coordinator_id )
562+ if bad_key_part then
563+ self .device .log .warn (
564+ string.format (
565+ " Bad Unique Key Part While Inspecting Connections in 'coordinator_running': %s" ,
566+ bad_key_part
567+ )
568+ )
569+ end
570+ return unique_key and Router .is_connected (unique_key ) and self ._initialized
506571end
507572
508573function SonosConnection :refresh_subscriptions (maybe_reply_tx )
@@ -524,10 +589,12 @@ function SonosConnection:send_command(cmd)
524589 if err or not json_payload then
525590 log .error (" Json encoding error: " .. err )
526591 else
527- Router .send_message_to_player (
528- utils .sonos_unique_key (household_id , coordinator_id ),
529- json_payload
530- )
592+ local unique_key , bad_key_part = utils .sonos_unique_key (household_id , coordinator_id )
593+ if not unique_key then
594+ self .device .log .error (string.format (" Invalid Sonos Unique Key Part: %s" , bad_key_part ))
595+ return
596+ end
597+ Router .send_message_to_player (unique_key , json_payload )
531598 end
532599end
533600
@@ -562,12 +629,17 @@ function SonosConnection:start()
562629 return false
563630 end
564631
565- local listener_id , register_listener_err =
566- Router .register_listener_for_socket (self , utils .sonos_unique_key (household_id , player_id ))
567- if register_listener_err ~= nil or not listener_id then
568- log .error (register_listener_err )
632+ local unique_key , bad_key_part = utils .sonos_unique_key (household_id , player_id )
633+ if bad_key_part then
634+ self .device .log .error (string.format (" Invalid Sonos Unique Key Part: %s" , bad_key_part ))
569635 else
570- self ._self_listener_uuid = listener_id
636+ local listener_id , register_listener_err =
637+ Router .register_listener_for_socket (self , unique_key )
638+ if register_listener_err ~= nil or not listener_id then
639+ log .error (register_listener_err )
640+ else
641+ self ._self_listener_uuid = listener_id
642+ end
571643 end
572644 end
573645
@@ -578,16 +650,39 @@ function SonosConnection:start()
578650
579651 self :refresh_subscriptions ()
580652 local coordinator_id = self .driver .sonos :get_coordinator_for_player (household_id , player_id )
653+ local self_unique_key , self_bad_key_part = utils .sonos_unique_key (household_id , player_id )
654+ local coordinator_unique_key , coordinator_bad_key_part =
655+ utils .sonos_unique_key (household_id , coordinator_id )
581656 if
582- Router .is_connected (utils .sonos_unique_key (household_id , player_id ))
583- and Router .is_connected (utils .sonos_unique_key (household_id , coordinator_id ))
657+ self_unique_key
658+ and Router .is_connected (self_unique_key )
659+ and coordinator_unique_key
660+ and Router .is_connected (coordinator_unique_key )
584661 then
585662 self .device :online ()
586663 self ._initialized = true
587664 self ._keepalive = true
588665 return true
589666 end
590667
668+ if self_bad_key_part then
669+ self .device .log .error (
670+ string.format (
671+ " Invalid Unique Key Part for 'self' Player during connection bring-up: %s" ,
672+ self_bad_key_part
673+ )
674+ )
675+ end
676+
677+ if coordinator_bad_key_part then
678+ self .device .log .error (
679+ string.format (
680+ " Invalid Unique Key Part for 'coordinator' Player during connection bring-up: %s" ,
681+ coordinator_bad_key_part
682+ )
683+ )
684+ end
685+
591686 return false
592687end
593688
@@ -601,7 +696,12 @@ function SonosConnection:stop()
601696 local coordinator_id = self .driver .sonos :get_coordinator_for_group (household_id , group_id )
602697
603698 if player_id ~= coordinator_id then
604- Router .close_socket_for_player (utils .sonos_unique_key (household_id , player_id ))
699+ local unique_key , bad_key_part = utils .sonos_unique_key (household_id , player_id )
700+ if not unique_key then
701+ self .device .log .error (string.format (" Invalid Sonos Unique Key Part: %s" , bad_key_part ))
702+ return
703+ end
704+ Router .close_socket_for_player (unique_key )
605705 end
606706end
607707
0 commit comments