refactor(remote): extract chat relogin authenticator
This commit is contained in:
1 parent
3e012dbf31
commit
b9ee61d429
1 file changed
+122
@@ -0,0 +1,122 @@
|
||||
package com.m57.hermescontrol.data.remote
|
||||
|
||||
import com.m57.hermescontrol.data.local.AuthManager
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Handles basic credential login and WS ticket minting for in-chat reconnect/re-authentication.
|
||||
*
|
||||
* Extracted from [com.m57.hermescontrol.ui.chat.ChatViewModel] to isolate raw OkHttp network calls.
|
||||
*/
|
||||
class ChatReloginAuthenticator(
|
||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||
private val mainDispatcher: CoroutineDispatcher = Dispatchers.Main,
|
||||
) {
|
||||
suspend fun relogin(
|
||||
username: String,
|
||||
password: String,
|
||||
onSuccess: () -> Unit,
|
||||
onFailure: (String) -> Unit,
|
||||
) {
|
||||
withContext(ioDispatcher) {
|
||||
val endpoint = AuthManager.endpointForBuild()
|
||||
val jsonMediaType = "application/json; charset=utf-8".toMediaType()
|
||||
val jsonBody =
|
||||
JSONObject()
|
||||
.put("provider", "basic")
|
||||
.put("username", username)
|
||||
.put("password", password)
|
||||
.put("next", "")
|
||||
.toString()
|
||||
|
||||
try {
|
||||
val loginClient =
|
||||
OkHttpProvider.probe
|
||||
.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(10, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
val loginReq =
|
||||
Request
|
||||
.Builder()
|
||||
.url(endpoint.resolve("auth/password-login").toString())
|
||||
.header("Content-Type", "application/json")
|
||||
.post(jsonBody.toRequestBody(jsonMediaType))
|
||||
.build()
|
||||
|
||||
loginClient.newCall(loginReq).execute().use { loginResp ->
|
||||
if (!loginResp.isSuccessful) {
|
||||
val msg =
|
||||
when (loginResp.code) {
|
||||
401 -> "Invalid username or password (401)"
|
||||
403 -> "Forbidden (403)"
|
||||
else -> "HTTP error code: ${loginResp.code}"
|
||||
}
|
||||
withContext(mainDispatcher) {
|
||||
onFailure(msg)
|
||||
}
|
||||
return@withContext
|
||||
}
|
||||
}
|
||||
|
||||
val ticketClient =
|
||||
OkHttpProvider.base
|
||||
.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(10, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
val ticketReq =
|
||||
Request
|
||||
.Builder()
|
||||
.url(endpoint.resolve("api/auth/ws-ticket").toString())
|
||||
.post("{}".toRequestBody(jsonMediaType))
|
||||
.build()
|
||||
|
||||
ticketClient.newCall(ticketReq).execute().use { ticketResp ->
|
||||
if (!ticketResp.isSuccessful) {
|
||||
withContext(mainDispatcher) {
|
||||
onFailure("Failed to mint WS ticket: HTTP ${ticketResp.code}")
|
||||
}
|
||||
return@withContext
|
||||
}
|
||||
|
||||
val body = ticketResp.body.string()
|
||||
val ticket = JSONObject(body).optString("ticket").takeIf { it.isNotBlank() }
|
||||
|
||||
if (ticket.isNullOrBlank()) {
|
||||
withContext(mainDispatcher) {
|
||||
onFailure("Invalid ticket returned from server")
|
||||
}
|
||||
return@withContext
|
||||
}
|
||||
|
||||
AuthManager.setWsAuthParam("ticket")
|
||||
AuthManager.setToken(ticket)
|
||||
|
||||
withContext(mainDispatcher) {
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
withContext(mainDispatcher) {
|
||||
onFailure("Connection failed: ${e.message}")
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
withContext(mainDispatcher) {
|
||||
onFailure("Connection failed: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user