|
1 | 1 | package dev.schlaubi.gtakiller |
2 | 2 |
|
| 3 | +import dev.schlaubi.gtakiller.common.Kill |
| 4 | +import dev.schlaubi.gtakiller.common.KillGtaEvent |
| 5 | +import dev.schlaubi.gtakiller.common.Route |
| 6 | +import dev.schlaubi.gtakiller.common.UpdateKillCounterEvent |
3 | 7 | import io.github.oshai.kotlinlogging.KotlinLogging |
| 8 | +import io.ktor.serialization.kotlinx.* |
| 9 | +import io.ktor.serialization.kotlinx.json.* |
4 | 10 | import io.ktor.server.application.* |
5 | 11 | import io.ktor.server.engine.* |
6 | 12 | import io.ktor.server.netty.* |
7 | 13 | import io.ktor.server.plugins.* |
| 14 | +import io.ktor.server.plugins.contentnegotiation.* |
8 | 15 | import io.ktor.server.plugins.forwardedheaders.* |
| 16 | +import io.ktor.server.resources.* |
| 17 | +import io.ktor.server.response.* |
9 | 18 | import io.ktor.server.routing.* |
10 | 19 | import io.ktor.server.websocket.* |
11 | | -import io.ktor.websocket.* |
| 20 | +import kotlinx.coroutines.isActive |
| 21 | +import kotlinx.datetime.Clock |
| 22 | +import kotlinx.datetime.Instant |
| 23 | +import kotlinx.serialization.json.Json |
| 24 | +import kotlin.time.Duration.Companion.seconds |
12 | 25 |
|
13 | 26 | private val LOG = KotlinLogging.logger { } |
14 | 27 |
|
| 28 | +private var lastKill: Instant? = null |
| 29 | + |
15 | 30 | fun main() { |
16 | 31 | val sessions = mutableListOf<DefaultWebSocketServerSession>() |
17 | 32 |
|
18 | 33 | embeddedServer(Netty, port = 8080, host = "0.0.0.0") { |
19 | | - install(WebSockets) |
| 34 | + install(WebSockets) { |
| 35 | + contentConverter = KotlinxWebsocketSerializationConverter(Json) |
| 36 | + } |
| 37 | + install(Resources) |
| 38 | + install(ContentNegotiation) { |
| 39 | + json() |
| 40 | + } |
20 | 41 | install(XForwardedHeaders) |
21 | 42 |
|
22 | 43 | routing { |
23 | | - webSocket { |
24 | | - sessions += this |
| 44 | + resource<Route.Events> { |
| 45 | + webSocket { |
| 46 | + sessions += this |
25 | 47 |
|
26 | | - LOG.info { "Got session from: ${call.request.origin.remoteHost}" } |
| 48 | + val name = call.request.headers["X-Username"] ?: "Anonymous" |
27 | 49 |
|
28 | | - for (frame in incoming) { |
29 | | - LOG.debug { "GOT FRAME: $frame" } |
| 50 | + LOG.info { "Got session from: ${call.request.origin.remoteHost}" } |
30 | 51 |
|
31 | | - if (frame is Frame.Text) { |
32 | | - val text = frame.readText() |
33 | | - LOG.debug { "Got frame text: $text" } |
| 52 | + while (isActive) { |
| 53 | + val event = receiveEvent() |
| 54 | + LOG.debug { "GOT FRAME: $event" } |
34 | 55 |
|
35 | 56 | sessions.forEach { |
36 | | - it.send(text) |
| 57 | + it.send(event) |
| 58 | + } |
| 59 | + |
| 60 | + if (event is KillGtaEvent) { |
| 61 | + val kill = Kill(Clock.System.now(), name) |
| 62 | + val timeSinceLastKill = Clock.System.now() - (lastKill ?: Instant.DISTANT_PAST) |
| 63 | + if (timeSinceLastKill >= 10.seconds) { |
| 64 | + writeStats( |
| 65 | + stats.copy( |
| 66 | + stats.kills + kill, |
| 67 | + count = stats.count + 1 |
| 68 | + ) |
| 69 | + ) |
| 70 | + } |
| 71 | + sessions.forEach { |
| 72 | + it.send(UpdateKillCounterEvent(stats.count, kill)) |
| 73 | + } |
37 | 74 | } |
38 | 75 | } |
39 | | - } |
40 | 76 |
|
41 | | - sessions -= this |
| 77 | + sessions -= this |
| 78 | + |
| 79 | + LOG.info { "Lost session: ${call.request.origin.remoteHost}" } |
| 80 | + } |
| 81 | + } |
42 | 82 |
|
43 | | - LOG.info { "Lost session: ${call.request.origin.remoteHost}" } |
| 83 | + get<Route.Status> { |
| 84 | + call.respond(stats) |
44 | 85 | } |
45 | 86 | } |
46 | 87 | }.start(wait = true) |
|
0 commit comments