Parallel request with Retrofit, Coroutines and Suspend functions any request 401 after we call refresh token, update access token then call same req

214 views Asked by At

Parallel request with Retrofit, Coroutines and Suspend functions any request 401 after we call refresh token, update access token then call the same request again,

class ServiceInterceptor() : Interceptor {
    fun getSharedPreferences(): SharedPreferences {
        return PreferenceHelper.customPrefs(TelioEVApp.appContext, "SHARED_DB")
    }
    private fun getAccessToken(): String? {
        val sharedPreferences = PreferenceHelper.customPrefs(TelioEVApp.appContext, "SHARED_DB")
        val token: String? = sharedPreferences.getString(PREF_ACCESS_TOKEN, "")
        return token?.trim() ?: ""
    }
    override fun intercept(chain: Interceptor.Chain): Response {
     val tokenManager = object : TokenManager {
            val sharedPreferences =
                PreferenceHelper.customPrefs(TelioEVApp.appContext, "SHARED_DB")

            override fun getToken(): String? = getAccessToken()

            override fun hasToken(): Boolean? {
                if (getToken().isNullOrBlank()) {
                    return false
                }
                return true
            }

            override fun clearToken() {

                sharedPreferences.setData(PREF_ACCESS_TOKEN, "")
            }

            override fun refreshToken(): String? {
                val refreshToken: String? =
                    sharedPreferences.getData(Constants.PREF_REFRESH_TOKEN, "")
                val client = RetrofitBuilder.getUnsafeOkHttpClient()
                val params = JSONObject()
                val body: RequestBody = RequestBody.create(
                    "application/json".toMediaTypeOrNull(),
                    params.toString()
                )
                val nRequest = Request.Builder()
                    .post(body)
                    .header("accept", "application/json")
                    .header("X-Device-ID", "ANDROID")
                    .header("Content-Type", "application/json-patch+json")
                    .header("refresh_token", "$refreshToken")
                    .url("${BuildConfig.BASE_URL}${BuildConfig.BASE_PORT}/api/token/refresh")
                    .build()
                val response = client?.newCall(nRequest)?.execute()
                if (response?.code == 200) {
                    // Get response
                    val jsonData = response.body?.string() ?: ""
                    val gson = Gson()
                    val loginResponse: ResponseBodies.LoginResponse = gson.fromJson(
                        jsonData,
                        ResponseBodies.LoginResponse::class.java
                    )
                    if (loginResponse.statusCode == 200) {
                        sharedPreferences.setData(
                            Constants.PREF_ACCESS_TOKEN,
                            loginResponse.body?.accessToken
                        )
                        sharedPreferences.setData(
                            Constants.PREF_REFRESH_TOKEN,
                            loginResponse.body?.refreshToken
                        )

                        sharedPreferences.setData(
                            Constants.PREF_EXPIRES_IN,
                            loginResponse.body?.expireIn
                        )
                        // Add refreshToken expires to shared preferences
                        sharedPreferences.setData(
                            Constants.PREF_REFRESH_TOKEN_EXPIRES,
                            loginResponse.body?.refreshExpireIn
                        )
                        // add user delta time to shared preferences
                        sharedPreferences.setData(
                            Constants.PREF_USER_DELTA_TIME,
                            System.currentTimeMillis() / 1000
                        )
                    } else {
                        val  shareViewModel = ViewModelProvider(TelioEVApp.getInstance()).get(SharedViewModel::class.java)
                        shareViewModel.onLogout(ShareDataBean(1,loginResponse.message?:"Session expired"))
                    }
                }
                return getAccessToken()

            }
        }
        val request = chain.request()
        val apiRequest = request.newBuilder()
            .addHeader("X-Device-ID", "ANDROID")
            .apply {
                if (!getAccessToken().isNullOrBlank())
                    header("Authorization", "Bearer " + getAccessToken())
            }
            .build()
//        request.header("Authorization:Bearer" + getAccessToken())
        val response = chain.proceed(apiRequest)
        var unauthorized = false
        if (response.code == 401 || response.code == 422) {
            response.close()
            unauthorized = true
        }

        if (unauthorized) {
            tokenManager.clearToken() // remove old access token
            tokenManager.refreshToken() // hit new api
            val accessToken : String? = tokenManager.getToken()
            if (!accessToken.isNullOrBlank()) {
                val modifiedRequest = request.newBuilder()
                    .addHeader("X-Device-ID", "ANDROID")
                    .addHeader("Authorization", "Bearer $accessToken")
                    .build()

                return chain.proceed(modifiedRequest)
            }
        }
        return response
    }

}

ServiceInterceptor.kt

    lifecycleScope.launch {
        try {
    
            itemIds.asFlow()
                   .flowOn(Dispatchers.IO) 
                   .collect{ itemId -> itemById[itemId] = MyService.getItem(itemId)}

itemIds.asFlow()
                   .flowOn(Dispatchers.IO) 
                   .collect{ itemId -> itemById[itemId] = MyService.getItem(itemId)}
    
        } catch (exception: Exception) {
            exception.printStackTrace()
        }
    
        Log.i(TAG, "All requests have been executed")
    }

Also please look at the lifecycle scope how to check refresh token call when any API 401 than call same request again

0

There are 0 answers