From 9cb5df86335b01e770eb656aa5eda3692410276e Mon Sep 17 00:00:00 2001 From: vlad Date: Sun, 17 Jul 2016 20:46:10 -0400 Subject: App interruption and formats for Time --- project/Build.scala | 22 +++++++++++----------- src/main/scala/com/drivergrp/core/app.scala | 26 ++++++++++++++++++++------ src/main/scala/com/drivergrp/core/rest.scala | 25 +++++++++++++++++++++---- 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index 60ae493..7bd1539 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -18,18 +18,18 @@ object DriverBuild extends Build { val akkaHttpV = "2.4.8" val dependencies = Seq( - "com.typesafe.akka" %% "akka-http-core" % akkaHttpV, - "com.typesafe.akka" %% "akka-http-experimental" % akkaHttpV, - "com.typesafe.akka" %% "akka-http-jackson-experimental" % akkaHttpV, - "com.typesafe.akka" %% "akka-http-spray-json-experimental" % akkaHttpV, - "com.typesafe.akka" %% "akka-http-testkit" % akkaHttpV, - "org.scalatest" % "scalatest_2.11" % "2.2.1" % "test", - "com.typesafe.slick" %% "slick" % "3.0.0", - "com.typesafe" % "config" % "1.2.1", + "com.typesafe.akka" %% "akka-http-core" % akkaHttpV, + "com.typesafe.akka" %% "akka-http-experimental" % akkaHttpV, + "com.typesafe.akka" %% "akka-http-jackson-experimental" % akkaHttpV, + "com.typesafe.akka" %% "akka-http-spray-json-experimental" % akkaHttpV, + "com.typesafe.akka" %% "akka-http-testkit" % akkaHttpV, + "org.scalatest" % "scalatest_2.11" % "2.2.1" % "test", + "com.typesafe.slick" %% "slick" % "3.0.0", + "com.typesafe" % "config" % "1.2.1", "com.typesafe.scala-logging" %% "scala-logging" % "3.1.0", - "ch.qos.logback" % "logback-classic" % "1.1.3", - "org.slf4j" % "slf4j-nop" % "1.6.4", - "org.scalaz" %% "scalaz-core" % "7.2.4", + "ch.qos.logback" % "logback-classic" % "1.1.3", + "org.slf4j" % "slf4j-nop" % "1.6.4", + "org.scalaz" %% "scalaz-core" % "7.2.4", "com.github.swagger-akka-http" %% "swagger-akka-http" % "0.7.1" ) diff --git a/src/main/scala/com/drivergrp/core/app.scala b/src/main/scala/com/drivergrp/core/app.scala index 97e09b5..53239e0 100644 --- a/src/main/scala/com/drivergrp/core/app.scala +++ b/src/main/scala/com/drivergrp/core/app.scala @@ -12,6 +12,9 @@ import com.drivergrp.core.rest.Swagger import com.typesafe.config.Config import org.slf4j.LoggerFactory +import scala.concurrent.Await +import scala.concurrent.duration._ + object app { @@ -21,22 +24,33 @@ object app { config: Config = com.drivergrp.core.config.loadDefaultConfig, interface: String = "localhost", port: Int = 8080) { + implicit private lazy val actorSystem = ActorSystem("spray-routing", config) + implicit private lazy val executionContext = actorSystem.dispatcher + implicit private lazy val materializer = ActorMaterializer()(actorSystem) + private lazy val http = Http()(actorSystem) + + def run() = { activateServices(modules) scheduleServicesDeactivation(modules) bindHttp(modules) + Console.print(s"${this.getClass.getName} App is started") + } + + def stop() = { + http.shutdownAllConnectionPools().onComplete { _ => + actorSystem.terminate() + Await.result(actorSystem.whenTerminated, 30.seconds) + Console.print(s"${this.getClass.getName} App is stopped") + } } - protected def bindHttp(modules: Seq[Module]) { - implicit val actorSystem = ActorSystem("spray-routing", config) - implicit val executionContext = actorSystem.dispatcher - implicit val materializer = ActorMaterializer()(actorSystem) + protected def bindHttp(modules: Seq[Module]) { val serviceTypes = modules.flatMap(_.routeTypes) val swaggerService = new Swagger(actorSystem, serviceTypes, config) val swaggerRoutes = swaggerService.routes ~ swaggerService.swaggerUI - - Http()(actorSystem).bindAndHandle( + http.bindAndHandle( route2HandlerFlow(logRequestResult("log")(modules.map(_.route).foldLeft(swaggerRoutes) { _ ~ _ })), interface, port)(materializer) } diff --git a/src/main/scala/com/drivergrp/core/rest.scala b/src/main/scala/com/drivergrp/core/rest.scala index 421f5d1..4e8ea3e 100644 --- a/src/main/scala/com/drivergrp/core/rest.scala +++ b/src/main/scala/com/drivergrp/core/rest.scala @@ -11,12 +11,12 @@ import akka.stream.ActorMaterializer import akka.util.Timeout import com.drivergrp.core.logging.Logger import com.drivergrp.core.stats.Stats -import com.drivergrp.core.time.TimeRange +import com.drivergrp.core.time.{Time, TimeRange} import com.drivergrp.core.time.provider.TimeProvider import com.github.swagger.akka.model._ import com.github.swagger.akka.{HasActorSystem, SwaggerHttpService} import com.typesafe.config.Config -import spray.json.{DeserializationException, JsNumber, JsString, JsValue, RootJsonFormat} +import spray.json.{DeserializationException, JsNumber, JsObject, JsString, JsValue, RootJsonFormat} import scala.concurrent.duration._ import scala.concurrent.{ExecutionContext, Future} @@ -72,8 +72,7 @@ object rest { def IdInPath[T]: PathMatcher1[Id[T]] = PathMatcher("""[+-]?\d*""".r) flatMap { string ⇒ - try Some(Id[T](string.toLong)) - catch { case _: IllegalArgumentException ⇒ None } + try Some(Id[T](string.toLong)) catch { case _: IllegalArgumentException ⇒ None } } implicit def idFormat[T] = new RootJsonFormat[Id[T]] { @@ -97,6 +96,24 @@ object rest { case _ => throw new DeserializationException("Name expects string") } } + + def TimeInPath[T]: PathMatcher1[Time] = + PathMatcher("""[+-]?\d*""".r) flatMap { string ⇒ + try Some(Time(string.toLong)) catch { case _: IllegalArgumentException ⇒ None } + } + + implicit def timeFormat[T] = new RootJsonFormat[Time] { + def write(time: Time) = JsObject("timestamp" -> JsNumber(time.millis)) + + def read(value: JsValue): Time = value match { + case JsObject(fields) => + fields.get("timestamp").flatMap { + case JsNumber(millis) => Some(Time(millis.toLong)) + case _ => None + }.getOrElse(throw new DeserializationException("Time expects number")) + case _ => throw new DeserializationException("Time expects number") + } + } } trait OptionTDirectives { -- cgit v1.2.3