refactor: move api request logic completely out of core
This commit is contained in:
parent
f606eb2e33
commit
0a5b0f532a
5 changed files with 74 additions and 57 deletions
|
|
@ -11,6 +11,8 @@ import io.ktor.client.plugins.plugin
|
||||||
import io.ktor.client.plugins.websocket.WebSockets
|
import io.ktor.client.plugins.websocket.WebSockets
|
||||||
import io.ktor.client.request.header
|
import io.ktor.client.request.header
|
||||||
import io.ktor.client.statement.bodyAsText
|
import io.ktor.client.statement.bodyAsText
|
||||||
|
import io.ktor.http.ContentType
|
||||||
|
import io.ktor.http.contentType
|
||||||
import io.ktor.http.userAgent
|
import io.ktor.http.userAgent
|
||||||
import io.ktor.serialization.kotlinx.json.json
|
import io.ktor.serialization.kotlinx.json.json
|
||||||
import io.ktor.util.appendAll
|
import io.ktor.util.appendAll
|
||||||
|
|
@ -28,7 +30,7 @@ class ApiClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
val client = HttpClient {
|
internal val client = HttpClient {
|
||||||
expectSuccess = true
|
expectSuccess = true
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
json(ApiConstants.json)
|
json(ApiConstants.json)
|
||||||
|
|
@ -37,6 +39,7 @@ class ApiClient {
|
||||||
install(HttpCookies)
|
install(HttpCookies)
|
||||||
defaultRequest {
|
defaultRequest {
|
||||||
url("https://discord.com/api/v9/")
|
url("https://discord.com/api/v9/")
|
||||||
|
contentType(ContentType.Application.Json)
|
||||||
userAgent(ApiConstants.userAgent)
|
userAgent(ApiConstants.userAgent)
|
||||||
headers.appendAll(ApiConstants.baseHeaders)
|
headers.appendAll(ApiConstants.baseHeaders)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package moe.lava.neon.api.endpoints
|
||||||
|
|
||||||
|
import io.ktor.client.call.body
|
||||||
|
import io.ktor.client.request.get
|
||||||
|
import io.ktor.client.request.header
|
||||||
|
import io.ktor.client.request.parameter
|
||||||
|
import io.ktor.client.request.post
|
||||||
|
import io.ktor.client.request.setBody
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import moe.lava.neon.api.ApiClient
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ExperimentResponse(
|
||||||
|
val fingerprint: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
private data class LoginRequest(
|
||||||
|
val login: String,
|
||||||
|
val password: String,
|
||||||
|
val undelete: Boolean = false,
|
||||||
|
val loginSource: String? = null,
|
||||||
|
val giftCodeSkuId: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class LoginResponse(
|
||||||
|
val userId: String,
|
||||||
|
val token: String,
|
||||||
|
val userSettings: UserSettings,
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
data class UserSettings(val locale: String, val theme: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun ApiClient.getExperiments() = client.get("experiments") {
|
||||||
|
parameter("with_guild_experiments", "true")
|
||||||
|
}.body<ExperimentResponse>()
|
||||||
|
|
||||||
|
suspend fun ApiClient.login(email: String, password: String, fingerprint: String) = client.post("auth/login") {
|
||||||
|
header("X-Fingerprint", fingerprint)
|
||||||
|
setBody(LoginRequest(
|
||||||
|
login = email,
|
||||||
|
password = password,
|
||||||
|
))
|
||||||
|
}.body<LoginResponse>()
|
||||||
|
|
@ -21,8 +21,6 @@ kotlin {
|
||||||
implementation(project(":api:gateway"))
|
implementation(project(":api:gateway"))
|
||||||
implementation(project(":api:rest"))
|
implementation(project(":api:rest"))
|
||||||
implementation(project(":common"))
|
implementation(project(":common"))
|
||||||
implementation(libs.ktor.client.core)
|
|
||||||
implementation(libs.ktor.serialization.kotlinx.json)
|
|
||||||
|
|
||||||
implementation(project.dependencies.platform(libs.koin.bom))
|
implementation(project.dependencies.platform(libs.koin.bom))
|
||||||
implementation(libs.koin.core)
|
implementation(libs.koin.core)
|
||||||
|
|
|
||||||
|
|
@ -1,43 +1,14 @@
|
||||||
package moe.lava.neon.core.repository
|
package moe.lava.neon.core.repository
|
||||||
|
|
||||||
import co.touchlab.kermit.Logger
|
import co.touchlab.kermit.Logger
|
||||||
import io.ktor.client.call.body
|
|
||||||
import io.ktor.client.request.get
|
|
||||||
import io.ktor.client.request.header
|
|
||||||
import io.ktor.client.request.parameter
|
|
||||||
import io.ktor.client.request.post
|
|
||||||
import io.ktor.client.request.setBody
|
|
||||||
import io.ktor.http.ContentType
|
|
||||||
import io.ktor.http.contentType
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import moe.lava.neon.api.ApiClient
|
import moe.lava.neon.api.ApiClient
|
||||||
|
import moe.lava.neon.api.endpoints.getExperiments
|
||||||
|
import moe.lava.neon.api.endpoints.login
|
||||||
import moe.lava.neon.core.AppSettings
|
import moe.lava.neon.core.AppSettings
|
||||||
|
|
||||||
@Serializable
|
|
||||||
private data class ExperimentResponse(
|
|
||||||
val fingerprint: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
private data class LoginRequest(
|
|
||||||
val login: String,
|
|
||||||
val password: String,
|
|
||||||
val undelete: Boolean = false,
|
|
||||||
val loginSource: String? = null,
|
|
||||||
val giftCodeSkuId: String? = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
private data class LoginResponse(
|
|
||||||
val userId: String,
|
|
||||||
val token: String,
|
|
||||||
val userSettings: UserSettings,
|
|
||||||
) {
|
|
||||||
@Serializable
|
|
||||||
data class UserSettings(val locale: String, val theme: String)
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class AuthResponse {
|
sealed class AuthResponse {
|
||||||
|
// TODO: Specify all possible error types here
|
||||||
|
data class Failed(val error: Throwable) : AuthResponse()
|
||||||
data class Success(val token: String) : AuthResponse()
|
data class Success(val token: String) : AuthResponse()
|
||||||
// TODO
|
// TODO
|
||||||
// data class MFARequested() : AuthResponse()
|
// data class MFARequested() : AuthResponse()
|
||||||
|
|
@ -57,24 +28,23 @@ class AuthRepository internal constructor(
|
||||||
email: String,
|
email: String,
|
||||||
password: String,
|
password: String,
|
||||||
): AuthResponse {
|
): AuthResponse {
|
||||||
if (fingerprint == null) {
|
try {
|
||||||
fingerprint = api.client.get("experiments") {
|
if (fingerprint == null) {
|
||||||
parameter("with_guild_experiments", "true")
|
fingerprint = api.getExperiments().fingerprint
|
||||||
}.body<ExperimentResponse>().fingerprint
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val res = api.client.post("auth/login") {
|
val login = api.login(
|
||||||
header("X-Fingerprint", fingerprint)
|
email = email,
|
||||||
contentType(ContentType.Application.Json)
|
|
||||||
setBody(LoginRequest(
|
|
||||||
login = email,
|
|
||||||
password = password,
|
password = password,
|
||||||
))
|
fingerprint = fingerprint!!,
|
||||||
|
)
|
||||||
|
logger.i { "Login success $login" }
|
||||||
|
this.token = login.token
|
||||||
|
|
||||||
|
return AuthResponse.Success(login.token)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
return AuthResponse.Failed(e)
|
||||||
}
|
}
|
||||||
val body = res.body<LoginResponse>()
|
|
||||||
logger.i { "Login success $body" }
|
|
||||||
this.token = body.token
|
|
||||||
return AuthResponse.Success(body.token)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun login(token: String): String {
|
fun login(token: String): String {
|
||||||
|
|
|
||||||
|
|
@ -122,13 +122,13 @@ class LoginViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun login(email: String, password: String): LoginResult {
|
suspend fun login(email: String, password: String): LoginResult {
|
||||||
return try {
|
return when (val res = auth.login(email, password)) {
|
||||||
when (val res = auth.login(email, password)) {
|
is AuthResponse.Success -> LoginResult.Success
|
||||||
is AuthResponse.Success -> LoginResult.Success
|
is AuthResponse.Failed -> {
|
||||||
|
val e = res.error
|
||||||
|
logger.e(e) { "Login failed" }
|
||||||
|
LoginResult.Failed(e.toString())
|
||||||
}
|
}
|
||||||
} catch(e: Throwable) {
|
|
||||||
logger.e(e) { "Login failed" }
|
|
||||||
LoginResult.Failed(e.toString())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue