Skip to content

Commit

Permalink
Merge pull request #272 from innFactory/feat/jsoniterConfig
Browse files Browse the repository at this point in the history
feat: setting jsoniter config with application.conf
  • Loading branch information
MoeQuadrat authored Apr 17, 2024
2 parents 5ac774e + c10c137 commit ea00694
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.innfactory.smithy4play

import com.github.plokhotnyuk.jsoniter_scala.core.ReaderConfig
import de.innfactory.smithy4play.middleware.MiddlewareBase
import play.api.mvc.ControllerComponents
import play.api.routing.Router.Routes
Expand All @@ -17,9 +18,9 @@ trait AutoRoutableController {
service: smithy4s.Service[Alg],
ec: ExecutionContext,
cc: ControllerComponents
): Seq[MiddlewareBase] => Routes = (middlewares: Seq[MiddlewareBase]) =>
new SmithyPlayRouter[Alg, F](impl, service).routes(middlewares)
): (Seq[MiddlewareBase], ReaderConfig) => Routes = (middlewares: Seq[MiddlewareBase], readerConfig: ReaderConfig) =>
new SmithyPlayRouter[Alg, F](impl, service).routes(middlewares, readerConfig)

val router: Seq[MiddlewareBase] => Routes
val router: (Seq[MiddlewareBase], ReaderConfig) => Routes

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.innfactory.smithy4play

