mirror of
https://github.com/arcan1s/ffxivbis.git
synced 2025-07-08 11:25:52 +00:00
Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
7a6cd84ce3 | |||
33b750123d | |||
d049238dcf | |||
5d72852420 | |||
78a00e2cab |
1
.gitignore
vendored
1
.gitignore
vendored
@ -75,6 +75,7 @@ lib_managed/
|
|||||||
src_managed/
|
src_managed/
|
||||||
project/boot/
|
project/boot/
|
||||||
project/plugins/project/
|
project/plugins/project/
|
||||||
|
.bsp/
|
||||||
|
|
||||||
# Scala-IDE specific
|
# Scala-IDE specific
|
||||||
.scala_dependencies
|
.scala_dependencies
|
||||||
|
11
build.sbt
11
build.sbt
@ -1,3 +1,5 @@
|
|||||||
|
organization := "me.arcanis"
|
||||||
|
|
||||||
name := "ffxivbis"
|
name := "ffxivbis"
|
||||||
|
|
||||||
scalaVersion := "2.13.6"
|
scalaVersion := "2.13.6"
|
||||||
@ -5,12 +7,3 @@ scalaVersion := "2.13.6"
|
|||||||
scalacOptions ++= Seq("-deprecation", "-feature")
|
scalacOptions ++= Seq("-deprecation", "-feature")
|
||||||
|
|
||||||
enablePlugins(JavaAppPackaging)
|
enablePlugins(JavaAppPackaging)
|
||||||
|
|
||||||
assemblyMergeStrategy in assembly := {
|
|
||||||
case PathList("META-INF", xs @ _*) => MergeStrategy.discard
|
|
||||||
case "application.conf" => MergeStrategy.concat
|
|
||||||
case "module-info.class" => MergeStrategy.first
|
|
||||||
case x =>
|
|
||||||
val oldStrategy = (assemblyMergeStrategy in assembly).value
|
|
||||||
oldStrategy(x)
|
|
||||||
}
|
|
@ -1 +1 @@
|
|||||||
sbt.version = 1.3.3
|
sbt.version = 1.5.8
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6")
|
|
||||||
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.3")
|
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.3")
|
||||||
|
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.3")
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.4")
|
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.4")
|
||||||
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.10.0-RC1")
|
addDependencyTreePlugin
|
||||||
|
@ -11,6 +11,6 @@
|
|||||||
<appender-ref ref="http" />
|
<appender-ref ref="http" />
|
||||||
</logger>
|
</logger>
|
||||||
<logger name="org.flywaydb.core.internal" level="INFO" />
|
<logger name="org.flywaydb.core.internal" level="INFO" />
|
||||||
<logger name="com.zaxxer.hikari.pool.HikariPool" level="INFO" />
|
<logger name="com.zaxxer.hikari.pool" level="INFO" />
|
||||||
|
|
||||||
</configuration>
|
</configuration>
|
||||||
|
@ -13,8 +13,8 @@ import akka.http.scaladsl.server.Directive0
|
|||||||
import akka.http.scaladsl.server.Directives.{extractClientIP, extractRequestContext, mapResponse, optionalHeaderValueByType}
|
import akka.http.scaladsl.server.Directives.{extractClientIP, extractRequestContext, mapResponse, optionalHeaderValueByType}
|
||||||
import com.typesafe.scalalogging.Logger
|
import com.typesafe.scalalogging.Logger
|
||||||
|
|
||||||
import java.time.{Instant, ZoneId}
|
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
|
import java.time.{Instant, ZoneId}
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
trait HttpLog {
|
trait HttpLog {
|
||||||
@ -68,7 +68,7 @@ object HttpLog {
|
|||||||
|
|
||||||
val httpLogDatetimeFormatter: DateTimeFormatter =
|
val httpLogDatetimeFormatter: DateTimeFormatter =
|
||||||
DateTimeFormatter
|
DateTimeFormatter
|
||||||
.ofPattern("dd/MMM/uuuu:HH:mm:ss xx ")
|
.ofPattern("dd/MMM/uuuu:HH:mm:ss xx")
|
||||||
.withLocale(Locale.UK)
|
.withLocale(Locale.UK)
|
||||||
.withZone(ZoneId.systemDefault())
|
.withZone(ZoneId.systemDefault())
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ class RootEndpoint(system: ActorSystem[Nothing], storage: ActorRef[Message], pro
|
|||||||
private val config = system.settings.config
|
private val config = system.settings.config
|
||||||
|
|
||||||
implicit val scheduler: Scheduler = system.scheduler
|
implicit val scheduler: Scheduler = system.scheduler
|
||||||
implicit val timeout: Timeout = config.getDuration("me.arcanis.ffxivbis.settings.request-timeout")
|
implicit val timeout: Timeout = config.getTimeout("me.arcanis.ffxivbis.settings.request-timeout")
|
||||||
|
|
||||||
private val auth = AuthorizationProvider(config, storage, timeout, scheduler)
|
private val auth = AuthorizationProvider(config, storage, timeout, scheduler)
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ class Swagger(config: Config) extends SwaggerHttpService {
|
|||||||
classOf[api.v1.LootEndpoint],
|
classOf[api.v1.LootEndpoint],
|
||||||
classOf[api.v1.PartyEndpoint],
|
classOf[api.v1.PartyEndpoint],
|
||||||
classOf[api.v1.PlayerEndpoint],
|
classOf[api.v1.PlayerEndpoint],
|
||||||
|
classOf[api.v1.StatusEndpoint],
|
||||||
classOf[api.v1.TypesEndpoint],
|
classOf[api.v1.TypesEndpoint],
|
||||||
classOf[api.v1.UserEndpoint]
|
classOf[api.v1.UserEndpoint]
|
||||||
)
|
)
|
||||||
@ -35,7 +36,7 @@ class Swagger(config: Config) extends SwaggerHttpService {
|
|||||||
|
|
||||||
override val host: String =
|
override val host: String =
|
||||||
if (config.hasPath("me.arcanis.ffxivbis.web.hostname")) config.getString("me.arcanis.ffxivbis.web.hostname")
|
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()
|
private val basicAuth = new SecurityScheme()
|
||||||
.description("basic http auth")
|
.description("basic http auth")
|
||||||
|
@ -32,14 +32,15 @@ class RootApiV1Endpoint(
|
|||||||
private val lootEndpoint = new LootEndpoint(storage, auth)
|
private val lootEndpoint = new LootEndpoint(storage, auth)
|
||||||
private val partyEndpoint = new PartyEndpoint(storage, provider, auth)
|
private val partyEndpoint = new PartyEndpoint(storage, provider, auth)
|
||||||
private val playerEndpoint = new PlayerEndpoint(storage, provider, auth)
|
private val playerEndpoint = new PlayerEndpoint(storage, provider, auth)
|
||||||
|
private val statusEndpoint = new StatusEndpoint
|
||||||
private val typesEndpoint = new TypesEndpoint(config)
|
private val typesEndpoint = new TypesEndpoint(config)
|
||||||
private val userEndpoint = new UserEndpoint(storage, auth)
|
private val userEndpoint = new UserEndpoint(storage, auth)
|
||||||
|
|
||||||
def route: Route =
|
def route: Route =
|
||||||
handleExceptions(exceptionHandler) {
|
handleExceptions(exceptionHandler) {
|
||||||
handleRejections(rejectionHandler) {
|
handleRejections(rejectionHandler) {
|
||||||
biSEndpoint.route ~ lootEndpoint.route ~ partyEndpoint.route ~
|
biSEndpoint.route ~ lootEndpoint.route ~ partyEndpoint.route ~ playerEndpoint.route ~
|
||||||
playerEndpoint.route ~ typesEndpoint.route ~ userEndpoint.route
|
statusEndpoint.route ~ typesEndpoint.route ~ userEndpoint.route
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -52,5 +52,6 @@ trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol {
|
|||||||
implicit val playerBiSLinkFormat: RootJsonFormat[PlayerBiSLinkModel] = jsonFormat2(PlayerBiSLinkModel.apply)
|
implicit val playerBiSLinkFormat: RootJsonFormat[PlayerBiSLinkModel] = jsonFormat2(PlayerBiSLinkModel.apply)
|
||||||
implicit val playerIdWithCountersFormat: RootJsonFormat[PlayerIdWithCountersModel] =
|
implicit val playerIdWithCountersFormat: RootJsonFormat[PlayerIdWithCountersModel] =
|
||||||
jsonFormat9(PlayerIdWithCountersModel.apply)
|
jsonFormat9(PlayerIdWithCountersModel.apply)
|
||||||
|
implicit val statusFormat: RootJsonFormat[StatusModel] = jsonFormat1(StatusModel.apply)
|
||||||
implicit val userFormat: RootJsonFormat[UserModel] = jsonFormat4(UserModel.apply)
|
implicit val userFormat: RootJsonFormat[UserModel] = jsonFormat4(UserModel.apply)
|
||||||
}
|
}
|
||||||
|
@ -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])
|
@ -24,14 +24,14 @@ class PartyService(context: ActorContext[Message], storage: ActorRef[DatabaseMes
|
|||||||
with StrictLogging {
|
with StrictLogging {
|
||||||
import me.arcanis.ffxivbis.utils.Implicits._
|
import me.arcanis.ffxivbis.utils.Implicits._
|
||||||
|
|
||||||
private val cacheTimeout: FiniteDuration =
|
private val cacheTimeout =
|
||||||
context.system.settings.config.getDuration("me.arcanis.ffxivbis.settings.cache-timeout")
|
context.system.settings.config.getFiniteDuration("me.arcanis.ffxivbis.settings.cache-timeout")
|
||||||
implicit private val executionContext: ExecutionContext = {
|
implicit private val executionContext: ExecutionContext = {
|
||||||
val selector = DispatcherSelector.fromConfig("me.arcanis.ffxivbis.default-dispatcher")
|
val selector = DispatcherSelector.fromConfig("me.arcanis.ffxivbis.default-dispatcher")
|
||||||
context.system.dispatchers.lookup(selector)
|
context.system.dispatchers.lookup(selector)
|
||||||
}
|
}
|
||||||
implicit private val timeout: Timeout =
|
implicit private val timeout: Timeout =
|
||||||
context.system.settings.config.getDuration("me.arcanis.ffxivbis.settings.request-timeout")
|
context.system.settings.config.getTimeout("me.arcanis.ffxivbis.settings.request-timeout")
|
||||||
implicit private val scheduler: Scheduler = context.system.scheduler
|
implicit private val scheduler: Scheduler = context.system.scheduler
|
||||||
|
|
||||||
override def onMessage(msg: Message): Behavior[Message] = handle(Map.empty)(msg)
|
override def onMessage(msg: Message): Behavior[Message] = handle(Map.empty)(msg)
|
||||||
|
@ -11,7 +11,6 @@ package me.arcanis.ffxivbis.utils
|
|||||||
import akka.util.Timeout
|
import akka.util.Timeout
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
|
|
||||||
import java.time.Duration
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import scala.concurrent.duration.FiniteDuration
|
import scala.concurrent.duration.FiniteDuration
|
||||||
import scala.language.implicitConversions
|
import scala.language.implicitConversions
|
||||||
@ -19,20 +18,14 @@ import scala.util.Try
|
|||||||
|
|
||||||
object Implicits {
|
object Implicits {
|
||||||
|
|
||||||
implicit def getBooleanFromOptionString(maybeYes: Option[String]): Boolean = maybeYes.map(_.toLowerCase) match {
|
|
||||||
case Some("yes" | "on") => true
|
|
||||||
case _ => false
|
|
||||||
}
|
|
||||||
|
|
||||||
implicit def getFiniteDuration(duration: Duration): FiniteDuration =
|
|
||||||
FiniteDuration(duration.toNanos, TimeUnit.NANOSECONDS)
|
|
||||||
|
|
||||||
implicit def getTimeout(duration: Duration): Timeout =
|
|
||||||
FiniteDuration(duration.toNanos, TimeUnit.NANOSECONDS)
|
|
||||||
|
|
||||||
implicit class ConfigExtension(config: Config) {
|
implicit class ConfigExtension(config: Config) {
|
||||||
|
|
||||||
|
def getFiniteDuration(path: String): FiniteDuration =
|
||||||
|
FiniteDuration(config.getDuration(path, TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS)
|
||||||
|
|
||||||
def getOptString(path: String): Option[String] =
|
def getOptString(path: String): Option[String] =
|
||||||
Try(config.getString(path)).toOption.filter(_.nonEmpty)
|
Try(config.getString(path)).toOption.filter(_.nonEmpty)
|
||||||
|
|
||||||
|
def getTimeout(path: String): Timeout = getFiniteDuration(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
version := "0.11.1"
|
version := "0.12.1"
|
||||||
|
Reference in New Issue
Block a user