Few cleanups

This commit is contained in:
Oliver Rümpelein 2021-09-25 13:22:34 +02:00
parent 1d35ea2b49
commit 5b13eb5ece
10 changed files with 189 additions and 130 deletions

View File

@ -1,11 +1,13 @@
package de.pheerai.buzzer
import de.pheerai.buzzer.plugins.*
import de.pheerai.buzzer.routing.configureRoutes
import de.pheerai.buzzer.setup.setupPlugins
import io.ktor.server.engine.*
import io.ktor.server.netty.*
fun main() {
embeddedServer(Netty, port = 8888, host = "0.0.0.0") {
configureSockets()
setupPlugins()
configureRoutes()
}.start(wait = true)
}

View File

@ -0,0 +1,21 @@
package de.pheerai.buzzer.clients
import kotlinx.html.*
fun HTML.createAdminDocument() {
head {
meta { charset = "UTF-8" }
title { +"JS Client" }
script { src = "https://code.jquery.com/jquery-3.6.0.min.js" }
script { src = "/assets/adminClient.js" }
}
body {
ol {
id = "usernames"
}
button {
onClick = "resetReceived()"
+"Reset"
}
}
}

View File

@ -0,0 +1,34 @@
package de.pheerai.buzzer.clients
import kotlinx.html.*
fun HTML.createPlayerDocument() {
head {
meta { charset = "UTF-8" }
title { +"JS Client" }
link(
href = "/assets/player.css",
rel = "stylesheet",
type = "text/css"
)
script { src = "https://code.jquery.com/jquery-3.6.0.min.js" }
script { src = "/assets/playerClient.js" }
}
body {
div(classes = "parent") {
attributes["foo"] = "bar"
div(classes = "input") {
label { +"Player" }
div(classes = "bumper") {}
input {
id = "username"
placeholder = "<name>"
}
}
button(classes = "submit") {
onClick = "sendUsername()"
+"I know that!"
}
}
}
}

View File

@ -0,0 +1,14 @@
package de.pheerai.buzzer.data
import java.util.*
object SessionStorage {
val playerSessions = synchronisedCollectionOf<PlayerSocket>()
val gameMasterSessions = synchronisedCollectionOf<GameMasterSocket>()
}
fun <T : Any> synchronisedCollectionOf(vararg data: T): MutableCollection<T> {
val list = LinkedList<T>()
list.addAll(data)
return Collections.synchronizedCollection(list)
}

View File

@ -0,0 +1,20 @@
package de.pheerai.buzzer.handlers
import de.pheerai.buzzer.data.GameMasterSocket
import de.pheerai.buzzer.data.SessionStorage
import io.ktor.http.cio.websocket.*
import kotlinx.coroutines.isActive
suspend fun WebSocketSession.handleGameMasterSocket() {
SessionStorage.gameMasterSessions.add(GameMasterSocket(this))
for (frame in incoming) {
when (frame) {
is Frame.Text -> {
val text = frame.readText()
SessionStorage.playerSessions.filter { it.session.isActive }
.forEach { it.session.send(text) }
}
else -> {}
}
}
}

View File

@ -0,0 +1,22 @@
package de.pheerai.buzzer.handlers
import de.pheerai.buzzer.data.PlayerSocket
import de.pheerai.buzzer.data.SessionStorage
import io.ktor.http.cio.websocket.*
import kotlinx.coroutines.isActive
import org.slf4j.Logger
suspend fun WebSocketSession.handlePlayerSocket(log: Logger) {
SessionStorage.playerSessions.add(PlayerSocket(this))
for (frame in incoming) {
when (frame) {
is Frame.Text -> {
val text = frame.readText()
log.info("Username: $text")
SessionStorage.gameMasterSessions.filter { it.session.isActive }
.forEach { it.session.send(text) }
}
else -> {}
}
}
}

View File

