refactor: split up core into multiple modules
This commit is contained in:
parent
2725342c3f
commit
0d84411f14
38 changed files with 344 additions and 149 deletions
|
|
@ -0,0 +1,81 @@
|
|||
package moe.lava.neon.api
|
||||
|
||||
import co.touchlab.kermit.Logger
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.body
|
||||
import io.ktor.client.plugins.HttpSend
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.client.plugins.cookies.HttpCookies
|
||||
import io.ktor.client.plugins.defaultRequest
|
||||
import io.ktor.client.plugins.plugin
|
||||
import io.ktor.client.plugins.websocket.WebSockets
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.statement.bodyAsText
|
||||
import io.ktor.http.userAgent
|
||||
import io.ktor.serialization.kotlinx.json.json
|
||||
import io.ktor.util.appendAll
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import moe.lava.neon.common.captcha.CaptchaRequest
|
||||
import moe.lava.neon.common.captcha.CaptchaResponse
|
||||
|
||||
class ApiClient {
|
||||
private val logger = Logger.withTag("neon.core.api/client")
|
||||
|
||||
private var captchaHandler: (suspend (CaptchaRequest) -> CaptchaResponse)? = null
|
||||
|
||||
fun setCaptchaHandler(handler: suspend (CaptchaRequest) -> CaptchaResponse) {
|
||||
this.captchaHandler = handler
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
val client = HttpClient {
|
||||
expectSuccess = true
|
||||
install(ContentNegotiation) {
|
||||
json(ApiConstants.json)
|
||||
}
|
||||
install(WebSockets)
|
||||
install(HttpCookies)
|
||||
defaultRequest {
|
||||
url("https://discord.com/api/v9/")
|
||||
userAgent(ApiConstants.userAgent)
|
||||
headers.appendAll(ApiConstants.baseHeaders)
|
||||
}
|
||||
}.apply {
|
||||
plugin(HttpSend).intercept { req ->
|
||||
logger.d { "Intercepting ${req.url.buildString()}" }
|
||||
val call = execute(req)
|
||||
if (call.response.status.value != 400) return@intercept call
|
||||
logger.d { "Found 400 response: ${call.response.bodyAsText()}" }
|
||||
val captchaRequest = runCatching { call.response.body<CaptchaRequest>() }
|
||||
.getOrNull()
|
||||
?: return@intercept call
|
||||
|
||||
logger.d { "Starting captcha flow for: $captchaRequest" }
|
||||
|
||||
val captcha = captchaHandler
|
||||
if (captcha == null) {
|
||||
logger.w { "Captcha handler not found, passing through!" }
|
||||
return@intercept call
|
||||
}
|
||||
|
||||
val solved = captcha(captchaRequest)
|
||||
logger.d { "Captcha solved $solved" }
|
||||
if (solved !is CaptchaResponse.Success) {
|
||||
val failure = solved as CaptchaResponse.Failed
|
||||
logger.w(failure.error) { "Captcha failed" }
|
||||
return@intercept call
|
||||
}
|
||||
|
||||
logger.d { "Refiring" }
|
||||
req.apply {
|
||||
header("X-Captcha-Key", solved.token)
|
||||
if (captchaRequest.captchaSessionId != null) {
|
||||
header("X-Captcha-Session-Id", captchaRequest.captchaSessionId)
|
||||
}
|
||||
if (captchaRequest.captchaRqtoken != null) {
|
||||
header("X-Captcha-Rqtoken", captchaRequest.captchaRqtoken)
|
||||
}
|
||||
}.let { execute(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue