PixelDroid-App-Android/app/src/main/java/org/pixeldroid/app/utils/di/APIModule.kt

95 lines
3.0 KiB
Kotlin

package org.pixeldroid.app.utils.di
import org.pixeldroid.app.utils.api.PixelfedAPI
import org.pixeldroid.app.utils.api.objects.Token
import org.pixeldroid.app.utils.db.AppDatabase
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.runBlocking
import okhttp3.*
import org.pixeldroid.app.utils.api.PixelfedAPI.Companion.apiForUser
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
class APIModule {
@Provides
@Singleton
fun providesAPIHolder(db: AppDatabase): PixelfedAPIHolder {
return PixelfedAPIHolder(db)
}
}
class TokenAuthenticator(val user: UserDatabaseEntity, val db: AppDatabase, val apiHolder: PixelfedAPIHolder) : Authenticator {
private val pixelfedAPI = PixelfedAPI.createFromUrl(user.instance_uri)
// Returns the number of tries for this response by walking through the priorResponses
private fun Response.responseCount(): Int {
var result = 1
var response: Response? = priorResponse
while (response != null) {
result++
response = response.priorResponse
}
return result
}
override fun authenticate(route: Route?, response: Response): Request? {
if (response.responseCount() > 3) {
return null // Give up, we've already failed to authenticate a couple times
}
// Refresh the access_token using a synchronous api request
val newAccessToken: Token = try {
runBlocking {
pixelfedAPI.obtainToken(
scope = "",
grant_type = "refresh_token",
refresh_token = user.refreshToken,
client_id = user.clientId,
client_secret = user.clientSecret
)
}
} catch (e: Exception){
return null
}
// Save the new access token and refresh token
if (newAccessToken.access_token != null && newAccessToken.refresh_token != null) {
db.userDao().updateAccessToken(
newAccessToken.access_token,
newAccessToken.refresh_token,
user.user_id, user.instance_uri
)
apiHolder.setToCurrentUser()
}
// Add new header to rejected request and retry it
return response.request.newBuilder()
.header("Authorization", "Bearer ${newAccessToken.access_token.orEmpty()}")
.build()
}
}
class PixelfedAPIHolder(private val db: AppDatabase){
var api: PixelfedAPI? =
db.userDao().getActiveUser()?.let {
setToCurrentUser(it)
}
fun setToCurrentUser(
user: UserDatabaseEntity = db.userDao().getActiveUser()!!
): PixelfedAPI {
val newAPI = apiForUser(user, db, this)
api = newAPI
return newAPI
}
}