efim 8716385ea1 adding fork := true for backend server interrupts
without it app starts in same jvm and we're told that Ctrl+C will not
always kill the Ember server:

https://typelevel.org/cats-effect/docs/2.x/datatypes/ioapp
WARNING: If you run your IOApp program from sbt, you may observe cancellation and resource releasing is not happening. This is due to sbt, by default, running programs in the same JVM as sbt, so when your program is canceled sbt avoids stopping its own JVM. To properly allow cancellation, ensure your progam is forked into its own JVM via a setting like fork := true in your sbt configuration.
2023-04-23 23:35:45 +04:00

81 lines
2.8 KiB
Scala

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.generic.auto._
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)(
wsb: WebSocketBuilder[cats.effect.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] =
Stream
.emits(TestModels.testChangesList)
.covary[IO].metered(1.second).map(state => WebSocketFrame.Text(state.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))
}
wsb.build(send, receive)
}
case GET -> Root / "vote" / vote as (playerId, roomId) => {
// TODO forward these to the service implementation
IO(println(s">> got $vote from $playerId in $roomId")) >> Ok()
}
case GET -> Root / "end-voting" as (playerId, roomId) => {
IO(println(s">> got request to end voting from $playerId in $roomId")) >> Ok()
}
case GET -> Root / "new-poll" as (playerId, roomId) => {
IO(println(s">> got request to start new voting from $playerId in $roomId")) >> Ok()
}
}
val authMiddleware = AuthMiddleware(auth.authUser)
val aa = authMiddleware(authedRoomRoutes)
val authenticationRoute = HttpRoutes
.of[IO] {
case req @ POST -> Root / "login" => {
for {
data <- req.as[Requests.LogIn]
authResult <- auth.accessRoom(
data.roomName,
data.password,
data.nickname
)
resp <- authResult match {
case Left(error) =>
Forbidden(error)
case Right(sessionId) => {
Ok("Logged in!").map(
_.addCookie(
ResponseCookie("authcookie", sessionId.toString())
)
)
}
}
} yield resp
}
}
(authenticationRoute <+> authMiddleware(authedRoomRoutes)).orNotFound
}
}