Skip to content

Commit

Permalink
Use EitherT
Browse files Browse the repository at this point in the history
  • Loading branch information
H1rono committed Feb 23, 2024
1 parent 113a3ce commit 07ef930
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 11 deletions.
51 changes: 41 additions & 10 deletions src/main/scala/h1rono/BotHandler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,57 @@ import cats.effect._
import org.http4s._
import org.http4s.circe._
import cats.syntax.all._
import cats.data.EitherT

trait BotHandler[F[_]] {
def bot(req: Request[F]): F[Status]
}

object BotHandler {
def impl[F[_]: Async: std.Console]: BotHandler[F] = new BotHandler[F] {
final case class Config(verificationToken: String, accessToken: String)

def impl[F[_]: Async: std.Console](conf: Config): BotHandler[F] = new BotHandler[F] {
def bot(req: Request[F]): F[Status] = for {
payload <- req.as[Json]
eventType = getHeaderValue(req, CIString("x-traq-bot-event")).getOrElse(
throw new Exception("x-traq-bot-event not found")
req <- botInner(req).value
// TODO: Do something with req
} yield req match {
case Left(HandleResults.BadInput) => Status.BadRequest
case Left(HandleResults.Success) => Status.NoContent
case Left(HandleResults.UnexpectedError) => Status.InternalServerError
case Right(_) => Status.NoContent
}

private sealed trait HandleResults
private object HandleResults {
case object Success extends HandleResults
case object BadInput extends HandleResults
case object UnexpectedError extends HandleResults
}

private def botInner(req: Request[F]): EitherT[F, HandleResults, (String, Json)] = for {
payload <- EitherT.right(req.as[Json])
eventType <- checkRequest(req)
_ <- EitherT.right(std.Console[F].println(s"event type is $eventType"))
_ <- EitherT.right(std.Console[F].println(payload))
} yield (eventType, payload)

private def checkRequest(req: Request[F]): EitherT[F, HandleResults, String] = for {
eventType <- EitherT.fromOption[F](
getHeaderValue(req, CIString("x-traq-bot-event")),
HandleResults.BadInput
)
token <- EitherT.fromOption[F](
getHeaderValue(req, CIString("x-traq-bot-token")),
HandleResults.BadInput
)
token = getHeaderValue(req, CIString("x-traq-bot-token")).getOrElse(
throw new Exception("x-traq-bot-token not found")
res <- EitherT.cond(
token == conf.verificationToken,
eventType,
HandleResults.BadInput: HandleResults
)
_ <- std.Console[F].println(s"event type is $eventType")
_ <- std.Console[F].println(payload)
} yield Status.NoContent
} yield res

private def getHeaderValue[F[_]](req: Request[F], key: CIString): Option[String] = for {
private def getHeaderValue(req: Request[F], key: CIString): Option[String] = for {
headers <- req.headers.get(key)
header <- headers.get(0)
} yield header.value
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/h1rono/BotServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ object BotServer {

val helloWorldAlg = HelloWorld.impl[F]
val dumpReqAlg = DumpReq.impl[F]
val botHandlerAlg = BotHandler.impl[F]
val botHandlerAlg = BotHandler.impl[F](BotHandler.Config(verificationToken, accessToken))

// Combine Service Routes into an HttpApp.
// Can also be done via a Router if you
Expand Down

0 comments on commit 07ef930

Please sign in to comment.