Kabindra Shrestha
02/13/2025, 10:58 AMKabindra Shrestha
02/13/2025, 12:17 PMval provideHttpClientModule = module {
fun provideHttpClient(
appDatabase: AppDatabase,
tokenProvider: TokenProvider
): HttpClient {
return HttpClient {
install(Logging) {
logger = Logger.SIMPLE
level = LogLevel.ALL
}
install(ContentNegotiation) {
json(
json = Json {
prettyPrint = true
isLenient = true
ignoreUnknownKeys = true
explicitNulls = false
},
contentType = ContentType.Application.Json
)
}
install(HttpTimeout) {
socketTimeoutMillis = 60_000
requestTimeoutMillis = 60_000
}
install(UserAgent) {
agent = getPlatform().userAgent
}
defaultRequest {
runBlocking {
url("baseUrl")
contentType(ContentType.Application.Json)
val platform = getPlatform()
header(HEADER_USER_DEVICE, platform.userDevice + HEADER_USER_DEVICE_KEY)
header(HEADER_USER_DEVICE_PLATFORM, platform.devicePlatform)
header(HEADER_USER_DEVICE_VERSION, platform.deviceVersion)
header(HEADER_USER_DEVICE_BUILD, platform.deviceBuild)
header(HEADER_USER_DEVICE_BRAND, platform.deviceBrand)
header(HEADER_USER_DEVICE_MODEL, platform.deviceModel)
header(HEADER_USER_DEVICE_APP_VERSION, platform.appVersion)
header(HEADER_USER_DEVICE_APP_VERSION_CODE, platform.appVersionCode)
}
}
install(Auth) {
bearer {
loadTokens {
runBlocking {
val accessToken = tokenProvider.getAccessToken()
val refreshToken = tokenProvider.getRefreshToken()
if (accessToken.isNotEmpty() && refreshToken.isNotEmpty()) {
BearerTokens(accessToken, refreshToken)
} else {
tokenProvider.clearTokens()
null
// BearerTokens("", "")
}
}
}
refreshTokens {
runBlocking {
val refreshToken = tokenProvider.getRefreshToken()
if (refreshToken.isNotEmpty()) {
val response: HttpResponse = client.submitForm(
url = ApiEndpoints.API_REFRESH_TOKEN,
formParameters = parameters {
append("refresh_token", refreshToken)
}
) {
markAsRefreshTokenRequest()
}
if (response.status.isSuccess()) {
val responses: RefreshTokenDTO = response.body()
if (getStatus<Status>(responses.status)) {
tokenProvider.updateTokens(
responses.response?.token!!,
responses.response.refresh_token!!
)
BearerTokens(
responses.response.token,
responses.response.refresh_token
)
} else {
tokenProvider.clearTokens()
null
// BearerTokens("", "")
}
} else {
tokenProvider.clearTokens()
null
// BearerTokens("", "")
}
} else {
tokenProvider.clearTokens()
null
// BearerTokens("", "")
}
}
}
sendWithoutRequest { request ->
when (request.url.pathSegments.last()) {
"check-user" -> false
"verify-otp" -> false
else -> true
}
}
}
}
}
}
singleOf(::provideHttpClient)
singleOf(::TokenProvider)
}
class TokenProvider(private val appDatabase: AppDatabase) {
private var accessToken: String? = null
private var refreshToken: String? = null
private val mutex = Mutex()
suspend fun getAccessToken(): String = mutex.withLock {
if (accessToken.isNullOrEmpty()) {
val tokens = appDatabase.apiTokenDao.findAll()
accessToken = tokens.firstOrNull()?.token?.takeIf { it.isNotEmpty() } ?: ""
}
accessToken ?: ""
}
suspend fun getRefreshToken(): String = mutex.withLock {
if (refreshToken.isNullOrEmpty()) {
val tokens = appDatabase.apiTokenDao.findAll()
refreshToken = tokens.firstOrNull()?.refresh_token?.takeIf { it.isNotEmpty() } ?: ""
}
refreshToken ?: ""
}
suspend fun updateTokens(newAccessToken: String, newRefreshToken: String) = mutex.withLock {
accessToken = newAccessToken
refreshToken = newRefreshToken
appDatabase.apiTokenDao.deleteAll() // Clear old tokens if needed
appDatabase.apiTokenDao.add(ApiTokenDTO(newAccessToken, newRefreshToken)) // Add the new one
}
suspend fun clearTokens() = mutex.withLock {
accessToken = ""
refreshToken = ""
appDatabase.apiTokenDao.deleteAll()
}
}
streetsofboston
02/13/2025, 1:00 PM