Skip to content

Commit 88367b6

Browse files
authored
Move rescope token request to IO thread (#7869)
Task/Issue URL: https://app.asana.com/1/137249556945/project/608920331025315/task/1213530835574684?focus=true ### Description Moves the network request that happens in `GetScopedSyncAuthTokenHandler` to an `io` thread instead of trying to do it on the `java bridge` thread (which is for JS->Native comms). ### Steps to test this PR - QA optional <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Moves token rescoping into an injected app-level coroutine on the IO dispatcher, introducing async behavior that could affect response timing/cancellation and test determinism if dispatchers/scopes are misconfigured. > > **Overview** > `GetScopedSyncAuthTokenHandler` now performs `syncApi.rescopeToken` asynchronously by launching on an injected `@AppCoroutineScope` with `dispatcherProvider.io()`, instead of executing inline on the message handler thread. > > Tests are updated to inject a `CoroutineTestRule` test scope/dispatcher provider so the new coroutine-based behavior remains verifiable while keeping the existing success/error response and pixel assertions intact. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 389af64. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Craig Russell <[email protected]>
1 parent cf56e35 commit 88367b6

File tree

2 files changed

+22
-7
lines changed

2 files changed

+22
-7
lines changed

sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/messaging/GetScopedSyncAuthTokenHandler.kt

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
package com.duckduckgo.sync.impl.messaging
1818

19+
import com.duckduckgo.app.di.AppCoroutineScope
1920
import com.duckduckgo.common.utils.AppUrl
21+
import com.duckduckgo.common.utils.DispatcherProvider
2022
import com.duckduckgo.contentscopescripts.api.ContentScopeJsMessageHandlersPlugin
2123
import com.duckduckgo.di.scopes.AppScope
2224
import com.duckduckgo.js.messaging.api.JsCallbackData
@@ -31,6 +33,8 @@ import com.duckduckgo.sync.impl.SyncApi
3133
import com.duckduckgo.sync.impl.pixels.SyncPixels
3234
import com.duckduckgo.sync.store.SyncStore
3335
import com.squareup.anvil.annotations.ContributesMultibinding
36+
import kotlinx.coroutines.CoroutineScope
37+
import kotlinx.coroutines.launch
3438
import logcat.LogPriority
3539
import logcat.logcat
3640
import org.json.JSONObject
@@ -42,6 +46,8 @@ class GetScopedSyncAuthTokenHandler @Inject constructor(
4246
private val syncStore: SyncStore,
4347
private val deviceSyncState: DeviceSyncState,
4448
private val syncPixels: SyncPixels,
49+
@AppCoroutineScope private val appCoroutineScope: CoroutineScope,
50+
private val dispatcherProvider: DispatcherProvider,
4551
) : ContentScopeJsMessageHandlersPlugin {
4652
override fun getJsMessageHandler(): JsMessageHandler =
4753
object : JsMessageHandler {
@@ -70,14 +76,16 @@ class GetScopedSyncAuthTokenHandler @Inject constructor(
7076
return
7177
}
7278

73-
val jsonPayload = runCatching {
74-
handleRescopeTokenResult(syncApi.rescopeToken(token, SCOPE))
75-
}.getOrElse { e ->
76-
logcat(LogPriority.ERROR) { "DuckChat-Sync: exception during rescope token: ${e.message}" }
77-
createErrorPayload("internal error")
78-
}
79+
appCoroutineScope.launch(dispatcherProvider.io()) {
80+
val jsonPayload = runCatching {
81+
handleRescopeTokenResult(syncApi.rescopeToken(token, SCOPE))
82+
}.getOrElse { e ->
83+
logcat(LogPriority.ERROR) { "DuckChat-Sync: exception during rescope token: ${e.message}" }
84+
createErrorPayload("internal error")
85+
}
7986

80-
sendResponse(jsMessaging, jsMessage, jsonPayload)
87+
sendResponse(jsMessaging, jsMessage, jsonPayload)
88+
}
8189
}
8290

8391
private fun handleRescopeTokenResult(result: Result<String>): JSONObject {

sync/sync-impl/src/test/java/com/duckduckgo/sync/impl/messaging/GetScopedSyncAuthTokenHandlerTest.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.duckduckgo.sync.impl.messaging
1818

1919
import androidx.test.ext.junit.runners.AndroidJUnit4
20+
import com.duckduckgo.common.test.CoroutineTestRule
2021
import com.duckduckgo.js.messaging.api.JsCallbackData
2122
import com.duckduckgo.js.messaging.api.JsMessage
2223
import com.duckduckgo.js.messaging.api.JsMessaging
@@ -30,6 +31,7 @@ import org.junit.Assert.assertEquals
3031
import org.junit.Assert.assertFalse
3132
import org.junit.Assert.assertTrue
3233
import org.junit.Before
34+
import org.junit.Rule
3335
import org.junit.Test
3436
import org.junit.runner.RunWith
3537
import org.mockito.kotlin.argumentCaptor
@@ -41,6 +43,9 @@ import org.mockito.kotlin.whenever
4143
@RunWith(AndroidJUnit4::class)
4244
class GetScopedSyncAuthTokenHandlerTest {
4345

46+
@get:Rule
47+
val coroutineTestRule: CoroutineTestRule = CoroutineTestRule()
48+
4449
private val mockSyncApi: SyncApi = mock()
4550
private val mockSyncStore: SyncStore = mock()
4651
private val mockDeviceSyncState: DeviceSyncState = mock()
@@ -58,6 +63,8 @@ class GetScopedSyncAuthTokenHandlerTest {
5863
syncStore = mockSyncStore,
5964
deviceSyncState = mockDeviceSyncState,
6065
syncPixels = mockSyncPixels,
66+
appCoroutineScope = coroutineTestRule.testScope,
67+
dispatcherProvider = coroutineTestRule.testDispatcherProvider,
6168
)
6269
}
6370

0 commit comments

Comments
 (0)