Fix Meebook/Huskelisten crash on non-list API responses and handle JWT token expiry#341
Fix Meebook/Huskelisten crash on non-list API responses and handle JWT token expiry#341Jogge wants to merge 1 commit into
Conversation
…T token expiry Fixes scaarup#311 — Sensors become unavailable after a few hours/days and require a reload to recover. ## Problem When Meebook's JWT token expires, the API returns a JSON dict (`{"message": "JWT-Token expired, please renew."}`) instead of the expected JSON array. The code iterated over this response directly, causing `TypeError: string indices must be integers, not 'str'` which crashed the sensor update loop and made all sensors permanently unavailable until a manual reload. The same class of bug existed in the Huskelisten flow, where a bare `except:` clause failed to set `data = None`, leaving `data` undefined if JSON parsing failed. ## Solution **Meebook — JWT token expiry recovery:** When Meebook returns a JWT expiry message, the integration now invalidates the cached widget token, resets the HTTP session (to clear stale cookies), forces a full Aula token refresh via `login(force_refresh=True)`, obtains a fresh widget token, and retries the Meebook request — all in a single pass without a retry loop. **Meebook — defensive response handling:** - Wrapped `json.loads()` in `try/except (json.JSONDecodeError, ValueError)` (was previously unprotected) - Added `isinstance(data, list)` type guard before iterating - Preserved the existing `exceptionMessage` error handling within the type guard **Huskelisten — defensive response handling:** - Narrowed bare `except:` to `except (json.JSONDecodeError, ValueError)` - Set `data = None` on parse failure (previously left `data` undefined) - Added `isinstance(data, list)` type guard before iterating **login() — force_refresh parameter:** Added `force_refresh=False` parameter to `login()` to allow bypassing the "token looks valid" cache check, needed for the Meebook recovery flow to force `renew_access_token()` even when the access token hasn't technically expired yet.
|
The access token and the problem itself is only related to Meebook, right? I do not understand why the login function for Aula itself needs to be changed here? |
|
@scaarup Jeg smider lige Copilots forklaring på, hvorfor det er implementeret sådan her:
Jeg spurgte efterfølgende, om det kunne løses mere elegant, og fik denne opsumering:
Problemet er bare, at når jeg beder den implementere det, så bliver ændringerne ret invasive og begynder bl.a. at fjerne mock-data: Jeg kan godt følge, hvad Python-koden gør, men jeg ville ikke selv kunne implementere det fra bunden. Den nuværende løsning virker dog som forventet. Hvis du har et forslag til en mere elegant løsning, som undgår at ændre login-flowet, er du meget velkommen til at byde ind 🙌 |
Match upstream PR scaarup#341 widget JWT recovery; revert v0.2.6 regressions
Fixes #311 — Sensors become unavailable after a few hours/days and require a reload to recover.
Problem
When Meebook's JWT token expires, the API returns a JSON dict (
{"message": "JWT-Token expired, please renew."}) instead of the expected JSON array. The code iterated over this response directly, causingTypeError: string indices must be integers, not 'str'which crashed the sensor update loop and made all sensors permanently unavailable until a manual reload.The same class of bug existed in the Huskelisten flow, where a bare
except:clause failed to setdata = None, leavingdataundefined if JSON parsing failed.Solution
Meebook — JWT token expiry recovery:
When Meebook returns a JWT expiry message, the integration now invalidates the cached widget token, resets the HTTP session (to clear stale cookies), forces a full Aula token refresh via
login(force_refresh=True), obtains a fresh widget token, and retries the Meebook request — all in a single pass without a retry loop.Meebook — defensive response handling:
json.loads()intry/except (json.JSONDecodeError, ValueError)(was previously unprotected)isinstance(data, list)type guard before iteratingexceptionMessageerror handling within the type guardHuskelisten — defensive response handling:
except:toexcept (json.JSONDecodeError, ValueError)data = Noneon parse failure (previously leftdataundefined)isinstance(data, list)type guard before iteratinglogin() — force_refresh parameter:
Added
force_refresh=Falseparameter tologin()to allow bypassing the "token looks valid" cache check, needed for the Meebook recovery flow to forcerenew_access_token()even when the access token hasn't technically expired yet.