This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
suspend fun <T> synchronized(block: suspend () -> T): T { | |
val thisJobId = id.getAndIncrement() | |
while (isInsideCriticalSection) { | |
suspendCoroutine { cont -> // <-- suspending call | |
suspendedJobs[thisJobId] = cont | |
} | |
suspendedJobs.remove(thisJobId) | |
} | |
... | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fun obtainAccessToken(): String { | |
val kCriticalSection = DI.get<KCriticalSection>(qualifier = "shared") | |
val singleThread = DI.get<CoroutineDispatcher>(qualifier = "shared") | |
return runBlocking(singleThread) { | |
kCriticalSection.synchronized { | |
val accessToken = readAccessTokenFromStorageOrMemory() // might be a suspending call | |
if (accessToken != null && System.currentTimeMillis() < accessToken.createdAt + accessToken.expiresIn) { | |
return@synchronized accessToken.toString() // access token is valid |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
if (accessToken != null && System.currentTimeMillis() < accessToken.createdAt + accessToken.expiresIn) { | |
return@synchronized accessToken.toString() // access token is valid | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.concurrent.ConcurrentHashMap | |
import kotlin.coroutines.Continuation | |
import kotlin.coroutines.resume | |
import kotlin.coroutines.suspendCoroutine | |
class KCriticalSection { | |
private val suspendedJobs = ConcurrentHashMap<Int, Continuation<Boolean>>() | |
private var id = AtomicInteger(1000) | |
@Volatile private var isInsideCriticalSection = false |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
suspend fun obtainAccessToken(): String = | |
KCriticalSection().synchronized { | |
val accessToken = readAccessTokenFromStorageOrMemory() // might be a suspending call | |
if (accessToken != null && System.currentTimeMillis() < accessToken.createdAt + accessToken.expiresIn) { | |
return@synchronized accessToken.toString() // access token is valid | |
} | |
val refreshToken = readRefreshTokenFromSecureStorage() // normally a suspending call |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
suspend fun obtainAccessToken(): String { | |
val accessToken = readAccessTokenFromStorageOrMemory() // might be a suspending call | |
if (accessToken != null && System.currentTimeMillis() < accessToken.createdAt + accessToken.expiresIn) { | |
return accessToken.toString() // access token is valid | |
} | |
val refreshToken = readRefreshTokenFromSecureStorage() // normally a suspending call | |
// normally suspending as it makes another API call |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
suspend fun obtainAccessToken(): String { | |
// do the real job to obtain access token | |
return "access token" | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import kotlinx.coroutines.runBlocking | |
import okhttp3.Interceptor | |
import okhttp3.Response | |
class AuthInterceptor : Interceptor { | |
override fun intercept(chain: Interceptor.Chain): Response { | |
val accessToken = runBlocking { obtainAccessToken() } | |
val request = chain.request() | |
val newRequest = request.newBuilder() | |
.addHeader("Authorization", accessToken) |
NewerOlder