diff --git a/src/main/resources/logback-application.xml b/src/main/resources/logback-application.xml
new file mode 100644
index 0000000..dab4978
--- /dev/null
+++ b/src/main/resources/logback-application.xml
@@ -0,0 +1,27 @@
+
+
+
+
+ [%-5level %d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] [%logger{50}]: %msg%n
+
+
+ application.log
+
+
+ 1
+ 20
+ application.log.%i.gz
+
+
+
+ 100MB
+
+
+
+
+
+ 50000
+ true
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/logback-http.xml b/src/main/resources/logback-http.xml
new file mode 100644
index 0000000..d8d39dd
--- /dev/null
+++ b/src/main/resources/logback-http.xml
@@ -0,0 +1,27 @@
+
+
+
+
+ [%d{yyyy-MM-dd HH:mm:ss.SSS}] %marker %msg%n
+
+
+ http.log
+
+
+ 1
+ 20
+ http.log.%i.gz
+
+
+
+ 100MB
+
+
+
+
+
+ 50000
+ true
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
index 20a0ca5..722a79e 100644
--- a/src/main/resources/logback.xml
+++ b/src/main/resources/logback.xml
@@ -1,5 +1,13 @@
+
+
+
+
+
+
+
+
diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/BiSEndpoint.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/BiSEndpoint.scala
index 5565b23..13dbc12 100644
--- a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/BiSEndpoint.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/BiSEndpoint.scala
@@ -29,7 +29,7 @@ import scala.util.{Failure, Success}
@Path("api/v1")
class BiSEndpoint(override val storage: ActorRef, ariyala: ActorRef)(implicit timeout: Timeout)
- extends BiSHelper(storage, ariyala) with Authorization with JsonSupport with HttpExceptionsHandler {
+ extends BiSHelper(storage, ariyala) with Authorization with JsonSupport with HttpHandler {
def route: Route = createBiS ~ getBiS ~ modifyBiS
@@ -55,14 +55,16 @@ class BiSEndpoint(override val storage: ActorRef, ariyala: ActorRef)(implicit ti
def createBiS: Route =
path("party" / Segment / "bis") { partyId =>
handleExceptions(exceptionHandler) {
- extractExecutionContext { implicit executionContext =>
- authenticateBasicBCrypt(s"party $partyId", authPost(partyId)) { _ =>
- put {
- entity(as[PlayerBiSLinkResponse]) { bisLink =>
- val playerId = bisLink.playerId.withPartyId(partyId)
- onComplete(putBiS(playerId, bisLink.link)) {
- case Success(_) => complete(StatusCodes.Created, HttpEntity.Empty)
- case Failure(exception) => throw exception
+ handleRejections(rejectionHandler) {
+ extractExecutionContext { implicit executionContext =>
+ authenticateBasicBCrypt(s"party $partyId", authPost(partyId)) { _ =>
+ put {
+ entity(as[PlayerBiSLinkResponse]) { bisLink =>
+ val playerId = bisLink.playerId.withPartyId(partyId)
+ onComplete(putBiS(playerId, bisLink.link)) {
+ case Success(_) => complete(StatusCodes.Created, HttpEntity.Empty)
+ case Failure(exception) => throw exception
+ }
}
}
}
@@ -95,17 +97,20 @@ class BiSEndpoint(override val storage: ActorRef, ariyala: ActorRef)(implicit ti
def getBiS: Route =
path("party" / Segment / "bis") { partyId =>
handleExceptions(exceptionHandler) {
- extractExecutionContext { implicit executionContext =>
- authenticateBasicBCrypt(s"party $partyId", authGet(partyId)) { _ =>
- get {
- parameters("nick".as[String].?, "job".as[String].?) { (maybeNick, maybeJob) =>
- val playerId = PlayerId(partyId, maybeNick, maybeJob)
- onComplete(bis(partyId, playerId)) {
- case Success(response) => complete(response.map(PlayerResponse.fromPlayer))
- case Failure(exception) => throw exception
+ handleRejections(rejectionHandler) {
+ extractExecutionContext { implicit executionContext =>
+ authenticateBasicBCrypt(s"party $partyId", authGet(partyId)) { _ =>
+ get {
+ parameters("nick".as[String].?, "job".as[String].?) { (maybeNick, maybeJob) =>
+ val playerId = PlayerId(partyId, maybeNick, maybeJob)
+ onComplete(bis(partyId, playerId)) {
+ case Success(response) => complete(response.map(PlayerResponse.fromPlayer))
+ case Failure(exception) => throw exception
+ }
}
}
}
+
}
}
}
@@ -133,14 +138,16 @@ class BiSEndpoint(override val storage: ActorRef, ariyala: ActorRef)(implicit ti
def modifyBiS: Route =
path("party" / Segment / "bis") { partyId =>
handleExceptions(exceptionHandler) {
- extractExecutionContext { implicit executionContext =>
- authenticateBasicBCrypt(s"party $partyId", authPost(partyId)) { _ =>
- post {
- entity(as[PieceActionResponse]) { action =>
- val playerId = action.playerIdResponse.withPartyId(partyId)
- onComplete(doModifyBiS(action.action, playerId, action.piece.toPiece)) {
- case Success(_) => complete(StatusCodes.Accepted, HttpEntity.Empty)
- case Failure(exception) => throw exception
+ handleRejections(rejectionHandler) {
+ extractExecutionContext { implicit executionContext =>
+ authenticateBasicBCrypt(s"party $partyId", authPost(partyId)) { _ =>
+ post {
+ entity(as[PieceActionResponse]) { action =>
+ val playerId = action.playerIdResponse.withPartyId(partyId)
+ onComplete(doModifyBiS(action.action, playerId, action.piece.toPiece)) {
+ case Success(_) => complete(StatusCodes.Accepted, HttpEntity.Empty)
+ case Failure(exception) => throw exception
+ }
}
}
}
diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/HttpExceptionsHandler.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/HttpExceptionsHandler.scala
deleted file mode 100644
index 75fdd56..0000000
--- a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/HttpExceptionsHandler.scala
+++ /dev/null
@@ -1,16 +0,0 @@
-package me.arcanis.ffxivbis.http.api.v1
-
-import akka.http.scaladsl.model.StatusCodes
-import akka.http.scaladsl.server.Directives._
-import akka.http.scaladsl.server._
-import com.typesafe.scalalogging.StrictLogging
-import me.arcanis.ffxivbis.http.api.v1.json._
-
-trait HttpExceptionsHandler extends StrictLogging { this: JsonSupport =>
-
- def exceptionHandler: ExceptionHandler = ExceptionHandler {
- case other: Exception =>
- logger.error("exception during request completion", other)
- complete(StatusCodes.InternalServerError, ErrorResponse("unknown server error"))
- }
-}
diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/HttpHandler.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/HttpHandler.scala
new file mode 100644
index 0000000..47a51df
--- /dev/null
+++ b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/HttpHandler.scala
@@ -0,0 +1,26 @@
+package me.arcanis.ffxivbis.http.api.v1
+
+import akka.http.scaladsl.model._
+import akka.http.scaladsl.server.Directives._
+import akka.http.scaladsl.server._
+import com.typesafe.scalalogging.StrictLogging
+import me.arcanis.ffxivbis.http.api.v1.json._
+import spray.json._
+
+trait HttpHandler extends StrictLogging { this: JsonSupport =>
+
+ implicit def exceptionHandler: ExceptionHandler = ExceptionHandler {
+ case other: Exception =>
+ logger.error("exception during request completion", other)
+ complete(StatusCodes.InternalServerError, ErrorResponse("unknown server error"))
+ }
+
+ implicit def rejectionHandler: RejectionHandler =
+ RejectionHandler.default
+ .mapRejectionResponse {
+ case response @ HttpResponse(_, _, entity: HttpEntity.Strict, _) =>
+ val message = ErrorResponse(entity.data.utf8String).toJson
+ response.copy(entity = HttpEntity(ContentTypes.`application/json`, message.compactPrint))
+ case other => other
+ }
+}
diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/LootEndpoint.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/LootEndpoint.scala
index 02651d8..35a39b2 100644
--- a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/LootEndpoint.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/LootEndpoint.scala
@@ -28,7 +28,7 @@ import scala.util.{Failure, Success}
@Path("api/v1")
class LootEndpoint(override val storage: ActorRef)(implicit timeout: Timeout)
- extends LootHelper(storage) with Authorization with JsonSupport with HttpExceptionsHandler {
+ extends LootHelper(storage) with Authorization with JsonSupport with HttpHandler {
def route: Route = getLoot ~ modifyLoot
@@ -56,14 +56,16 @@ class LootEndpoint(override val storage: ActorRef)(implicit timeout: Timeout)
def getLoot: Route =
path("party" / Segment / "loot") { partyId =>
handleExceptions(exceptionHandler) {
- extractExecutionContext { implicit executionContext =>
- authenticateBasicBCrypt(s"party $partyId", authGet(partyId)) { _ =>
- get {
- parameters("nick".as[String].?, "job".as[String].?) { (maybeNick, maybeJob) =>
- val playerId = PlayerId(partyId, maybeNick, maybeJob)
- onComplete(loot(partyId, playerId)) {
- case Success(response) => complete(response.map(PlayerResponse.fromPlayer))
- case Failure(exception) => throw exception
+ handleRejections(rejectionHandler) {
+ extractExecutionContext { implicit executionContext =>
+ authenticateBasicBCrypt(s"party $partyId", authGet(partyId)) { _ =>
+ get {
+ parameters("nick".as[String].?, "job".as[String].?) { (maybeNick, maybeJob) =>
+ val playerId = PlayerId(partyId, maybeNick, maybeJob)
+ onComplete(loot(partyId, playerId)) {
+ case Success(response) => complete(response.map(PlayerResponse.fromPlayer))
+ case Failure(exception) => throw exception
+ }
}
}
}
@@ -94,14 +96,16 @@ class LootEndpoint(override val storage: ActorRef)(implicit timeout: Timeout)
def modifyLoot: Route =
path("party" / Segment / "loot") { partyId =>
handleExceptions(exceptionHandler) {
- extractExecutionContext { implicit executionContext =>
- authenticateBasicBCrypt(s"party $partyId", authPost(partyId)) { _ =>
- post {
- entity(as[PieceActionResponse]) { action =>
- val playerId = action.playerIdResponse.withPartyId(partyId)
- onComplete(doModifyLoot(action.action, playerId, action.piece.toPiece)) {
- case Success(_) => complete(StatusCodes.Accepted, HttpEntity.Empty)
- case Failure(exception) => throw exception
+ handleRejections(rejectionHandler) {
+ extractExecutionContext { implicit executionContext =>
+ authenticateBasicBCrypt(s"party $partyId", authPost(partyId)) { _ =>
+ post {
+ entity(as[PieceActionResponse]) { action =>
+ val playerId = action.playerIdResponse.withPartyId(partyId)
+ onComplete(doModifyLoot(action.action, playerId, action.piece.toPiece)) {
+ case Success(_) => complete(StatusCodes.Accepted, HttpEntity.Empty)
+ case Failure(exception) => throw exception
+ }
}
}
}
@@ -136,13 +140,15 @@ class LootEndpoint(override val storage: ActorRef)(implicit timeout: Timeout)
def suggestLoot: Route =
path("party" / Segment / "loot") { partyId =>
handleExceptions(exceptionHandler) {
- extractExecutionContext { implicit executionContext =>
- authenticateBasicBCrypt(s"party $partyId", authGet(partyId)) { _ =>
- put {
- entity(as[PieceResponse]) { piece =>
- onComplete(suggestPiece(partyId, piece.toPiece)) {
- case Success(response) => complete(response.map(PlayerIdWithCountersResponse.fromPlayerId))
- case Failure(exception) => throw exception
+ handleRejections(rejectionHandler) {
+ extractExecutionContext { implicit executionContext =>
+ authenticateBasicBCrypt(s"party $partyId", authGet(partyId)) { _ =>
+ put {
+ entity(as[PieceResponse]) { piece =>
+ onComplete(suggestPiece(partyId, piece.toPiece)) {
+ case Success(response) => complete(response.map(PlayerIdWithCountersResponse.fromPlayerId))
+ case Failure(exception) => throw exception
+ }
}
}
}
diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/PlayerEndpoint.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/PlayerEndpoint.scala
index 8506027..fb6e7c3 100644
--- a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/PlayerEndpoint.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/PlayerEndpoint.scala
@@ -28,7 +28,7 @@ import scala.util.{Failure, Success}
@Path("api/v1")
class PlayerEndpoint(override val storage: ActorRef, ariyala: ActorRef)(implicit timeout: Timeout)
- extends PlayerHelper(storage, ariyala) with Authorization with JsonSupport with HttpExceptionsHandler {
+ extends PlayerHelper(storage, ariyala) with Authorization with JsonSupport with HttpHandler {
def route: Route = getParty ~ modifyParty
@@ -56,14 +56,16 @@ class PlayerEndpoint(override val storage: ActorRef, ariyala: ActorRef)(implicit
def getParty: Route =
path("party" / Segment) { partyId =>
handleExceptions(exceptionHandler) {
- extractExecutionContext { implicit executionContext =>
- authenticateBasicBCrypt(s"party $partyId", authGet(partyId)) { _ =>
- get {
- parameters("nick".as[String].?, "job".as[String].?) { (maybeNick, maybeJob) =>
- val playerId = PlayerId(partyId, maybeNick, maybeJob)
- onComplete(getPlayers(partyId, playerId)) {
- case Success(response) => complete(response.map(PlayerResponse.fromPlayer))
- case Failure(exception) => throw exception
+ handleRejections(rejectionHandler) {
+ extractExecutionContext { implicit executionContext =>
+ authenticateBasicBCrypt(s"party $partyId", authGet(partyId)) { _ =>
+ get {
+ parameters("nick".as[String].?, "job".as[String].?) { (maybeNick, maybeJob) =>
+ val playerId = PlayerId(partyId, maybeNick, maybeJob)
+ onComplete(getPlayers(partyId, playerId)) {
+ case Success(response) => complete(response.map(PlayerResponse.fromPlayer))
+ case Failure(exception) => throw exception
+ }
}
}
}
@@ -94,13 +96,15 @@ class PlayerEndpoint(override val storage: ActorRef, ariyala: ActorRef)(implicit
def modifyParty: Route =
path("party" / Segment) { partyId =>
handleExceptions(exceptionHandler) {
- extractExecutionContext { implicit executionContext =>
- authenticateBasicBCrypt(s"party $partyId", authPost(partyId)) { _ =>
- entity(as[PlayerActionResponse]) { action =>
- val player = action.playerIdResponse.toPlayer.copy(partyId = partyId)
- onComplete(doModifyPlayer(action.action, player)) {
- case Success(_) => complete(StatusCodes.Accepted, HttpEntity.Empty)
- case Failure(exception) => throw exception
+ handleRejections(rejectionHandler) {
+ extractExecutionContext { implicit executionContext =>
+ authenticateBasicBCrypt(s"party $partyId", authPost(partyId)) { _ =>
+ entity(as[PlayerActionResponse]) { action =>
+ val player = action.playerIdResponse.toPlayer.copy(partyId = partyId)
+ onComplete(doModifyPlayer(action.action, player)) {
+ case Success(_) => complete(StatusCodes.Accepted, HttpEntity.Empty)
+ case Failure(exception) => throw exception
+ }
}
}
}
diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/UserEndpoint.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/UserEndpoint.scala
index b9e33fc..f7d51d3 100644
--- a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/UserEndpoint.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/UserEndpoint.scala
@@ -28,7 +28,7 @@ import scala.util.{Failure, Success}
@Path("api/v1")
class UserEndpoint(override val storage: ActorRef)(implicit timeout: Timeout)
- extends UserHelper(storage) with Authorization with JsonSupport with HttpExceptionsHandler {
+ extends UserHelper(storage) with Authorization with JsonSupport with HttpHandler {
def route: Route = createParty ~ createUser ~ deleteUser ~ getUsers
@@ -52,13 +52,15 @@ class UserEndpoint(override val storage: ActorRef)(implicit timeout: Timeout)
def createParty: Route =
path("party" / Segment / "create") { partyId =>
handleExceptions(exceptionHandler) {
- extractExecutionContext { implicit executionContext =>
- put {
- entity(as[UserResponse]) { user =>
- val admin = user.toUser.copy(partyId = partyId, permission = Permission.admin)
- onComplete(addUser(admin, isHashedPassword = false)) {
- case Success(_) => complete(StatusCodes.Created, HttpEntity.Empty)
- case Failure(exception) => throw exception
+ handleRejections(rejectionHandler) {
+ extractExecutionContext { implicit executionContext =>
+ put {
+ entity(as[UserResponse]) { user =>
+ val admin = user.toUser.copy(partyId = partyId, permission = Permission.admin)
+ onComplete(addUser(admin, isHashedPassword = false)) {
+ case Success(_) => complete(StatusCodes.Created, HttpEntity.Empty)
+ case Failure(exception) => throw exception
+ }
}
}
}
@@ -88,14 +90,16 @@ class UserEndpoint(override val storage: ActorRef)(implicit timeout: Timeout)
def createUser: Route =
path("party" / Segment / "users") { partyId =>
handleExceptions(exceptionHandler) {
- extractExecutionContext { implicit executionContext =>
- authenticateBasicBCrypt(s"party $partyId", authAdmin(partyId)) { _ =>
- post {
- entity(as[UserResponse]) { user =>
- val withPartyId = user.toUser.copy(partyId = partyId)
- onComplete(addUser(withPartyId, isHashedPassword = false)) {
- case Success(_) => complete(StatusCodes.Accepted, HttpEntity.Empty)
- case Failure(exception) => throw exception
+ handleRejections(rejectionHandler) {
+ extractExecutionContext { implicit executionContext =>
+ authenticateBasicBCrypt(s"party $partyId", authAdmin(partyId)) { _ =>
+ post {
+ entity(as[UserResponse]) { user =>
+ val withPartyId = user.toUser.copy(partyId = partyId)
+ onComplete(addUser(withPartyId, isHashedPassword = false)) {
+ case Success(_) => complete(StatusCodes.Accepted, HttpEntity.Empty)
+ case Failure(exception) => throw exception
+ }
}
}
}
@@ -123,12 +127,14 @@ class UserEndpoint(override val storage: ActorRef)(implicit timeout: Timeout)
def deleteUser: Route =
path("party" / Segment / "users" / Segment) { (partyId, username) =>
handleExceptions(exceptionHandler) {
- extractExecutionContext { implicit executionContext =>
- authenticateBasicBCrypt(s"party $partyId", authAdmin(partyId)) { _ =>
- delete {
- onComplete(removeUser(partyId, username)) {
- case Success(_) => complete(StatusCodes.Accepted, HttpEntity.Empty)
- case Failure(exception) => throw exception
+ handleRejections(rejectionHandler) {
+ extractExecutionContext { implicit executionContext =>
+ authenticateBasicBCrypt(s"party $partyId", authAdmin(partyId)) { _ =>
+ delete {
+ onComplete(removeUser(partyId, username)) {
+ case Success(_) => complete(StatusCodes.Accepted, HttpEntity.Empty)
+ case Failure(exception) => throw exception
+ }
}
}
}
@@ -158,12 +164,14 @@ class UserEndpoint(override val storage: ActorRef)(implicit timeout: Timeout)
def getUsers: Route =
path("party" / Segment / "users") { partyId =>
handleExceptions(exceptionHandler) {
- extractExecutionContext { implicit executionContext =>
- authenticateBasicBCrypt(s"party $partyId", authAdmin(partyId)) { _ =>
- get {
- onComplete(users(partyId)) {
- case Success(response) => complete(response.map(UserResponse.fromUser))
- case Failure(exception) => throw exception
+ handleRejections(rejectionHandler) {
+ extractExecutionContext { implicit executionContext =>
+ authenticateBasicBCrypt(s"party $partyId", authAdmin(partyId)) { _ =>
+ get {
+ onComplete(users(partyId)) {
+ case Success(response) => complete(response.map(UserResponse.fromUser))
+ case Failure(exception) => throw exception
+ }
}
}
}