adding alpha create room capability

This commit is contained in:
efim 2023-04-28 10:08:04 +04:00
parent e1364c9b9b
commit 62d63546c4
3 changed files with 83 additions and 11 deletions

View File

@ -22,9 +22,12 @@ object MyHttpService {
val authedRoomRoutes: AuthedRoutes[(PlayerID, RoomID), IO] =
AuthedRoutes.of {
case GET -> Root / "subscribe" as (playerId, roomId) => {
val initial = Stream.evals(roomService.getRoom(roomId))
val subscription = roomService.subscribe(roomId)
val send: Stream[IO, WebSocketFrame] =
roomService
.subscribe(roomId)
(initial ++ subscription)
.evalTap(state => IO(println(s">> sending room state $state to $playerId")))
.map(state => WebSocketFrame.Text(state.getViewFor(playerId).asJson.noSpaces))
val receive: Pipe[IO, WebSocketFrame, Unit] = _.evalMap {
@ -69,13 +72,32 @@ object MyHttpService {
playerId <- EitherT(roomService.joinRoom(roomId, nickName, nickPassword, roomPassword))
authCookie <- EitherT.liftF(auth.joinRoom(roomId, playerId))
_ <- EitherT.liftF(IO(println(s"> logging in $nickName to $roomName")))
resp <- EitherT.liftF(Ok().flatTap(resp => IO(resp.addCookie(authCookie))))
resp = Response(Status.Ok).addCookie(authCookie)
} yield resp
val response = responseOrError.leftSemiflatMap(error => Forbidden(error.toString())).merge
response
}
case req @ POST -> Root / "create-room" => {
val responseOrError = for {
data <- EitherT.right(req.as[Requests.LogIn])
Requests.LogIn(roomName, nickName, roomPassword, nickPassword) = data
room <- EitherT(roomService.createRoom(roomName, nickName, nickPassword, roomPassword))
owner = room.players.head // TODO add check
authCookie <- EitherT.liftF(auth.joinRoom(room.id, owner.id))
_ <- EitherT.liftF(
IO(println(s"> logging in $nickName to new room $room | $authCookie"))
)
resp = Response(Status.Ok).addCookie(authCookie)
_ <- EitherT.liftF(IO(println(s"> about to reply $resp ${resp.cookies}")))
} yield resp
val response = responseOrError.leftSemiflatMap(error => Forbidden(error.toString())).merge
response
}
}
(authenticationRoute <+> authMiddleware(authedRoomRoutes)).orNotFound

View File

@ -15,7 +15,12 @@ enum RoomError {
}
trait RoomService[F[_]] {
def createRoom(newRoom: Room): F[Either[RoomError, Room]]
def createRoom(
roomName: String,
nickName: String,
nickPassword: String,
roomPassword: String
): F[Either[RoomError, Room]]
def updateRoom(roomId: RoomID, roomUpd: Room => Room): F[Unit]
def joinRoom(
id: RoomID,
@ -35,19 +40,37 @@ trait RoomService[F[_]] {
class InMemoryRoomService[F[_]: Concurrent](stateRef: Ref[F, Map[RoomID, (Room, Topic[F, Room])]])
extends RoomService[F] {
override def createRoom(newRoom: Room): F[Either[RoomError, Room]] = {
// TODO accept allowed cards and separate request
override def createRoom(
roomName: String,
nickName: String,
nickPassword: String,
roomPassword: String
): F[Either[RoomError, Room]] = {
for {
updatesTopic <- Topic[F, Room]
room <- stateRef.modify { rooms =>
rooms.get(newRoom.id) match {
val roomId = RoomID(roomName)
rooms.get(roomId) match {
case Some(_) =>
rooms -> RoomError.RoomAlreadyExists(newRoom.id.name).asLeft[Room]
rooms -> RoomError.RoomAlreadyExists(roomName).asLeft[Room]
case None =>
(rooms.updated(newRoom.id, (newRoom, updatesTopic))) -> newRoom.asRight[RoomError]
val ownerPlayer = Player.create(nickName)
val newRoom = Room(
roomId,
players = List(ownerPlayer),
owner = ownerPlayer.id,
password = roomPassword,
allowedCards = List("XS", "S", "M", "L", "XL"), // TODO accept from front
round = RoundState.Voting(Map.empty),
playersPasswords = Map(nickName -> nickPassword)
)
rooms.updated(newRoom.id, (newRoom, updatesTopic)) -> newRoom.asRight[RoomError]
}
}
} yield room
}
override def updateRoom(roomId: RoomID, roomUpd: Room => Room): F[Unit] = {
for {
// modify is function to update state and compute auxillary value to return, here - topic
@ -82,8 +105,8 @@ class InMemoryRoomService[F[_]: Concurrent](stateRef: Ref[F, Map[RoomID, (Room,
roomID,
room =>
room.round match {
case RoundState.Viewing(votes) => room.copy(round = RoundState.Viewing(votes))
case RoundState.Voting(_) => room.copy(round = RoundState.Voting(Map.empty))
case RoundState.Viewing(_) => room
case RoundState.Voting(votes) => room.copy(round = RoundState.Viewing(votes))
}
)
override def startNewPoll(roomID: RoomID, playerID: PlayerID): F[Unit] = updateRoom(
@ -91,7 +114,7 @@ class InMemoryRoomService[F[_]: Concurrent](stateRef: Ref[F, Map[RoomID, (Room,
room =>
room.round match {
case RoundState.Viewing(_) => room.copy(round = RoundState.Voting(Map.empty))
case RoundState.Voting(votes) => room.copy(round = RoundState.Viewing(votes))
case RoundState.Voting(votes) => room
}
)

View File

@ -76,6 +76,32 @@ object JoinRoomComponent {
}
} --> responseReceived
)
val newRoomButton = button(
"Create new room",
onClick
.mapTo {
(roomNameVar.now(), roomPassVar.now(), nicknameVar.now(), nicknamePass.now())
}
.flatMap { case (roomName, roomPass, nickname, nicknamePass) =>
Fetch
.post(
"/api/create-room",
body = Requests.LogIn(
roomName,
nickname,
roomPass,
nicknamePass
)
)
.text.map { response =>
if (response.ok) {
loggedIn.onNext(true)
response
} else response
}
} --> responseReceived
)
div(
className := "flex flex-col h-full justify-center",
@ -85,6 +111,7 @@ object JoinRoomComponent {
nameInput(nicknameVar, "Enter your nickname:"),
passInput(nicknamePass, "nickname pass:"),
submitButton,
newRoomButton,
div(
div(
code("received:")