Try mitigating unexpected logouts (#2251)
* Try mitigating unexpected logouts. Try making getting/storing session data use a Mutex for synchronization. Also added some more logs so we can understand exactly where it's failing.
This commit is contained in:
parent
e6d2e1af72
commit
b755a2584b
3 changed files with 45 additions and 15 deletions
3
changelog.d/+try-mitigating-unexpected-logouts.misc
Normal file
3
changelog.d/+try-mitigating-unexpected-logouts.misc
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
Try mitigating unexpected logouts by making getting/storing session data use a Mutex for synchronization.
|
||||||
|
|
||||||
|
Also added some more logs so we can understand exactly where it's failing.
|
||||||
|
|
@ -139,6 +139,8 @@ class RustMatrixClient(
|
||||||
// TODO handle isSoftLogout parameter.
|
// TODO handle isSoftLogout parameter.
|
||||||
appCoroutineScope.launch {
|
appCoroutineScope.launch {
|
||||||
val existingData = sessionStore.getSession(client.userId())
|
val existingData = sessionStore.getSession(client.userId())
|
||||||
|
val anonymizedToken = existingData?.accessToken?.takeLast(4)
|
||||||
|
Timber.d("Removing session data with token: '...$anonymizedToken'.")
|
||||||
if (existingData != null) {
|
if (existingData != null) {
|
||||||
// Set isTokenValid to false
|
// Set isTokenValid to false
|
||||||
val newData = client.session().toSessionData(
|
val newData = client.session().toSessionData(
|
||||||
|
|
@ -146,8 +148,15 @@ class RustMatrixClient(
|
||||||
loginType = existingData.loginType,
|
loginType = existingData.loginType,
|
||||||
)
|
)
|
||||||
sessionStore.updateData(newData)
|
sessionStore.updateData(newData)
|
||||||
|
Timber.d("Removed session data with token: '...$anonymizedToken'.")
|
||||||
|
} else {
|
||||||
|
Timber.d("No session data found.")
|
||||||
}
|
}
|
||||||
doLogout(doRequest = false, removeSession = false, ignoreSdkError = false)
|
doLogout(doRequest = false, removeSession = false, ignoreSdkError = false)
|
||||||
|
}.invokeOnCompletion {
|
||||||
|
if (it != null) {
|
||||||
|
Timber.e(it, "Failed to remove session data.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timber.v("didReceiveAuthError -> already cleaning up")
|
Timber.v("didReceiveAuthError -> already cleaning up")
|
||||||
|
|
@ -158,11 +167,18 @@ class RustMatrixClient(
|
||||||
Timber.w("didRefreshTokens()")
|
Timber.w("didRefreshTokens()")
|
||||||
appCoroutineScope.launch {
|
appCoroutineScope.launch {
|
||||||
val existingData = sessionStore.getSession(client.userId()) ?: return@launch
|
val existingData = sessionStore.getSession(client.userId()) ?: return@launch
|
||||||
|
val anonymizedToken = client.session().accessToken.takeLast(4)
|
||||||
|
Timber.d("Saving new session data with token: '...$anonymizedToken'. Was token valid: ${existingData.isTokenValid}")
|
||||||
val newData = client.session().toSessionData(
|
val newData = client.session().toSessionData(
|
||||||
isTokenValid = existingData.isTokenValid,
|
isTokenValid = true,
|
||||||
loginType = existingData.loginType,
|
loginType = existingData.loginType,
|
||||||
)
|
)
|
||||||
sessionStore.updateData(newData)
|
sessionStore.updateData(newData)
|
||||||
|
Timber.d("Saved new session data with token: '...$anonymizedToken'.")
|
||||||
|
}.invokeOnCompletion {
|
||||||
|
if (it != null) {
|
||||||
|
Timber.e(it, "Failed to save new session data.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@ import io.element.android.libraries.sessionstorage.api.SessionData
|
||||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
@ -37,6 +39,8 @@ class DatabaseSessionStore @Inject constructor(
|
||||||
private val database: SessionDatabase,
|
private val database: SessionDatabase,
|
||||||
private val dispatchers: CoroutineDispatchers,
|
private val dispatchers: CoroutineDispatchers,
|
||||||
) : SessionStore {
|
) : SessionStore {
|
||||||
|
private val sessionDataMutex = Mutex()
|
||||||
|
|
||||||
override fun isLoggedIn(): Flow<LoggedInState> {
|
override fun isLoggedIn(): Flow<LoggedInState> {
|
||||||
return database.sessionDataQueries.selectFirst()
|
return database.sessionDataQueries.selectFirst()
|
||||||
.asFlow()
|
.asFlow()
|
||||||
|
|
@ -53,11 +57,11 @@ class DatabaseSessionStore @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun storeData(sessionData: SessionData) {
|
override suspend fun storeData(sessionData: SessionData) = sessionDataMutex.withLock {
|
||||||
database.sessionDataQueries.insertSessionData(sessionData.toDbModel())
|
database.sessionDataQueries.insertSessionData(sessionData.toDbModel())
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun updateData(sessionData: SessionData) {
|
override suspend fun updateData(sessionData: SessionData) = sessionDataMutex.withLock {
|
||||||
val result = database.sessionDataQueries.selectByUserId(sessionData.userId)
|
val result = database.sessionDataQueries.selectByUserId(sessionData.userId)
|
||||||
.executeAsOneOrNull()
|
.executeAsOneOrNull()
|
||||||
?.toApiModel()
|
?.toApiModel()
|
||||||
|
|
@ -66,8 +70,7 @@ class DatabaseSessionStore @Inject constructor(
|
||||||
Timber.e("User ${sessionData.userId} not found in session database")
|
Timber.e("User ${sessionData.userId} not found in session database")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Copy new data from SDK, but keep login timestamp
|
||||||
// Copy new data from SDK, but keep login timestamp
|
|
||||||
database.sessionDataQueries.updateSession(
|
database.sessionDataQueries.updateSession(
|
||||||
sessionData.copy(
|
sessionData.copy(
|
||||||
loginTimestamp = result.loginTimestamp,
|
loginTimestamp = result.loginTimestamp,
|
||||||
|
|
@ -76,21 +79,27 @@ class DatabaseSessionStore @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getLatestSession(): SessionData? {
|
override suspend fun getLatestSession(): SessionData? {
|
||||||
return database.sessionDataQueries.selectFirst()
|
return sessionDataMutex.withLock {
|
||||||
.executeAsOneOrNull()
|
database.sessionDataQueries.selectFirst()
|
||||||
?.toApiModel()
|
.executeAsOneOrNull()
|
||||||
|
?.toApiModel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getSession(sessionId: String): SessionData? {
|
override suspend fun getSession(sessionId: String): SessionData? {
|
||||||
return database.sessionDataQueries.selectByUserId(sessionId)
|
return sessionDataMutex.withLock {
|
||||||
.executeAsOneOrNull()
|
database.sessionDataQueries.selectByUserId(sessionId)
|
||||||
?.toApiModel()
|
.executeAsOneOrNull()
|
||||||
|
?.toApiModel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getAllSessions(): List<SessionData> {
|
override suspend fun getAllSessions(): List<SessionData> {
|
||||||
return database.sessionDataQueries.selectAll()
|
return sessionDataMutex.withLock {
|
||||||
.executeAsList()
|
database.sessionDataQueries.selectAll()
|
||||||
.map { it.toApiModel() }
|
.executeAsList()
|
||||||
|
.map { it.toApiModel() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sessionsFlow(): Flow<List<SessionData>> {
|
override fun sessionsFlow(): Flow<List<SessionData>> {
|
||||||
|
|
@ -102,6 +111,8 @@ class DatabaseSessionStore @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun removeSession(sessionId: String) {
|
override suspend fun removeSession(sessionId: String) {
|
||||||
database.sessionDataQueries.removeSession(sessionId)
|
sessionDataMutex.withLock {
|
||||||
|
database.sessionDataQueries.removeSession(sessionId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue