From 793b88b9b982d8b5ed9618ac7a178d3881a2c7c4 Mon Sep 17 00:00:00 2001
From: Taras Smakula <tarassmakula@gmail.com>
Date: Fri, 15 Dec 2023 14:10:27 +0200
Subject: [PATCH] Try to refresh on invalid token callback

---
 app/src/main/java/org/futo/circles/App.kt     |  4 ++-
 .../auth/feature/token/RefreshTokenManager.kt | 30 +++++++++----------
 .../auth/feature/token/RefreshTokenWorker.kt  | 10 +++++--
 .../provider/MatrixSessionListenerProvider.kt | 28 ++++++++++++++---
 4 files changed, 50 insertions(+), 22 deletions(-)

diff --git a/app/src/main/java/org/futo/circles/App.kt b/app/src/main/java/org/futo/circles/App.kt
index f43399085..0685db4f8 100644
--- a/app/src/main/java/org/futo/circles/App.kt
+++ b/app/src/main/java/org/futo/circles/App.kt
@@ -9,6 +9,7 @@ import com.vanniktech.emoji.google.GoogleEmojiProvider
 import dagger.hilt.android.HiltAndroidApp
 import org.futo.circles.core.base.CirclesAppConfig
 import org.futo.circles.core.base.NetworkObserver
+import org.futo.circles.core.feature.ErrorLogger
 import org.futo.circles.core.provider.MatrixNotificationSetupListener
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.futo.circles.feature.notifications.FcmHelper
@@ -20,6 +21,7 @@ import org.matrix.android.sdk.api.session.Session
 import timber.log.Timber
 import javax.inject.Inject
 
+
 @HiltAndroidApp
 class App : Application() {
 
@@ -37,6 +39,7 @@ class App : Application() {
 
     override fun onCreate() {
         super.onCreate()
+        ErrorLogger.appendLog("App start")
         NetworkObserver.register(applicationContext)
         CirclesAppConfig.Initializer()
             .buildConfigInfo(
@@ -67,7 +70,6 @@ class App : Application() {
         notificationUtils.createNotificationChannels()
         setupLifecycleObserver()
         if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree())
-
     }
 
     private fun setupLifecycleObserver() {
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/token/RefreshTokenManager.kt b/auth/src/main/java/org/futo/circles/auth/feature/token/RefreshTokenManager.kt
index ef14c6f28..277c50b2e 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/token/RefreshTokenManager.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/token/RefreshTokenManager.kt
@@ -5,16 +5,16 @@ import androidx.work.Constraints
 import androidx.work.Data
 import androidx.work.ExistingPeriodicWorkPolicy
 import androidx.work.NetworkType
-import androidx.work.PeriodicWorkRequest.Companion.MIN_PERIODIC_FLEX_MILLIS
 import androidx.work.PeriodicWorkRequest.Companion.MIN_PERIODIC_INTERVAL_MILLIS
 import androidx.work.PeriodicWorkRequestBuilder
 import androidx.work.WorkManager
 import dagger.hilt.android.qualifiers.ApplicationContext
+import org.futo.circles.core.feature.ErrorLogger
 import org.matrix.android.sdk.api.auth.data.sessionId
 import org.matrix.android.sdk.api.session.Session
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
-import kotlin.math.max
+import kotlin.math.roundToLong
 
 class RefreshTokenManager @Inject constructor(
     @ApplicationContext val context: Context
@@ -22,7 +22,7 @@ class RefreshTokenManager @Inject constructor(
 
     fun scheduleTokenRefreshIfNeeded(session: Session) {
         val credentials = session.sessionParams.credentials
-        val expireTime = credentials.expiresInMs ?: return
+        val expireTime = ((credentials.expiresInMs ?: 0) * 0.7).roundToLong()
         if (credentials.refreshToken.isNullOrEmpty()) return
         if (expireTime < MIN_PERIODIC_INTERVAL_MILLIS) return
 
@@ -30,23 +30,22 @@ class RefreshTokenManager @Inject constructor(
             .putString(RefreshTokenWorker.SESSION_ID_PARAM_KEY, credentials.sessionId())
             .build()
 
-        val flex = max(expireTime / 3, MIN_PERIODIC_FLEX_MILLIS)
-
-        val refreshRequest = PeriodicWorkRequestBuilder<RefreshTokenWorker>(
-            expireTime, TimeUnit.MILLISECONDS,
-            flex, TimeUnit.MILLISECONDS
-        )
-            .setConstraints(
-                Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
-            )
-            .setInputData(sessionIdData)
-            .build()
+        val refreshRequest =
+            PeriodicWorkRequestBuilder<RefreshTokenWorker>(expireTime, TimeUnit.MILLISECONDS)
+                .setConstraints(
+                    Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
+                )
+                .setInputData(sessionIdData)
+                .build()
 
         WorkManager.getInstance(context).enqueueUniquePeriodicWork(
             credentials.sessionId(),
-            ExistingPeriodicWorkPolicy.UPDATE,
+            ExistingPeriodicWorkPolicy.KEEP,
             refreshRequest
         )
+        ErrorLogger.appendLog(
+            "scheduled sessionId ${credentials.sessionId()}, expireTime $expireTime"
+        )
     }
 
     fun cancelTokenRefreshing(session: Session) {
@@ -55,6 +54,7 @@ class RefreshTokenManager @Inject constructor(
     }
 
     fun cancelTokenRefreshingById(credentialsSessionId: String) {
+        ErrorLogger.appendLog("$credentialsSessionId canceled")
         WorkManager.getInstance(context).cancelUniqueWork(credentialsSessionId)
     }
 
diff --git a/auth/src/main/java/org/futo/circles/auth/feature/token/RefreshTokenWorker.kt b/auth/src/main/java/org/futo/circles/auth/feature/token/RefreshTokenWorker.kt
index a5d322858..bb47ed485 100644
--- a/auth/src/main/java/org/futo/circles/auth/feature/token/RefreshTokenWorker.kt
+++ b/auth/src/main/java/org/futo/circles/auth/feature/token/RefreshTokenWorker.kt
@@ -9,6 +9,7 @@ import dagger.assisted.Assisted
 import dagger.assisted.AssistedInject
 import org.futo.circles.core.extensions.Response
 import org.futo.circles.core.extensions.createResult
+import org.futo.circles.core.feature.ErrorLogger
 import org.futo.circles.core.provider.MatrixInstanceProvider
 
 @HiltWorker
@@ -18,13 +19,18 @@ class RefreshTokenWorker @AssistedInject constructor(
 ) : CoroutineWorker(context, params) {
 
     override suspend fun doWork(): Result {
+        ErrorLogger.appendLog("worker start")
         val sessionId = params.inputData.getString(SESSION_ID_PARAM_KEY) ?: run {
             WorkManager.getInstance(context).cancelWorkById(this.id)
             return Result.failure()
         }
+        ErrorLogger.appendLog("sessionId $sessionId")
         val result = refreshToken(sessionId)
-        return if (result is Response.Success) Result.success()
-        else {
+        return if (result is Response.Success) {
+            ErrorLogger.appendLog("worker success")
+            Result.success()
+        } else {
+            ErrorLogger.appendLog("worker failure")
             WorkManager.getInstance(context).cancelWorkById(this.id)
             Result.failure()
         }
diff --git a/core/src/main/java/org/futo/circles/core/provider/MatrixSessionListenerProvider.kt b/core/src/main/java/org/futo/circles/core/provider/MatrixSessionListenerProvider.kt
index 9ddcec3fe..54fe389af 100644
--- a/core/src/main/java/org/futo/circles/core/provider/MatrixSessionListenerProvider.kt
+++ b/core/src/main/java/org/futo/circles/core/provider/MatrixSessionListenerProvider.kt
@@ -1,5 +1,13 @@
 package org.futo.circles.core.provider
 
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import org.futo.circles.core.extensions.Response
+import org.futo.circles.core.extensions.coroutineScope
+import org.futo.circles.core.extensions.createResult
+import org.futo.circles.core.feature.ErrorLogger
+import org.matrix.android.sdk.api.auth.data.sessionId
 import org.matrix.android.sdk.api.failure.GlobalError
 import org.matrix.android.sdk.api.session.Session
 
@@ -10,11 +18,23 @@ object MatrixSessionListenerProvider {
 
     val sessionListener: Session.Listener = object : Session.Listener {
         override fun onGlobalError(session: Session, globalError: GlobalError) {
-            if (globalError is GlobalError.InvalidToken) {
-                onInvalidToken?.invoke(globalError)
-                onInvalidToken = null
+            if (globalError !is GlobalError.InvalidToken) return
+
+            session.coroutineScope.launch(Dispatchers.IO) {
+                ErrorLogger.appendLog("manual refresh")
+                val refreshResult = createResult {
+                    MatrixInstanceProvider.matrix.authenticationService()
+                        .refreshToken(session.sessionParams.credentials.sessionId())
+                }
+
+                if (refreshResult is Response.Error) {
+                    ErrorLogger.appendLog("invalid token")
+                    withContext(Dispatchers.Main) {
+                        onInvalidToken?.invoke(globalError)
+                        onInvalidToken = null
+                    }
+                }
             }
-
         }
     }
 
-- 
GitLab