@@ -77,8 +77,76 @@ function SonosDriverLifecycleHandlers.initialize_device(driver, device)
77
77
log .error (" token event bus closed, aborting initialization" )
78
78
return
79
79
end
80
- driver :request_oauth_token ()
81
- token_event_receive :receive ()
80
+ token_event_receive :settimeout (30 )
81
+ local token , token_recv_err
82
+ -- max 30 mins
83
+ local backoff_builder = utils .backoff_builder (60 * 30 , 30 , 2 )
84
+ if not driver :is_waiting_for_oauth_token () then
85
+ local _ , request_token_err = driver :request_oauth_token ()
86
+ if request_token_err then
87
+ log .warn (string.format (" Error sending token request: %s" , request_token_err ))
88
+ end
89
+ end
90
+
91
+ local backoff_timer = nil
92
+ while not token do
93
+ local send_request = false
94
+ -- we use the backoff to create a timer and utilize a select loop here, instead of
95
+ -- utilizing a sleep, so that we can create a long delay on our polling of the cloud
96
+ -- without putting ourselves in a situation where we're sleeping for an extended period
97
+ -- of time so that we don't sleep through the users's log-in attempt and fail to resume
98
+ -- our connection attempts in a timely manner.
99
+ --
100
+ -- The backoff caps at 30 mins, as commented above
101
+ if not backoff_timer then
102
+ backoff_timer = cosock .timer .create_oneshot (backoff_builder ())
103
+ end
104
+ local token_recv_ready , _ , token_select_err =
105
+ cosock .socket .select ({ token_event_receive , backoff_timer }, nil , nil )
106
+
107
+ if token_select_err then
108
+ log .warn (string.format (" select error: %s" , token_select_err ))
109
+ end
110
+
111
+ token , token_recv_err = nil , nil
112
+ for _ , receiver in pairs (token_recv_ready or {}) do
113
+ if receiver == backoff_timer then
114
+ -- we just make a note that the backoff has elapsed, rather than
115
+ -- put a request in flight immediately.
116
+ --
117
+ -- This is just in case both receivers are ready, so that we can prioritize
118
+ -- handling the token instead of putting another request in flight.
119
+ send_request = true
120
+ backoff_timer = nil
121
+ end
122
+
123
+ if receiver == token_event_receive then
124
+ token , token_recv_err = token_event_receive :receive ()
125
+ end
126
+ end
127
+
128
+ if token_recv_err == " timeout" then
129
+ log .debug (" timeout waiting for OAuth token in reconnect task" )
130
+ elseif token_recv_err and not token then
131
+ log .warn (
132
+ string.format (
133
+ " Unexpected error on token event receive bus: %s" ,
134
+ token_recv_err
135
+ )
136
+ )
137
+ end
138
+
139
+ if send_request then
140
+ if not driver :is_waiting_for_oauth_token () then
141
+ local _ , request_token_err = driver :request_oauth_token ()
142
+ if request_token_err then
143
+ log .warn (
144
+ string.format (" Error sending token request: %s" , request_token_err )
145
+ )
146
+ end
147
+ end
148
+ end
149
+ end
82
150
else
83
151
device .log .error (
84
152
string.format (
0 commit comments