From 5d72852420518c4d235a1adece645797ae485eee Mon Sep 17 00:00:00 2001 From: Evgeniy Alekseev Date: Mon, 17 Jan 2022 16:57:32 +0300 Subject: [PATCH] add status endpoint --- build.sbt | 3 ++ project/build.properties | 2 +- src/main/resources/logback.xml | 2 +- src/main/resources/reference.conf | 16 +++--- .../me/arcanis/ffxivbis/http/HttpLog.scala | 4 +- .../me/arcanis/ffxivbis/http/Swagger.scala | 3 +- .../http/api/v1/RootApiV1Endpoint.scala | 5 +- .../ffxivbis/http/api/v1/StatusEndpoint.scala | 54 +++++++++++++++++++ .../http/api/v1/json/JsonSupport.scala | 1 + .../http/api/v1/json/StatusModel.scala | 13 +++++ .../http/api/v1/StatusEndpointTest.scala | 29 ++++++++++ 11 files changed, 117 insertions(+), 15 deletions(-) create mode 100644 src/main/scala/me/arcanis/ffxivbis/http/api/v1/StatusEndpoint.scala create mode 100644 src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/StatusModel.scala create mode 100644 src/test/scala/me/arcanis/ffxivbis/http/api/v1/StatusEndpointTest.scala diff --git a/build.sbt b/build.sbt index 33b8c82..c62bf66 100644 --- a/build.sbt +++ b/build.sbt @@ -1,3 +1,5 @@ +organization := "me.arcanis" + name := "ffxivbis" scalaVersion := "2.13.6" @@ -5,3 +7,4 @@ scalaVersion := "2.13.6" scalacOptions ++= Seq("-deprecation", "-feature") enablePlugins(JavaAppPackaging) +coverageEnabled := true diff --git a/project/build.properties b/project/build.properties index dd4ff43..f4f743c 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version = 1.6.1 +sbt.version = 1.5.8 diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 3a4ce88..818cea7 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -11,6 +11,6 @@ - + diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index d43d85f..09ec40b 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -57,14 +57,14 @@ me.arcanis.ffxivbis { # ttl of cached logins cache-timeout = 1m } - } + } - default-dispatcher { - type = Dispatcher - executor = "thread-pool-executor" - thread-pool-executor { - fixed-pool-size = 16 + default-dispatcher { + type = Dispatcher + executor = "thread-pool-executor" + thread-pool-executor { + fixed-pool-size = 16 + } + throughput = 1 } - throughput = 1 - } } diff --git a/src/main/scala/me/arcanis/ffxivbis/http/HttpLog.scala b/src/main/scala/me/arcanis/ffxivbis/http/HttpLog.scala index 0e8b4b4..1ea4b68 100644 --- a/src/main/scala/me/arcanis/ffxivbis/http/HttpLog.scala +++ b/src/main/scala/me/arcanis/ffxivbis/http/HttpLog.scala @@ -13,8 +13,8 @@ import akka.http.scaladsl.server.Directive0 import akka.http.scaladsl.server.Directives.{extractClientIP, extractRequestContext, mapResponse, optionalHeaderValueByType} import com.typesafe.scalalogging.Logger -import java.time.{Instant, ZoneId} import java.time.format.DateTimeFormatter +import java.time.{Instant, ZoneId} import java.util.Locale trait HttpLog { @@ -68,7 +68,7 @@ object HttpLog { val httpLogDatetimeFormatter: DateTimeFormatter = DateTimeFormatter - .ofPattern("dd/MMM/uuuu:HH:mm:ss xx ") + .ofPattern("dd/MMM/uuuu:HH:mm:ss xx") .withLocale(Locale.UK) .withZone(ZoneId.systemDefault()) } diff --git a/src/main/scala/me/arcanis/ffxivbis/http/Swagger.scala b/src/main/scala/me/arcanis/ffxivbis/http/Swagger.scala index c4da73e..1958dbd 100644 --- a/src/main/scala/me/arcanis/ffxivbis/http/Swagger.scala +++ b/src/main/scala/me/arcanis/ffxivbis/http/Swagger.scala @@ -22,6 +22,7 @@ class Swagger(config: Config) extends SwaggerHttpService { classOf[api.v1.LootEndpoint], classOf[api.v1.PartyEndpoint], classOf[api.v1.PlayerEndpoint], + classOf[api.v1.StatusEndpoint], classOf[api.v1.TypesEndpoint], classOf[api.v1.UserEndpoint] ) @@ -35,7 +36,7 @@ class Swagger(config: Config) extends SwaggerHttpService { override val host: String = if (config.hasPath("me.arcanis.ffxivbis.web.hostname")) config.getString("me.arcanis.ffxivbis.web.hostname") - else s"${config.getString("me.arcanis.ffxivbis.web.host")}:${config.getString("me.arcanis.ffxivbis.web.port")}" + else s"${config.getString("me.arcanis.ffxivbis.web.host")}:${config.getInt("me.arcanis.ffxivbis.web.port")}" private val basicAuth = new SecurityScheme() .description("basic http auth") diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/RootApiV1Endpoint.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/RootApiV1Endpoint.scala index 0fecf00..304577e 100644 --- a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/RootApiV1Endpoint.scala +++ b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/RootApiV1Endpoint.scala @@ -32,14 +32,15 @@ class RootApiV1Endpoint( private val lootEndpoint = new LootEndpoint(storage, auth) private val partyEndpoint = new PartyEndpoint(storage, provider, auth) private val playerEndpoint = new PlayerEndpoint(storage, provider, auth) + private val statusEndpoint = new StatusEndpoint private val typesEndpoint = new TypesEndpoint(config) private val userEndpoint = new UserEndpoint(storage, auth) def route: Route = handleExceptions(exceptionHandler) { handleRejections(rejectionHandler) { - biSEndpoint.route ~ lootEndpoint.route ~ partyEndpoint.route ~ - playerEndpoint.route ~ typesEndpoint.route ~ userEndpoint.route + biSEndpoint.route ~ lootEndpoint.route ~ partyEndpoint.route ~ playerEndpoint.route ~ + statusEndpoint.route ~ typesEndpoint.route ~ userEndpoint.route } } } diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/StatusEndpoint.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/StatusEndpoint.scala new file mode 100644 index 0000000..7523b3a --- /dev/null +++ b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/StatusEndpoint.scala @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019-2022 Evgeniy Alekseev. + * + * This file is part of ffxivbis + * (see https://github.com/arcan1s/ffxivbis). + * + * License: 3-clause BSD, see https://opensource.org/licenses/BSD-3-Clause + */ +package me.arcanis.ffxivbis.http.api.v1 + +import akka.http.scaladsl.server.Directives._ +import akka.http.scaladsl.server._ +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.media.{Content, Schema} +import io.swagger.v3.oas.annotations.responses.ApiResponse +import jakarta.ws.rs._ +import me.arcanis.ffxivbis.http.api.v1.json._ + +@Path("/api/v1") +class StatusEndpoint extends JsonSupport { + + def route: Route = getServerStatus + + @GET + @Path("status") + @Produces(value = Array("application/json")) + @Operation( + summary = "server status", + description = "Returns the server status descriptor", + responses = Array( + new ApiResponse( + responseCode = "200", + description = "Service status descriptor", + content = Array(new Content(schema = new Schema(implementation = classOf[StatusModel]))) + ), + new ApiResponse( + responseCode = "500", + description = "Internal server error", + content = Array(new Content(schema = new Schema(implementation = classOf[ErrorModel]))) + ), + ), + tags = Array("status"), + ) + def getServerStatus: Route = + path("status") { + get { + complete { + StatusModel( + version = Option(getClass.getPackage.getImplementationVersion), + ) + } + } + } +} diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/JsonSupport.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/JsonSupport.scala index 85e6bbc..6527958 100644 --- a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/JsonSupport.scala +++ b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/JsonSupport.scala @@ -52,5 +52,6 @@ trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol { implicit val playerBiSLinkFormat: RootJsonFormat[PlayerBiSLinkModel] = jsonFormat2(PlayerBiSLinkModel.apply) implicit val playerIdWithCountersFormat: RootJsonFormat[PlayerIdWithCountersModel] = jsonFormat9(PlayerIdWithCountersModel.apply) + implicit val statusFormat: RootJsonFormat[StatusModel] = jsonFormat1(StatusModel.apply) implicit val userFormat: RootJsonFormat[UserModel] = jsonFormat4(UserModel.apply) } diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/StatusModel.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/StatusModel.scala new file mode 100644 index 0000000..290f2c1 --- /dev/null +++ b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/StatusModel.scala @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2019-2022 Evgeniy Alekseev. + * + * This file is part of ffxivbis + * (see https://github.com/arcan1s/ffxivbis). + * + * License: 3-clause BSD, see https://opensource.org/licenses/BSD-3-Clause + */ +package me.arcanis.ffxivbis.http.api.v1.json + +import io.swagger.v3.oas.annotations.media.Schema + +case class StatusModel(@Schema(description = "server version") version: Option[String]) diff --git a/src/test/scala/me/arcanis/ffxivbis/http/api/v1/StatusEndpointTest.scala b/src/test/scala/me/arcanis/ffxivbis/http/api/v1/StatusEndpointTest.scala new file mode 100644 index 0000000..9d652d1 --- /dev/null +++ b/src/test/scala/me/arcanis/ffxivbis/http/api/v1/StatusEndpointTest.scala @@ -0,0 +1,29 @@ +package me.arcanis.ffxivbis.http.api.v1 + +import akka.http.scaladsl.model.StatusCodes +import akka.http.scaladsl.testkit.ScalatestRouteTest +import com.typesafe.config.Config +import me.arcanis.ffxivbis.Settings +import me.arcanis.ffxivbis.http.api.v1.json._ +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpecLike + +import scala.language.postfixOps + +class StatusEndpointTest extends AnyWordSpecLike + with Matchers with ScalatestRouteTest with JsonSupport { + + override val testConfig: Config = Settings.withRandomDatabase + + private val route = new StatusEndpoint().route + + "api v1 status endpoint" must { + + "return server status" in { + Get("/status") ~> route ~> check { + status shouldEqual StatusCodes.OK + } + } + + } +}