fix: tab reloads actually reload — kanban switch spam, plugins/skills refresh, ws mint (#897)
- ws: ticket-mint response body was read on the calling (main) thread —
the socket read threw NetworkOnMainThreadException, the mint failed,
and the kanban events stream never connected (board stuck Offline).
execute() + body read now run entirely on Dispatchers.IO; same fix in
DashboardSessionTokenRefresher.fetch (loopback mint path).
- kanban: re-selecting the already-active board reloads data and
reconnects events WITHOUT the redundant POST /boards/{id}/switch that
refresh fired on every tap.
- plugins: top-bar Refresh + pull-to-refresh wired through HermesScaffold
(previously no reload control at all).
- skills: Refresh icon now does a plain GET reload; the heavy hub-update
POST moved to the cloud icon so refresh is no longer disguised as update.
- test: mock the 3-arg Log.w overload (catch now logs the full stack).
Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
9c7bb8635f
commit
90c1e8dc5f
6 files changed
+131
-106
No files matched your search
@@ -450,28 +450,34 @@ object HermesWsClient {
|
||||
.post("{}".toRequestBody())
|
||||
.build()
|
||||
|
||||
// Run network call on Dispatchers.IO to avoid NetworkOnMainThreadException
|
||||
val response =
|
||||
// Run the ENTIRE call on Dispatchers.IO — execute() already hops,
|
||||
// but ResponseBody.string() reads the socket on the CALLING
|
||||
// thread. When the caller is main (kanban events connect), that
|
||||
// read throws NetworkOnMainThreadException and the mint fails.
|
||||
val (code, body) =
|
||||
kotlinx.coroutines.runBlocking(Dispatchers.IO) {
|
||||
client.newCall(request).execute()
|
||||
client.newCall(request).execute().use { resp ->
|
||||
resp.code to resp.body?.string()
|
||||
}
|
||||
}
|
||||
|
||||
response.use {
|
||||
if (response.isSuccessful) {
|
||||
val body = response.body.string()
|
||||
val ticketMatch = Regex("""\"ticket\":\"([^\"]+)\"""").find(body)
|
||||
val ticket = ticketMatch?.groupValues?.getOrNull(1)
|
||||
if (!ticket.isNullOrBlank()) {
|
||||
return TicketRequestResult(ticket, null)
|
||||
}
|
||||
Log.w(TAG, "WS ticket mint failed: response body did not contain ticket")
|
||||
} else {
|
||||
Log.w(TAG, "WS ticket mint failed: HTTP ${response.code}")
|
||||
return TicketRequestResult(null, response.code)
|
||||
if (body != null && code in 200..299) {
|
||||
val ticketMatch = Regex("""\"ticket\":\"([^\"]+)\"""").find(body)
|
||||
val ticket = ticketMatch?.groupValues?.getOrNull(1)
|
||||
if (!ticket.isNullOrBlank()) {
|
||||
return TicketRequestResult(ticket, null)
|
||||
}
|
||||
Log.w(TAG, "WS ticket mint failed: response body did not contain ticket")
|
||||
} else {
|
||||
Log.w(TAG, "WS ticket mint failed: HTTP $code")
|
||||
return TicketRequestResult(null, code)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "WS ticket mint failed: ${e.javaClass.simpleName}")
|
||||
// Include the stack: the exception class alone (e.g.
|
||||
// NetworkOnMainThreadException) can't show WHICH caller on what
|
||||
// thread tripped the mint (main-scope kanban events connect vs
|
||||
// the WS reconnect path).
|
||||
Log.w(TAG, "WS ticket mint failed: ${e.javaClass.simpleName}", e)
|
||||
return TicketRequestResult(null, null, exception = true)
|
||||
}
|
||||
return TicketRequestResult(null, null)
|
||||
|
||||
Reference in new issue
Block a user