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
}
- throughput = 1
- }
+
+ default-dispatcher {
+ type = Dispatcher
+ executor = "thread-pool-executor"
+ thread-pool-executor {
+ fixed-pool-size = 16
+ }
+ 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
+ }
+ }
+
+ }
+}