add WebSocket timers

- EventDispatcher, TimerEvent add.
This commit is contained in:
dalbodeule
2024-07-30 22:40:07 +09:00
parent da13e8b834
commit a9ee40e936
6 changed files with 179 additions and 11 deletions

View File

@@ -1,6 +1,7 @@
package space.mori.chzzk_bot.webserver
import io.ktor.http.*
import io.ktor.serialization.kotlinx.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.application.*
import io.ktor.server.engine.*
@@ -12,9 +13,18 @@ import io.ktor.server.routing.*
import io.ktor.server.websocket.*
import kotlinx.serialization.json.Json
import space.mori.chzzk_bot.webserver.routes.apiRoutes
import space.mori.chzzk_bot.webserver.routes.wsTimerRoutes
import java.time.Duration
val server = embeddedServer(Netty, port = 8080) {
install(WebSockets)
install(WebSockets) {
pingPeriod = Duration.ofSeconds(15)
timeout = Duration.ofSeconds(15)
maxFrameSize = Long.MAX_VALUE
masking = false
contentConverter = KotlinxWebsocketSerializationConverter(Json)
}
install(ContentNegotiation) {
json(Json {
prettyPrint = true
@@ -27,6 +37,7 @@ val server = embeddedServer(Netty, port = 8080) {
}
routing {
apiRoutes()
wsTimerRoutes()
swaggerUI("swagger-ui/index.html", "openapi/documentation.yaml") {
options {
version = "1.1.0"

View File

@@ -0,0 +1,76 @@
package space.mori.chzzk_bot.webserver.routes
import io.ktor.server.routing.*
import io.ktor.server.websocket.*
import io.ktor.websocket.*
import kotlinx.coroutines.channels.ClosedReceiveChannelException
import kotlinx.serialization.Serializable
import space.mori.chzzk_bot.common.events.Event
import space.mori.chzzk_bot.common.events.TimerType
import space.mori.chzzk_bot.common.services.UserService
import space.mori.chzzk_bot.common.events.EventDispatcher
import space.mori.chzzk_bot.common.events.EventHandler
import java.util.concurrent.ConcurrentHashMap
fun Routing.wsTimerRoutes() {
val sessions = ConcurrentHashMap<String, WebSocketServerSession>()
webSocket("/timer/{uid}") {
val uid = call.parameters["uid"]
val user = uid?.let { UserService.getUser(it) }
if (uid == null) {
close(CloseReason(CloseReason.Codes.CANNOT_ACCEPT, "Invalid UID"))
return@webSocket
}
if (user == null) {
close(CloseReason(CloseReason.Codes.CANNOT_ACCEPT, "Invalid UID"))
return@webSocket
}
sessions[uid] = this
try {
for (frame in incoming) {
when(frame) {
is Frame.Text -> {
}
is Frame.Ping -> send(Frame.Pong(frame.data))
else -> {
}
}
}
} catch(_: ClosedReceiveChannelException) {
} finally {
sessions.remove(uid)
}
}
run {
val dispatcher = EventDispatcher
dispatcher.register(TimerEvent::class.java, object : EventHandler<TimerEvent> {
override suspend fun handle(event: TimerEvent) {
sessions[event.uid]?.sendSerialized(TimerResponse(event.type, event.time ?: ""))
}
})
}
}
enum class TimerType {
UPTIME, TIMER
}
class TimerEvent(
val uid: String,
val type: TimerType,
val time: String?
): Event
@Serializable
data class TimerResponse(
val type: TimerType,
val time: String?
)