import com.github.plokhotnyuk.jsoniter_scala.core.ReaderConfig
import com.typesafe.config.Config
import de.innfactory.smithy4play.middleware.{ MiddlewareBase, MiddlewareRegistryBase, ValidateAuthMiddleware }
import io.github.classgraph.{ ClassGraph, ScanResult }
Expand All @@ -22,7 +23,8 @@ class AutoRouter @Inject(
config: Config
) extends BaseRouter {

private val pkg = config.getString("smithy4play.autoRoutePackage")
private val pkg = config.getString("smithy4play.autoRoutePackage")
private val readerConfig = ReaderConfig.fromApplicationConfig(config)

override val controllers: Seq[Routes] = {
val classGraphScanner: ScanResult = new ClassGraph().enableAllInfo().acceptPackages(pkg).scan()
Expand All @@ -39,7 +41,7 @@ class AutoRouter @Inject(

private def createFromClass(clazz: Class[_], middlewares: Seq[MiddlewareBase]): Routes =
app.injector.instanceOf(clazz) match {
case c: AutoRoutableController => c.router(middlewares)
case c: AutoRoutableController => c.router(middlewares, readerConfig)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ object AutoRoutingMacro {
with ..$parentss
with de.innfactory.smithy4play.AutoRoutableController
{ $self =>
override val router: Seq[de.innfactory.smithy4play.middleware.MiddlewareBase] => play.api.routing.Router.Routes = this
override val router:
(Seq[de.innfactory.smithy4play.middleware.MiddlewareBase], com.github.plokhotnyuk.jsoniter_scala.core.ReaderConfig)
=> play.api.routing.Router.Routes = this
..$body }
"""
case _ =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.innfactory.smithy4play

import com.github.plokhotnyuk.jsoniter_scala.core.ReaderConfig
import play.api.http.MimeTypes
import smithy4s.capability.instances.either._
import smithy4s.codecs.Writer.CachedCompiler
Expand All @@ -11,12 +12,13 @@ import smithy4s.schema.CachedSchemaCompiler
import smithy4s.xml.Xml
import smithy4s.{ codecs, Blob }

object CodecDecider {
case class CodecDecider(readerConfig: ReaderConfig) {

private val jsonCodecs = Json.payloadCodecs
.withJsoniterCodecCompiler(
Json.jsoniter
)
.withJsoniterReaderConfig(readerConfig)

private val jsonEncoder: BlobEncoder.Compiler = jsonCodecs.encoders
private val jsonDecoder: BlobDecoder.Compiler = jsonCodecs.decoders
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,24 @@
package de.innfactory.smithy4play

import alloy.SimpleRestJson
import aws.protocols.RestXml
import cats.data.{ EitherT, Kleisli }
import de.innfactory.smithy4play
import de.innfactory.smithy4play.middleware.MiddlewareBase
import play.api.http.MimeTypes
import play.api.mvc._
import smithy4s.codecs.PayloadError
import smithy4s.http._
import smithy4s.kinds.FunctorInterpreter
import smithy4s.schema.Schema
import smithy4s.{ Blob, Endpoint, Service }

import javax.inject.Inject
import scala.concurrent.{ ExecutionContext, Future }

class SmithyPlayEndpoint[Alg[_[_, _, _, _, _]], F[_] <: ContextRoute[_], Op[
_,
_,
_,
_,
_
], I, E, O, SI, SO](
class SmithyPlayEndpoint[Alg[_[_, _, _, _, _]], F[_] <: ContextRoute[_], Op[_, _, _, _, _], I, E, O, SI, SO](
service: Service[Alg],
impl: FunctorInterpreter[Op, F],
middleware: Seq[MiddlewareBase],
endpoint: Endpoint[Op, I, E, O, SI, SO]
endpoint: Endpoint[Op, I, E, O, SI, SO],
codecDecider: CodecDecider
)(implicit cc: ControllerComponents, ec: ExecutionContext)
extends AbstractController(cc) {

Expand Down Expand Up @@ -71,7 +64,7 @@ class SmithyPlayEndpoint[Alg[_[_, _, _, _, _]], F[_] <: ContextRoute[_], Op[
private def mapToEndpointResult(
statusCode: Int
)(output: O)(implicit defaultContentType: ContentType): HttpResponse[Blob] =
CodecDecider
codecDecider
.httpMessageEncoder(Seq(defaultContentType.value))
.fromSchema(outputSchema)
.write(
Expand Down Expand Up @@ -106,7 +99,7 @@ class SmithyPlayEndpoint[Alg[_[_, _, _, _, _]], F[_] <: ContextRoute[_], Op[
)(implicit defaultContentType: ContentType): EitherT[Future, ContextRouteError, I] =
EitherT {
Future {
val codec = CodecDecider.requestDecoder(Seq(defaultContentType.value))
val codec = codecDecider.requestDecoder(Seq(defaultContentType.value))
codec
.fromSchema(inputSchema)
.decode({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package de.innfactory.smithy4play

import cats.implicits.toTraverseOps
import com.github.plokhotnyuk.jsoniter_scala.core.ReaderConfig
import com.typesafe.config.Config
import de.innfactory.smithy4play.middleware.MiddlewareBase
import play.api.mvc.{ AbstractController, ControllerComponents, Handler, RequestHeader }
import play.api.routing.Router.Routes
Expand All @@ -21,12 +23,13 @@ class SmithyPlayRouter[Alg[_[_, _, _, _, _]], F[
)(implicit cc: ControllerComponents, ec: ExecutionContext)
extends AbstractController(cc) {

def routes(middlewares: Seq[MiddlewareBase]): Routes = {
def routes(middlewares: Seq[MiddlewareBase], readerConfig: ReaderConfig): Routes = {

val interpreter: PolyFunction5[service.Operation, Kind1[F]#toKind5] = service.toPolyFunction[Kind1[F]#toKind5](impl)
val endpoints: Seq[service.Endpoint[_, _, _, _, _]] = service.endpoints
val httpEndpoints: Seq[Either[HttpEndpoint.HttpEndpointError, HttpEndpoint[_]]] =
endpoints.map(ep => HttpEndpoint.cast(ep.schema))
val codecDecider = CodecDecider(readerConfig)

new PartialFunction[RequestHeader, Handler] {
override def isDefinedAt(x: RequestHeader): Boolean = {
Expand All @@ -48,7 +51,8 @@ class SmithyPlayRouter[Alg[_[_, _, _, _, _]], F[
service,
interpreter,
middlewares,
endpointAndHttpEndpoint._1
endpointAndHttpEndpoint._1,
codecDecider
).handler(v1)
} match {
case Right(value) => value
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package de.innfactory.smithy4play.client

import cats.data.Kleisli
import de.innfactory.smithy4play.{ ClientResponse, RunnableClientRequest }
import com.github.plokhotnyuk.jsoniter_scala.core.ReaderConfig
import de.innfactory.smithy4play.{ ClientResponse, CodecDecider, RunnableClientRequest }
import smithy4s.Service
import smithy4s.kinds.{ Kind1, PolyFunction5 }

Expand All @@ -10,10 +11,12 @@ import scala.concurrent.ExecutionContext
private class GenericAPIClient[Alg[_[_, _, _, _, _]]](
service: Service[Alg],
client: RequestClient,
readerConfig: ReaderConfig,
additionalSuccessCodes: List[Int] = List.empty
)(implicit ec: ExecutionContext) {

private val smithyPlayClient = new SmithyPlayClient("/", service, client, additionalSuccessCodes)
private val smithyPlayClient =
new SmithyPlayClient("/", service, client, CodecDecider(readerConfig), additionalSuccessCodes)

/* Takes a service and creates a Transformation[Op, ClientRequest] */
private def transformer(): Alg[Kind1[RunnableClientRequest]#toKind5] =
Expand Down Expand Up @@ -53,31 +56,35 @@ object GenericAPIClient {
def withClientAndHeaders(
client: RequestClient,
additionalHeaders: Option[Map[String, Seq[String]]],
additionalSuccessCodes: List[Int] = List.empty
additionalSuccessCodes: List[Int] = List.empty,
readerConfig: ReaderConfig = ReaderConfig
)(implicit ec: ExecutionContext): Alg[Kind1[ClientResponse]#toKind5] =
apply(service, additionalHeaders, additionalSuccessCodes, client)
apply(service, additionalHeaders, additionalSuccessCodes, client, readerConfig)

def withClient(
client: RequestClient,
additionalSuccessCodes: List[Int] = List.empty
additionalSuccessCodes: List[Int] = List.empty,
readerConfig: ReaderConfig = ReaderConfig
)(implicit ec: ExecutionContext): Alg[Kind1[RunnableClientRequest]#toKind5] =
apply(service, client, additionalSuccessCodes)
apply(service, client, additionalSuccessCodes, readerConfig)

}

def apply[Alg[_[_, _, _, _, _]]](
serviceI: Service[Alg],
client: RequestClient,
additionalSuccessCodes: List[Int]
additionalSuccessCodes: List[Int],
readerConfig: ReaderConfig
)(implicit ec: ExecutionContext): Alg[Kind1[RunnableClientRequest]#toKind5] =
new GenericAPIClient(serviceI, client, additionalSuccessCodes).transformer()
new GenericAPIClient(serviceI, client, readerConfig, additionalSuccessCodes).transformer()

def apply[Alg[_[_, _, _, _, _]]](
serviceI: Service[Alg],
additionalHeaders: Option[Map[String, Seq[String]]],
additionalSuccessCodes: List[Int],
client: RequestClient
client: RequestClient,
readerConfig: ReaderConfig
)(implicit ec: ExecutionContext): Alg[Kind1[ClientResponse]#toKind5] =
new GenericAPIClient(serviceI, client, additionalSuccessCodes).transformer(additionalHeaders)
new GenericAPIClient(serviceI, client, readerConfig, additionalSuccessCodes).transformer(additionalHeaders)

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package de.innfactory.smithy4play.client

import cats.implicits.toBifunctorOps
import de.innfactory.smithy4play.ClientResponse
import com.github.plokhotnyuk.jsoniter_scala.core.ReaderConfig
import de.innfactory.smithy4play.{ ClientResponse, CodecDecider }
import smithy4s.Blob
import smithy4s.http.{ CaseInsensitive, HttpEndpoint }

Expand All @@ -11,6 +12,7 @@ class SmithyPlayClient[Alg[_[_, _, _, _, _]], F[_]](
baseUri: String,
val service: smithy4s.Service[Alg],
client: RequestClient,
codecDecider: CodecDecider,
additionalSuccessCodes: List[Int] = List.empty
)(implicit executionContext: ExecutionContext) {

Expand All @@ -31,7 +33,8 @@ class SmithyPlayClient[Alg[_[_, _, _, _, _]], F[_]](
httpEndpoint = httpEndpoint,
input = service.input(op),
serviceHints = service.hints,
client = client
client = client,
codecDecider = codecDecider
).send()
)
.toOption
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ private[smithy4play] class SmithyPlayClientEndpoint[Op[_, _, _, _, _], I, E, O,
additionalSuccessCodes: List[Int],
httpEndpoint: HttpEndpoint[I],
input: I,
client: RequestClient
client: RequestClient,
codecDecider: CodecDecider
)(implicit executionContext: ExecutionContext) {

private implicit val inputSchema: Schema[I] = endpoint.input
Expand Down Expand Up @@ -53,7 +54,7 @@ private[smithy4play] class SmithyPlayClientEndpoint[Op[_, _, _, _, _], I, E, O,
}

private def writeInputToBlob(input: I, contentType: Seq[String]): EndpointRequest = {
val codecs = CodecDecider.requestEncoder(contentType)
val codecs = codecDecider.requestEncoder(contentType)
codecs.fromSchema(inputSchema).write(PlayHttpRequest(Blob.empty, Metadata.empty), input)
}

Expand All @@ -72,7 +73,7 @@ private[smithy4play] class SmithyPlayClientEndpoint[Op[_, _, _, _, _], I, E, O,
Future {
val headers = response.headers.map(x => (x._1, x._2))
val contentType = headers.getOrElse(contentTypeKey, Seq(serviceContentType))
val codec = CodecDecider.httpResponseDecoder(contentType)
val codec = codecDecider.httpResponseDecoder(contentType)

codec
.fromSchema(outputSchema)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package de.innfactory
import alloy.SimpleRestJson
import aws.protocols.RestXml
import cats.data.{ EitherT, Kleisli }
import com.github.plokhotnyuk.jsoniter_scala.core.ReaderConfig
import com.typesafe.config.Config
import de.innfactory.smithy4play.client.SmithyPlayClientEndpointErrorResponse
import org.slf4j
import play.api.Logger
Expand All @@ -15,6 +17,7 @@ import smithy4s.http.{ CaseInsensitive, HttpEndpoint, HttpResponse, Metadata }
import scala.annotation.{ compileTimeOnly, StaticAnnotation }
import scala.concurrent.Future
import scala.language.experimental.macros
import scala.util.Try
import scala.util.matching.Regex
import scala.xml.Elem

Expand Down Expand Up @@ -65,6 +68,42 @@ package object smithy4play {
}
}

implicit class EnhancedReaderConfig(readerConfig: ReaderConfig) {

def fromApplicationConfig(config: Config): ReaderConfig = {
val maxCharBufSize =
Try(config.getInt("smithy4play.jsoniter.maxCharBufSize")).toOption
val preferredBufSize =
Try(config.getInt("smithy4play.jsoniter.preferredBufSize")).toOption
val preferredCharBufSize =
Try(config.getInt("smithy4play.jsoniter.preferredCharBufSize")).toOption
val hexDumpSize =
Try(config.getInt("smithy4play.jsoniter.hexDumpSize")).toOption
val maxBufSize =
Try(config.getInt("smithy4play.jsoniter.MaxBufSize")).toOption
val throwReaderExceptionWithStackTrace =
Try(config.getBoolean("smithy4play.jsoniter.throwReaderExceptionWithStackTrace")).toOption
val appendHexDumpToParseException =
Try(config.getBoolean("smithy4play.jsoniter.appendHexDumpToParseException")).toOption
val checkForEndOfInput =
Try(config.getBoolean("smithy4play.jsoniter.checkForEndOfInput")).toOption

readerConfig
.withMaxCharBufSize(maxCharBufSize.getOrElse(readerConfig.maxCharBufSize))
.withPreferredBufSize(preferredBufSize.getOrElse(readerConfig.preferredBufSize))
.withCheckForEndOfInput(checkForEndOfInput.getOrElse(readerConfig.checkForEndOfInput))
.withPreferredCharBufSize(preferredCharBufSize.getOrElse(readerConfig.preferredCharBufSize))
.withHexDumpSize(hexDumpSize.getOrElse(readerConfig.hexDumpSize))
.withMaxBufSize(maxBufSize.getOrElse(readerConfig.maxBufSize))
.withAppendHexDumpToParseException(
appendHexDumpToParseException.getOrElse(readerConfig.appendHexDumpToParseException)
)
.withThrowReaderExceptionWithStackTrace(
throwReaderExceptionWithStackTrace.getOrElse(readerConfig.throwReaderExceptionWithStackTrace)
)
}
}

implicit class EnhancedThrowable(throwable: Throwable) {
private val regex1: Regex = """(?s), offset: (?:0x)?[0-9a-fA-F]+, buf:.*""".r
private val regex2: Regex = """(.*), offset: .*, buf:.* (\(path:.*\))""".r
Expand All @@ -77,7 +116,6 @@ package object smithy4play {
case msg => regex1.replaceAllIn(msg, "")
}
)

}

private[smithy4play] case class Smithy4PlayError(
Expand Down
8 changes: 2 additions & 6 deletions smithy4playTest/test/XmlControllerTest.scala
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import de.innfactory.smithy4play.CodecDecider
import de.innfactory.smithy4play.client.GenericAPIClient.EnhancedGenericAPIClient
import de.innfactory.smithy4play.client.SmithyPlayTestUtils._
import models.NodeImplicits.NodeEnhancer
import models.TestBase
import play.api.Application
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.libs.json.{ JsValue, Json, OFormat }
import play.api.libs.json.{Json, OFormat}
import play.api.test.FakeRequest
import play.api.test.Helpers._
import smithy4s.Blob
import smithy4s.http.CaseInsensitive
import testDefinitions.test.{ XmlTestInputBody, XmlControllerDefGen, XmlTestOutput }
import testDefinitions.test.{XmlControllerDefGen, XmlTestInputBody, XmlTestOutput}

import scala.xml._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.xml.{ Elem, Node, PrettyPrinter }

class XmlControllerTest extends TestBase {

Expand Down

0 comments on commit ea00694

Please sign in to comment.