fix(notification): resume stored session before reply (#805)

This commit is contained in:
AlexDev_ authored and GitHub committed 2026-08-04 19:54:49 +03:00
1 parent e1a04a9396
commit 356ccc98b5
13 files changed
+268 -39

No files matched your search

@@ -16,6 +16,7 @@ import com.m57.hermescontrol.data.model.PinnedModel
import com.m57.hermescontrol.data.remote.CleartextPolicy
import com.m57.hermescontrol.data.remote.CookieManager
import com.m57.hermescontrol.data.remote.ServerEndpoint
import com.m57.hermescontrol.data.session.ActiveSessionHolder
import com.m57.hermescontrol.theme.ThemePreference
import com.m57.hermescontrol.theme.ThemePreset
import kotlinx.coroutines.CoroutineScope
@@ -310,6 +311,7 @@ object AuthManager {
) {
requirePrefs().edit().putString("token_$profileId", token).apply()
if (getSelectedProfileId() == profileId) {
if (token == null) ActiveSessionHolder.clear()
// B7 (Jul 08 2026, kanban t_470): sync in-memory cachedToken
// to prevent stale tokens during ticket refresh
synchronized(this) {
@@ -326,6 +328,9 @@ object AuthManager {
}
fun setSelectedProfileId(id: String?) {
if (getSelectedProfileId() != id?.takeIf { it.isNotBlank() }) {
ActiveSessionHolder.clear()
}
serverStore.update { it.copy(selectedProfileId = id) }
synchronized(this) {
tokenInitialized = false
@@ -17,12 +17,32 @@ import kotlinx.coroutines.flow.asStateFlow
*/
object ActiveSessionHolder {
private val _activeSessionId = MutableStateFlow<String?>(null)
private var activeStoredSessionId: String? = null
/** The currently active chat session id, or null if none is known yet. */
val activeSessionId: StateFlow<String?> = _activeSessionId.asStateFlow()
/** Update the active session id. Pass null to clear (e.g. on logout). */
fun set(sessionId: String?) {
@Synchronized
fun set(
sessionId: String?,
storedSessionId: String? = null,
) {
_activeSessionId.value = sessionId
activeStoredSessionId = storedSessionId
}
@Synchronized
fun resolveStoredSessionId(sessionId: String?): String? =
if (sessionId == _activeSessionId.value) activeStoredSessionId ?: sessionId else sessionId
@Synchronized
fun resolveRuntimeSessionId(sessionId: String): String? =
_activeSessionId.value.takeIf { activeStoredSessionId == sessionId }
@Synchronized
fun clear() {
_activeSessionId.value = null
activeStoredSessionId = null
}
}
@@ -7,6 +7,7 @@ import com.m57.hermescontrol.data.local.AuthManager
import com.m57.hermescontrol.data.remote.DashboardSessionTokenRefresher
import com.m57.hermescontrol.data.remote.NetworkMonitor
import com.m57.hermescontrol.data.remote.OkHttpProvider
import com.m57.hermescontrol.data.session.ActiveSessionHolder
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -452,6 +453,7 @@ object HermesWsClient {
/** Cleanly close the WebSocket and stop auto-reconnect. */
fun disconnect(clearPendingMessages: Boolean = false) {
ActiveSessionHolder.clear()
synchronized(outboundLock) {
intentionalClose.set(true)
acceptQueuedMessages.set(!clearPendingMessages)
@@ -885,6 +887,7 @@ object HermesWsClient {
// reason is still inspected internally to detect auth failures.
Log.i(TAG, "WebSocket closed: $code")
connected.set(false)
ActiveSessionHolder.clear()
stopHealthTracking()
if (code == 4001 || code == 4401 ||
reason.contains("unauthorized", ignoreCase = true) ||
@@ -915,6 +918,7 @@ object HermesWsClient {
// detection.
Log.e(TAG, "WebSocket failure: ${t.javaClass.simpleName}", t)
connected.set(false)
ActiveSessionHolder.clear()
stopHealthTracking()
val code = response?.code ?: 0
if (code == 401 || t.message?.contains(