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 { val res = client.get("$baseUrl/api/states") val body = res.body>() return body } suspend fun getUsefulState(): List { 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() 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")