@ -1,128 +0,0 @@
package de.pheerai.buzzer.plugins
import de.pheerai.buzzer.data.GameMasterSocket
import de.pheerai.buzzer.data.PlayerSocket
import io.ktor.application.*
import io.ktor.html.*
import io.ktor.http.cio.websocket.*
import io.ktor.http.content.*
import io.ktor.routing.*
import io.ktor.websocket.*
import kotlinx.coroutines.isActive
import kotlinx.html.*
import java.time.Duration
import java.util.*
fun Application.configureSockets() {
install(WebSockets) {
pingPeriod = Duration.ofSeconds(15)
timeout = Duration.ofSeconds(15)
maxFrameSize = Long.MAX_VALUE
masking = false
}
routing {
val playerSessions = Collections.synchronizedCollection(LinkedList<PlayerSocket>())
val gameMasterSessions = Collections.synchronizedCollection(LinkedList<GameMasterSocket>())
static("/assets") {
resources("css")
resources("js")
}
get("/") {
call.respondHtml {
createPlayerDocument()
}
}
get("/client/player") {
call.respondHtml {
createPlayerDocument()
}
}
get("/client/master") {
call.respondHtml {
createAdminDocument()
}
}
webSocket("/socket/player") {
playerSessions.add(PlayerSocket(this))
for (frame in incoming) {
when (frame) {
is Frame.Text -> {
val text = frame.readText()
log.info("Username: $text")
gameMasterSessions.filter { it.session.isActive }
.forEach { it.session.send(text) }
}
else -> {}
}
}
}
webSocket("/socket/master") {
gameMasterSessions.add(GameMasterSocket(this))
for (frame in incoming) {
when (frame) {
is Frame.Text -> {
val text = frame.readText()
playerSessions.filter { it.session.isActive }
.forEach { it.session.send(text) }
}
else -> {}
}
}
}
}
}
fun HTML.createPlayerDocument() {
head {
meta { charset = "UTF-8" }
title { +"JS Client" }
link(
href = "/assets/player.css",
rel = "stylesheet",
type = "text/css"
)
script { src = "https://code.jquery.com/jquery-3.6.0.min.js" }
script { src = "/assets/playerClient.js" }
}
body {
div(classes = "parent") {
div(classes = "input") {
label { +"Player" }
div(classes = "bumper") {}
input {
id = "username"
placeholder = "<name>"
}
}
button(classes = "submit") {
onClick = "sendUsername()"
+"I know that!"
}
}
}
}
fun HTML.createAdminDocument() {
head {
meta { charset = "UTF-8" }
title { +"JS Client" }
script { src = "https://code.jquery.com/jquery-3.6.0.min.js" }
script { src = "/assets/adminClient.js" }
}
body {
ol {
id = "usernames"
}
button {
onClick = "resetReceived()"
+"Reset"
}
}
}

View File

@ -0,0 +1,52 @@
package de.pheerai.buzzer.routing
import de.pheerai.buzzer.clients.createAdminDocument
import de.pheerai.buzzer.clients.createPlayerDocument
import de.pheerai.buzzer.handlers.handleGameMasterSocket
import de.pheerai.buzzer.handlers.handlePlayerSocket
import io.ktor.application.*
import io.ktor.html.*
import io.ktor.http.content.*
import io.ktor.routing.*
import io.ktor.websocket.*
import org.slf4j.Logger
fun Application.configureRoutes() {
routing {
assetRoutes()
clientRoutes()
websocketRoutes(log)
}
}
private fun Routing.websocketRoutes(log: Logger) {
webSocket("/socket/player") { handlePlayerSocket(log) }
webSocket("/socket/master") { handleGameMasterSocket() }
}
private fun Routing.clientRoutes() {
get("/") {
call.respondHtml {
createPlayerDocument()
}
}
get("/client/player") {
call.respondHtml {
createPlayerDocument()
}
}
get("/client/master") {
call.respondHtml {
createAdminDocument()
}
}
}
private fun Routing.assetRoutes() {
static("/assets") {
resources("css")
resources("js")
}
}

View File

@ -0,0 +1,7 @@
package de.pheerai.buzzer.setup
import io.ktor.application.*
fun Application.setupPlugins() {
installWebSockets()
}

View File

@ -0,0 +1,15 @@
package de.pheerai.buzzer.setup
import io.ktor.application.*
import io.ktor.http.cio.websocket.*
import io.ktor.websocket.*
import java.time.Duration
fun Application.installWebSockets() {
install(WebSockets) {
pingPeriod = Duration.ofSeconds(15)
timeout = Duration.ofSeconds(15)
maxFrameSize = Long.MAX_VALUE
masking = false
}
}