feat(websocket)!: Implement WebSocket connection and event handling
This commit is contained in:
@@ -2,13 +2,19 @@ package model.sessions
|
||||
|
||||
import de.knockoutwhist.events.player.{RequestCardEvent, RequestTieChoiceEvent, RequestTrumpSuitEvent}
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
import logic.game.GameLobby
|
||||
import model.users.User
|
||||
import org.apache.pekko.actor.{Actor, ActorRef}
|
||||
import play.api.libs.json.{JsObject, JsValue, Json}
|
||||
import util.WebsocketEventMapper
|
||||
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.locks.{Lock, ReentrantLock}
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
||||
class UserSession(val user: User, val host: Boolean) extends PlayerSession {
|
||||
class UserSession(val user: User, val host: Boolean, val gameLobby: GameLobby) extends PlayerSession {
|
||||
var canInteract: Option[InteractionType] = None
|
||||
var websocketActor: Option[UserWebsocketActor] = None
|
||||
val lock: ReentrantLock = ReentrantLock()
|
||||
|
||||
override def updatePlayer(event: SimpleEvent): Unit = {
|
||||
@@ -31,5 +37,17 @@ class UserSession(val user: User, val host: Boolean) extends PlayerSession {
|
||||
def resetCanInteract(): Unit = {
|
||||
canInteract = None
|
||||
}
|
||||
|
||||
def handleWebResponse(eventType: String, data: JsObject): Unit = {
|
||||
lock.lock()
|
||||
Try {
|
||||
eventType match {
|
||||
case "Ping" =>
|
||||
// No action needed for Ping
|
||||
()
|
||||
}
|
||||
}
|
||||
lock.unlock()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
94
knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala
Normal file
94
knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala
Normal file
@@ -0,0 +1,94 @@
|
||||
package model.sessions
|
||||
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
import org.apache.pekko.actor.{Actor, ActorRef}
|
||||
import play.api.libs.json.{JsObject, JsValue, Json}
|
||||
import util.WebsocketEventMapper
|
||||
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
||||
class UserWebsocketActor(
|
||||
out: ActorRef,
|
||||
session: UserSession
|
||||
) extends Actor {
|
||||
|
||||
if (session.websocketActor.isDefined) {
|
||||
session.websocketActor.foreach(actor => actor.transmitTextToClient("Error: Multiple websocket connections detected. Closing this connection."))
|
||||
context.stop(self)
|
||||
} else {
|
||||
session.websocketActor = Some(this)
|
||||
}
|
||||
|
||||
override def receive: Receive = {
|
||||
case msg: String =>
|
||||
val jsonObject = Try {
|
||||
Json.parse(msg)
|
||||
}
|
||||
Try {
|
||||
jsonObject match {
|
||||
case Success(value) =>
|
||||
handle(value)
|
||||
case Failure(exception) =>
|
||||
transmitTextToClient(s"Error parsing JSON: ${exception.getMessage}")
|
||||
}
|
||||
}.failed.foreach(
|
||||
ex => transmitTextToClient(s"Error handling message: ${ex.getMessage}")
|
||||
)
|
||||
case other =>
|
||||
}
|
||||
|
||||
def transmitEventToClient(event: SimpleEvent): Unit = {
|
||||
val jsonString = WebsocketEventMapper.toJsonString(event)
|
||||
out ! jsonString
|
||||
}
|
||||
|
||||
private def transmitJsonToClient(jsonObj: JsObject): Unit = {
|
||||
out ! jsonObj.toString()
|
||||
}
|
||||
|
||||
private def transmitTextToClient(text: String): Unit = {
|
||||
out ! text
|
||||
}
|
||||
|
||||
private def handle(json: JsValue): Unit = {
|
||||
val idOpt = (json \ "id").asOpt[String]
|
||||
if (idOpt.isEmpty) {
|
||||
transmitJsonToClient(Json.obj(
|
||||
"status" -> "error",
|
||||
"error" -> "Missing 'id' field"
|
||||
))
|
||||
return
|
||||
}
|
||||
val id = idOpt.get
|
||||
val eventOpt = (json \ "event").asOpt[String]
|
||||
if (eventOpt.isEmpty) {
|
||||
transmitJsonToClient(Json.obj(
|
||||
"id" -> id,
|
||||
"event" -> null,
|
||||
"status" -> "error",
|
||||
"error" -> "Missing 'event' field"
|
||||
))
|
||||
return
|
||||
}
|
||||
val event = eventOpt.get
|
||||
val data = (json \ "data").asOpt[JsObject].getOrElse(Json.obj())
|
||||
val result = Try {
|
||||
session.handleWebResponse(event, data)
|
||||
}
|
||||
if (result.isSuccess) {
|
||||
transmitJsonToClient(Json.obj(
|
||||
"id" -> id,
|
||||
"event" -> event,
|
||||
"status" -> "success"
|
||||
))
|
||||
} else {
|
||||
transmitJsonToClient(Json.obj(
|
||||
"id" -> id,
|
||||
"event" -> event,
|
||||
"status" -> "error",
|
||||
"error" -> result.failed.get.getMessage
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user