HomeNative/app/src/main/java/dev/coffeeco/homenative/data/HomeClient.kt
2024-09-02 11:08:23 +02:00

102 lines
3.6 KiB
Kotlin

package dev.coffeeco.homenative.data
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.okhttp.OkHttp
import io.ktor.client.plugins.DefaultRequest
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.plugins.websocket.WebSockets
import io.ktor.client.plugins.websocket.receiveDeserialized
import io.ktor.client.plugins.websocket.sendSerialized
import io.ktor.client.plugins.websocket.webSocket
import io.ktor.client.request.get
import io.ktor.client.request.header
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.client.statement.HttpResponse
import io.ktor.http.ContentType
import io.ktor.http.HttpHeaders
import io.ktor.http.contentType
import io.ktor.serialization.kotlinx.KotlinxWebsocketSerializationConverter
import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
class HomeClient(private val baseUrl: String, private val accessToken: String) {
private val client: HttpClient = HttpClient(OkHttp) {
install(WebSockets) {
contentConverter = KotlinxWebsocketSerializationConverter(Json)
}
install(ContentNegotiation) {
json(Json { // isLenient = true
// useArrayPolymorphism = true
allowStructuredMapKeys = true
ignoreUnknownKeys = true // explicitNulls = false
// namingStrategy = JsonNamingStrategy.SnakeCase
})
}
install(DefaultRequest) {
header(HttpHeaders.Authorization, "Bearer $accessToken")
}
}
suspend fun apiStatus(): HttpResponse {
val res = client.get("$baseUrl/api/")
return res
}
private suspend fun getState(): List<StatesResItem> {
val res = client.get("$baseUrl/api/states")
val body = res.body<List<StatesResItem>>()
return body
}
suspend fun getUsefulState(): List<StatesResItem> {
val all = getState()
val filtered = all.filter { i -> i.entityId.startsWith("switch.") }
return filtered
}
private suspend fun updateService(
entityId: String, domain: String, service: String
): HttpResponse {
return client.post("$baseUrl/api/services/$domain/$service") {
contentType(ContentType.Application.Json)
setBody(PostServiceBody(entityId))
}
}
suspend fun updateSwitch(entityId: String, service: String) {
if (service !in switchServices) {
throw Exception("Illegal/unknown service was specified")
}
val res = updateService(entityId, "switch", service)
}
fun connect(coroutineScope: CoroutineScope) {
GlobalScope.launch {
client.webSocket(
"${baseUrl.replace("http", "ws")}/api/websocket"
) {
var iteratingNumber = 0
var isReady = false
while (true) {
val data = receiveDeserialized<WebSocketIncoming>()
if (data.type == "auth_required") sendSerialized(WSAuth("auth", accessToken))
if (data.type == "auth_ok") {
isReady = true
sendSerialized(WSSubscribe(iteratingNumber, "state_changed"))
}
println(data)
iteratingNumber++
}
}
}
}
}
val switchServices = listOf("turn_off", "turn_on", "toggle")