diff --git a/project/MornyConfiguration.scala b/project/MornyConfiguration.scala index 602efbe..5733ffb 100644 --- a/project/MornyConfiguration.scala +++ b/project/MornyConfiguration.scala @@ -1,4 +1,4 @@ -import sbt.* + //noinspection TypeAnnotation object MornyConfiguration { @@ -16,18 +16,18 @@ object MornyConfiguration { val dependencies: Seq[ModuleID] = Seq( - "com.github.spotbugs" % "spotbugs-annotations" % "4.8.2" % Compile, + "com.github.spotbugs" % "spotbugs-annotations" % "4.8.4" % Compile, "cc.sukazyo" % "messiva" % "0.2.0", "cc.sukazyo" % "resource-tools" % "0.2.2", "com.github.pengrad" % "java-telegram-bot-api" % "6.2.0", - "org.http4s" %% "http4s-dsl" % "0.23.25", - "org.http4s" %% "http4s-circe" % "0.23.25", - "org.http4s" %% "http4s-netty-server" % "0.5.12", + "org.http4s" %% "http4s-dsl" % "0.23.26", + "org.http4s" %% "http4s-circe" % "0.23.26", + "org.http4s" %% "http4s-netty-server" % "0.5.16", - "com.softwaremill.sttp.client3" %% "core" % "3.9.2", - "com.softwaremill.sttp.client3" %% "okhttp-backend" % "3.9.2", + "com.softwaremill.sttp.client3" %% "core" % "3.9.5", + "com.softwaremill.sttp.client3" %% "okhttp-backend" % "3.9.5", "com.squareup.okhttp3" % "okhttp" % "4.12.0" % Runtime, "org.typelevel" %% "case-insensitive" % "1.4.0", @@ -42,10 +42,10 @@ object MornyConfiguration { // used for disable slf4j // due to the slf4j api have been used in the following libraries: // - cron-utils - "org.slf4j" % "slf4j-nop" % "2.0.9" % Runtime, + "org.slf4j" % "slf4j-nop" % "2.0.13" % Runtime, - "org.scalatest" %% "scalatest" % "3.2.17" % Test, - "org.scalatest" %% "scalatest-freespec" % "3.2.17" % Test, + "org.scalatest" %% "scalatest" % "3.2.18" % Test, + "org.scalatest" %% "scalatest-freespec" % "3.2.18" % Test, // for test report "com.vladsch.flexmark" % "flexmark" % "0.64.8" % Test, "com.vladsch.flexmark" % "flexmark-profile-pegdown" % "0.64.8" % Test diff --git a/src/main/resources/assets_morny/images/http-sekai-400.png b/src/main/resources/assets_morny/images/http-sekai-400.png new file mode 100644 index 0000000..4b932eb Binary files /dev/null and b/src/main/resources/assets_morny/images/http-sekai-400.png differ diff --git a/src/main/scala/cc/sukazyo/cono/morny/core/http/ServiceUI.scala b/src/main/scala/cc/sukazyo/cono/morny/core/http/ServiceUI.scala index 404cfcd..c5ce3f8 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/core/http/ServiceUI.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/core/http/ServiceUI.scala @@ -2,17 +2,14 @@ package cc.sukazyo.cono.morny.core.http import cats.effect.IO import cc.sukazyo.cono.morny.core.http.api.HttpService4Api -import cc.sukazyo.cono.morny.data.TelegramImages -import org.http4s.{HttpRoutes, MediaType} +import org.http4s.HttpRoutes import org.http4s.dsl.io.* -import org.http4s.headers.`Content-Type` class ServiceUI extends HttpService4Api { override lazy val service: HttpRoutes[IO] = HttpRoutes.of[IO] { case GET -> Root => - NotImplemented(TelegramImages.IMG_501.get) - .map(_.withContentType(`Content-Type`(MediaType.image.jpeg))) + MornyNotImplemented() } } diff --git a/src/main/scala/cc/sukazyo/cono/morny/core/http/api/HttpService4Api.scala b/src/main/scala/cc/sukazyo/cono/morny/core/http/api/HttpService4Api.scala index 4368e19..8d83956 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/core/http/api/HttpService4Api.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/core/http/api/HttpService4Api.scala @@ -1,32 +1,12 @@ package cc.sukazyo.cono.morny.core.http.api import cats.effect.IO -import cc.sukazyo.cono.morny.util.UseThrowable.toLogString -import org.http4s.{HttpRoutes, Response} +import org.http4s.HttpRoutes -trait HttpService4Api { +trait HttpService4Api extends HttpStatus { lazy val service: HttpRoutes[IO] - extension (response: Response[IO]) { - def setMornyInternalErrorHeader (e: Throwable): Response[IO] = - response.setMornyInternalErrorHeader( - e.getClass.getSimpleName, - e.getMessage, - e.toLogString - ) - def setMornyInternalErrorHeader ( - `Morny-Internal-Error-Type`: String, - `Morny-Internal-Error-Message`: String, - `Morny-Internal-Error-Detail`: String - ): Response[IO] = - response.withHeaders( - "Morny-Internal-Error-Type" -> `Morny-Internal-Error-Type`, - "Morny-Internal-Error-Message" -> `Morny-Internal-Error-Message`, - "Morny-Internal-Error-Detail" -> `Morny-Internal-Error-Detail`, - ) - } - } object HttpService4Api { diff --git a/src/main/scala/cc/sukazyo/cono/morny/core/http/api/HttpStatus.scala b/src/main/scala/cc/sukazyo/cono/morny/core/http/api/HttpStatus.scala new file mode 100644 index 0000000..1fb9760 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/core/http/api/HttpStatus.scala @@ -0,0 +1,60 @@ +package cc.sukazyo.cono.morny.core.http.api + +import cats.effect.IO +import cc.sukazyo.cono.morny.data.TelegramImages +import cc.sukazyo.cono.morny.util.UseThrowable.toLogString +import org.http4s.{Header, MediaType, Response} +import org.http4s.dsl.io.* +import org.http4s.headers.`Content-Type` + +trait HttpStatus { + + private type ResponseT = Response[IO] + private type ResponseIO = IO[ResponseT] + + extension (response: ResponseT) { + def setMornyInternalErrorHeader (e: Throwable): ResponseT = + response.setMornyInternalErrorHeader( + e.getClass.getSimpleName, + e.getMessage, + e.toLogString + ) + def setMornyInternalErrorHeader ( + `Morny-Internal-Error-Type`: String, + `Morny-Internal-Error-Message`: String, + `Morny-Internal-Error-Detail`: String + ): ResponseT = + response + .putHeaders( + "Morny-Internal-Error-Type" -> `Morny-Internal-Error-Type`, + "Morny-Internal-Error-Message" -> `Morny-Internal-Error-Message`, + "Morny-Internal-Error-Detail" -> `Morny-Internal-Error-Detail`, + ) + } + + /** 400 Bad Request */ + def MornyBadRequest (): ResponseIO = + BadRequest(TelegramImages.IMG_400.get) + .map(_.withContentType(`Content-Type`(MediaType.image.png))) + + /** 404 Not Found */ + def MornyNotFound (): ResponseIO = + NotFound(TelegramImages.IMG_404.get) + .map(_.withContentType(`Content-Type`(MediaType.image.png))) + + /** 500 Internal Server Error */ + def MornyInternalServerError (): ResponseIO = + InternalServerError(TelegramImages.IMG_500.get) + .map(_.withContentType(`Content-Type`(MediaType.image.png))) + + /** 501 Not Implemented */ + def MornyNotImplemented (): ResponseIO = + NotImplemented(TelegramImages.IMG_501.get) + .map(_.withContentType(`Content-Type`(MediaType.image.png))) + + /** 523 Service Unavailable */ + def MornyServiceUnavailable (): ResponseIO = + ServiceUnavailable(TelegramImages.IMG_523.get) + .map(_.withContentType(`Content-Type`(MediaType.image.png))) + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/core/http/services/Ping.scala b/src/main/scala/cc/sukazyo/cono/morny/core/http/services/Ping.scala index c2b7fe6..c2881c5 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/core/http/services/Ping.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/core/http/services/Ping.scala @@ -2,14 +2,18 @@ package cc.sukazyo.cono.morny.core.http.services import cats.effect.IO import cc.sukazyo.cono.morny.core.http.api.HttpService4Api +import cc.sukazyo.cono.morny.core.MornySystem +import cc.sukazyo.cono.morny.util.CommonFormat import org.http4s.{HttpRoutes, Response} import org.http4s.circe.jsonEncoder import org.http4s.dsl.io.* class Ping extends HttpService4Api { - case class PingResult ( - pong: Boolean = true + private case class PingResult ( + pong: Boolean = true, + time: String = CommonFormat.formatDate(System.currentTimeMillis(), 0), + server: String = MornySystem.VERSION_FULL, ) override lazy val service: HttpRoutes[IO] = HttpRoutes.of[IO] { diff --git a/src/main/scala/cc/sukazyo/cono/morny/data/TelegramImages.scala b/src/main/scala/cc/sukazyo/cono/morny/data/TelegramImages.scala index e2e4c68..5a7110b 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/data/TelegramImages.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/data/TelegramImages.scala @@ -30,6 +30,7 @@ object TelegramImages { } val IMG_ABOUT: AssetsFileImage = AssetsFileImage("images/featured-image@0.5x.jpg") + val IMG_400: AssetsFileImage = AssetsFileImage("images/http-sekai-400.png") val IMG_404: AssetsFileImage = AssetsFileImage("images/http-sekai-404.png") val IMG_500: AssetsFileImage = AssetsFileImage("images/http-sekai-500.png") val IMG_501: AssetsFileImage = AssetsFileImage("images/http-sekai-501.png") diff --git a/src/main/scala/cc/sukazyo/cono/morny/stickers_get/http/StickerService.scala b/src/main/scala/cc/sukazyo/cono/morny/stickers_get/http/StickerService.scala index f2c0c50..5bf9989 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/stickers_get/http/StickerService.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/stickers_get/http/StickerService.scala @@ -3,14 +3,12 @@ package cc.sukazyo.cono.morny.stickers_get.http import cats.effect.IO import cc.sukazyo.cono.morny.core.http.api.HttpService4Api import cc.sukazyo.cono.morny.core.MornyCoeur -import cc.sukazyo.cono.morny.data.TelegramImages import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.File.getContent import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Requests.execute import com.pengrad.telegrambot.request.GetFile import com.pengrad.telegrambot.TelegramBot -import org.http4s.{HttpRoutes, MediaType} +import org.http4s.HttpRoutes import org.http4s.dsl.io.* -import org.http4s.headers.`Content-Type` import java.io.IOException @@ -28,34 +26,26 @@ class StickerService (using coeur: MornyCoeur) extends HttpService4Api { Ok(file) } catch { case e: IOException => - ServiceUnavailable( - TelegramImages.IMG_523.get, - `Content-Type`(MediaType.image.png), - ).map(_.setMornyInternalErrorHeader(e)) + MornyServiceUnavailable() + .map(_.setMornyInternalErrorHeader(e)) } else - NotFound( - TelegramImages.IMG_404.get, - `Content-Type`(MediaType.image.png), - ).map(_.setMornyInternalErrorHeader( - "_telegram_api", - response.errorCode.toString, - response.description, - )) + MornyNotFound() + .map(_.setMornyInternalErrorHeader( + "_telegram_api", + response.errorCode.toString, + response.description, + )) } catch case io: IOException => - ServiceUnavailable( - TelegramImages.IMG_523.get, - `Content-Type`(MediaType.image.png), - ).map(_.setMornyInternalErrorHeader(io)) + MornyServiceUnavailable() + .map(_.setMornyInternalErrorHeader(io)) case e: Throwable => - InternalServerError( - TelegramImages.IMG_500.get, - `Content-Type`(MediaType.image.png), - ).map(_.setMornyInternalErrorHeader(e)) + MornyInternalServerError() + .map(_.setMornyInternalErrorHeader(e)) - case GET -> Root / "sticker" => - NotFound("not found") + case GET -> "sticker" /: rest => + MornyBadRequest() // TODO: bad request } }