Files
ConnectMinecraft/src/main/kotlin/dev/solsynth/snConnect/services/SnService.kt
2025-10-05 03:14:20 +08:00

97 lines
3.2 KiB
Kotlin

package dev.solsynth.snConnect.services
import dev.solsynth.snConnect.models.WebSocketPacket
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import okhttp3.Response
import okio.ByteString
import java.util.logging.Logger
class SnService(private val baseUrl: String, val clientId: String, val clientSecret: String, val botApiKey: String?) {
val client = OkHttpClient.Builder().build();
private val logger = Logger.getLogger(SnService::class.java.name)
private var websocket: WebSocket? = null
fun getUrl(service: String, segment: String): String {
return "$baseUrl/$service$segment"
}
fun getWsBaseUrl(): String {
return baseUrl.replaceFirst("http", "ws")
}
fun connectWebSocket(listener: WebSocketListener): WebSocket {
val request = Request.Builder()
.url("${getWsBaseUrl()}/ws")
.apply {
botApiKey?.let { header("Authorization", "Bearer $it") }
}
.build()
return client.newWebSocket(request, listener)
}
fun connectWebSocketAsFlow(): Flow<WebSocketPacket> = channelFlow {
val url = "${getWsBaseUrl()}/ws"
val request = Request.Builder()
.url(url)
.apply {
botApiKey?.let { header("Authorization", "Bearer $it") }
}
.build()
fun connect() {
websocket = client.newWebSocket(request, object : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) {
logger.info("WebSocket connection opened to $url")
}
override fun onMessage(webSocket: WebSocket, text: String) {
WebSocketPacket.fromJson(text)?.let { trySend(it) }
}
override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
val text = bytes.string(Charsets.UTF_8)
WebSocketPacket.fromJson(text)?.let { trySend(it) }
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
logger.severe("WebSocket connection failed: ${t.message}, response: ${response?.code}")
websocket = null
GlobalScope.launch {
delay(1000)
connect()
}
}
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
logger.info("WebSocket connection closed: code=$code, reason=$reason")
websocket = null
GlobalScope.launch {
delay(1000)
connect()
}
}
})
}
connect()
awaitClose {
websocket?.close(1000, "Shutting down")
websocket = null
}
}
fun disconnect() {
websocket?.close(1000, "Disconnecting")
websocket = null
}
}