@@ -156,52 +156,26 @@ void KickAccount::refreshIfNeeded()
156156 }
157157
158158 auto now = QDateTime::currentDateTimeUtc () + CHECK_REFRESH_INTERVAL +
159- std::chrono::seconds{30 };
159+ std::chrono::seconds{60 };
160160 if (now < this ->expiresAt_ )
161161 {
162162 return ;
163163 }
164+ qCDebug (chatterinoKick) << " Attempting to refresh" << this ->username ()
165+ << " expires:" << this ->expiresAt_ ;
164166
165- QUrlQuery payload{
166- {" refresh_token" _L1, this ->refreshToken_ },
167- {" client_id" _L1, this ->clientID_ },
168- {" client_secret" _L1, this ->clientSecret_ },
169- {" grant_type" _L1, " refresh_token" _L1},
170- };
171-
172- auto weak = this ->weak_from_this ();
173- NetworkRequest (u" https://id.kick.com/oauth/token" _s,
174- NetworkRequestType::Post)
175- .header (" Content-Type" , " application/x-www-form-urlencoded" )
176- .payload (payload.toString (QUrl::FullyEncoded).toUtf8 ())
177- .onSuccess ([weak](const NetworkResult &res) {
178- auto self = weak.lock ();
179- if (!self)
180- {
181- return ;
182- }
183-
184- const auto json = res.parseJson ();
185- self->authToken_ = json[" access_token" _L1].toString ();
186- self->refreshToken_ = json[" refresh_token" _L1].toString ();
187- auto expiresInSec =
188- std::clamp<qint64>(json[" expires_in" _L1].toInteger (), 0 ,
189- std::numeric_limits<qint32>::max ());
190- self->expiresAt_ =
191- QDateTime::currentDateTimeUtc ().addSecs (expiresInSec);
192- self->save ();
193- self->authUpdated .invoke ();
194- })
195- .onError ([weak](const NetworkResult &res) {
196- auto self = weak.lock ();
197- if (!self)
198- {
199- return ;
200- }
201- qCWarning (chatterinoKick) << " Failed to refresh" << self->username ()
202- << " error:" << res.formatError ();
203- })
204- .execute ();
167+ // Hack: check the current token first to ensure we're connected. Otherwise,
168+ // we might miss the response.
169+ // FIXME: queue re-check earlier
170+ this ->check ([this ](CheckResult res) {
171+ if (res == CheckResult::NetworkError)
172+ {
173+ qCWarning (chatterinoKick)
174+ << " Skipping refresh, because of network error" ;
175+ return ;
176+ }
177+ this ->doRefresh ();
178+ });
205179}
206180
207181void KickAccount::loadSeventvUser ()
@@ -271,4 +245,91 @@ void KickAccount::loadSeventvUser()
271245 });
272246}
273247
248+ void KickAccount::check (const std::function<void (CheckResult)> &cb)
249+ {
250+ auto weak = this ->weak_from_this ();
251+ NetworkRequest (u" https://id.kick.com/oauth/token/introspect" _s,
252+ NetworkRequestType::Post)
253+ .timeout (10'000 )
254+ .onSuccess ([cb, weak](const NetworkResult & /* res*/ ) {
255+ auto self = weak.lock ();
256+ if (!self)
257+ {
258+ return ;
259+ }
260+ qCDebug (chatterinoKick)
261+ << " [Refresh]: Successfully checked previous token" ;
262+ cb (CheckResult::Valid);
263+ })
264+ .onError ([weak, cb](const NetworkResult &res) {
265+ auto self = weak.lock ();
266+ if (!self)
267+ {
268+ return ;
269+ }
270+ qCDebug (chatterinoKick)
271+ << " [Refresh; Error] Network response:" << res.formatError ();
272+ auto status = res.status ();
273+ if (!status || *status < 100 )
274+ {
275+ cb (CheckResult::NetworkError);
276+ return ;
277+ }
278+ if (*status == 401 )
279+ {
280+ cb (CheckResult::Expired);
281+ return ;
282+ }
283+ cb (CheckResult::OtherHttp);
284+ })
285+ .execute ();
286+ }
287+
288+ void KickAccount::doRefresh ()
289+ {
290+ QUrlQuery payload{
291+ {" refresh_token" _L1, this ->refreshToken_ },
292+ {" client_id" _L1, this ->clientID_ },
293+ {" client_secret" _L1, this ->clientSecret_ },
294+ {" grant_type" _L1, " refresh_token" _L1},
295+ };
296+
297+ auto weak = this ->weak_from_this ();
298+ NetworkRequest (u" https://id.kick.com/oauth/token" _s,
299+ NetworkRequestType::Post)
300+ .header (" Content-Type" , " application/x-www-form-urlencoded" )
301+ .payload (payload.toString (QUrl::FullyEncoded).toUtf8 ())
302+ .timeout (20'000 )
303+ .onSuccess ([weak](const NetworkResult &res) {
304+ auto self = weak.lock ();
305+ if (!self)
306+ {
307+ return ;
308+ }
309+
310+ const auto json = res.parseJson ();
311+ self->authToken_ = json[" access_token" _L1].toString ();
312+ self->refreshToken_ = json[" refresh_token" _L1].toString ();
313+ auto expiresInSec =
314+ std::clamp<qint64>(json[" expires_in" _L1].toInteger (), 0 ,
315+ std::numeric_limits<qint32>::max ());
316+ self->expiresAt_ =
317+ QDateTime::currentDateTimeUtc ().addSecs (expiresInSec);
318+ self->save ();
319+ self->authUpdated .invoke ();
320+ qCDebug (chatterinoKick)
321+ << " [Refresh] Successful, next expiry:" << self->expiresAt_ ;
322+ })
323+ .onError ([weak](const NetworkResult &res) {
324+ auto self = weak.lock ();
325+ if (!self)
326+ {
327+ return ;
328+ }
329+ qCWarning (chatterinoKick) << " Failed to refresh" << self->username ()
330+ << " error:" << res.formatError ();
331+ })
332+ .execute ();
333+ }
334+
274335} // namespace chatterino
0 commit comments