package industries.sunshine.planningpoker import cats.effect._ import cats.syntax.all._ import org.http4s._, org.http4s.dsl.io._, org.http4s.implicits._ import org.http4s.websocket.WebSocketFrame import io.circe.syntax._ import org.http4s.circe.CirceEntityDecoder._ import scala.concurrent.duration._ import org.http4s.server.websocket.WebSocketBuilder import fs2._ import industries.sunshine.planningpoker.common.Models.RoomID import industries.sunshine.planningpoker.common.Models.PlayerID import org.http4s.server.AuthMiddleware.apply import org.http4s.server.AuthMiddleware object MyHttpService { def create(auth: Auth[IO], roomService: RoomService[IO])( wsb: WebSocketBuilder[IO] ): HttpApp[cats.effect.IO] = { val authedRoomRoutes: AuthedRoutes[(PlayerID, RoomID), IO] = AuthedRoutes.of { case GET -> Root / "subscribe" as (playerId, roomId) => { val send: Stream[IO, WebSocketFrame] = roomService .subscribe(roomId) .map(state => WebSocketFrame.Text(state.getViewFor(playerId).asJson.noSpaces)) val receive: Pipe[IO, WebSocketFrame, Unit] = _.evalMap { case WebSocketFrame.Text(text, _) => Sync[IO].delay(println(text)) case other => Sync[IO].delay(println(other)) } IO(println(s"got ws request from $playerId in $roomId")) >> wsb.build(send, receive) } case GET -> Root / "vote" / vote as (playerId, roomId) => { IO(println(s">> got $vote from $playerId in $roomId")) >> roomService.acceptVote(roomId, playerId, vote) >> Ok() } case GET -> Root / "end-voting" as (playerId, roomId) => { IO(println(s">> got request to end voting from $playerId in $roomId")) >> roomService.endVoting(roomId, playerId) >> Ok() } case GET -> Root / "new-poll" as (playerId, roomId) => { IO(println(s">> got request to start new voting from $playerId in $roomId")) >> roomService.startNewPoll(roomId, playerId) >> Ok() } case GET -> Root / "logout" as (playerId, roomId) => { for { _ <- IO(println(s">> got request to logout from $playerId in $roomId")) _ <- roomService.leaveRoom(roomId, playerId) cookie = ResponseCookie(name = Auth.authcookieName, content = "").clearCookie } yield (Response(Status.Ok).addCookie(cookie)) } } val authMiddleware = AuthMiddleware(auth.authUser) val aa = authMiddleware(authedRoomRoutes) import cats.data.EitherT val authenticationRoute = HttpRoutes .of[IO] { case req @ POST -> Root / "login" => { val responseOrError = for { data <- EitherT.right(req.as[Requests.LogIn]) Requests.LogIn(roomName, nickName, roomPassword, nickPassword) = data roomId = RoomID(roomName) 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)))) } yield resp val response = responseOrError.leftSemiflatMap(error => Forbidden(error.toString())).merge response } } (authenticationRoute <+> authMiddleware(authedRoomRoutes)).orNotFound } }