From 97af734de345f2aedbe32887f620dbceb7ba54ba Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Thu, 8 Dec 2016 17:33:24 +0300 Subject: [PATCH 1/3] Remove aecor-api --- api/src/main/scala/aecor/api/Router.scala | 36 --------- build.sbt | 21 +----- .../main/scala/aecor/example/AccountAPI.scala | 5 +- .../main/scala/aecor/example/AppActor.scala | 74 ++++++++++++------- .../aecor/example/AuthorizePaymentAPI.scala | 5 +- 5 files changed, 53 insertions(+), 88 deletions(-) delete mode 100644 api/src/main/scala/aecor/api/Router.scala diff --git a/api/src/main/scala/aecor/api/Router.scala b/api/src/main/scala/aecor/api/Router.scala deleted file mode 100644 index 1c6bf266..00000000 --- a/api/src/main/scala/aecor/api/Router.scala +++ /dev/null @@ -1,36 +0,0 @@ -package aecor.api - -import akka.http.scaladsl.server.Directives._ -import akka.http.scaladsl.server._ -import shapeless.{::, Generic, HList, HNil, Lazy} -import simulacrum.typeclass - -@typeclass trait Router[A] { - def route(a: A): Route -} - -object Router { - def route[A](a: A)(implicit e: Router[A]): Route = e.route(a) - - def instance[A](f: A => Route): Router[A] = new Router[A] { - override def route(a: A): Route = f(a) - } - - implicit val hnil: Router[HNil] = new Router[HNil] { - override def route(a: (HNil)): Route = reject - } - - implicit def hcons[H, T <: HList](implicit H: Lazy[Router[H]], T: Lazy[Router[T]]): Router[H :: T] = new Router[::[H, T]] { - override def route(a: (::[H, T])): Route = { - H.value.route(a.head) ~ T.value.route(a.tail) - } - } - - implicit def generic[A, Repr](implicit gen: Generic.Aux[A, Repr], Repr: Router[Repr]): Router[A] = new Router[A] { - override def route(a: A): Route = Repr.route(gen.to(a)) - } - - implicit def routeRouter: Router[Route] = new Router[Route] { - override def route(a: Route): Route = a - } -} diff --git a/build.sbt b/build.sbt index 6e92ec8f..68dcdee7 100644 --- a/build.sbt +++ b/build.sbt @@ -23,7 +23,6 @@ lazy val scalaTestVersion = "3.0.1" lazy val scalaCheckShapelessVersion = "1.1.4" lazy val shapelessVersion = "2.3.2" lazy val kindProjectorVersion = "0.9.3" -lazy val simulacrumVersion = "0.10.0" lazy val paradiseVersion = "2.1.0" lazy val commonSettings = Seq( @@ -32,7 +31,6 @@ lazy val commonSettings = Seq( Resolver.bintrayRepo("projectseptemberinc", "maven") ), libraryDependencies ++= Seq( - "com.github.mpilquist" %% "simulacrum" % simulacrumVersion, compilerPlugin( "org.spire-math" %% "kind-projector" % kindProjectorVersion), compilerPlugin( @@ -50,9 +48,8 @@ lazy val aecor = project .settings(moduleName := "aecor") .settings(aecorSettings) .settings(noPublishSettings) - .aggregate(core, api, example, schedule, tests, bench) + .aggregate(core, example, schedule, tests, bench) .dependsOn(core, - api, example % "compile-internal", tests % "test-internal -> test", bench % "compile-internal;test-internal -> test") @@ -61,14 +58,6 @@ lazy val core = project .settings(moduleName := "aecor-core") .settings(aecorSettings) .settings(coreSettings) - .settings( - libraryDependencies += "org.scalacheck" %% "scalacheck" % scalaCheckVersion % "test") - -lazy val api = project - .dependsOn(core) - .settings(moduleName := "aecor-api") - .settings(aecorSettings) - .settings(apiSettings) lazy val schedule = project .dependsOn(core) @@ -91,7 +80,7 @@ lazy val tests = project .settings(testingSettings) lazy val example = project - .dependsOn(core, api, schedule) + .dependsOn(core, schedule) .settings(moduleName := "aecor-example") .settings(aecorSettings) .settings(noPublishSettings) @@ -111,12 +100,6 @@ lazy val coreSettings = Seq( ) ) -lazy val apiSettings = Seq( - libraryDependencies ++= Seq( - "com.typesafe.akka" %% "akka-http" % akkaHttpVersion - ) -) - lazy val scheduleSettings = commonProtobufSettings lazy val exampleSettings = Seq( diff --git a/example/src/main/scala/aecor/example/AccountAPI.scala b/example/src/main/scala/aecor/example/AccountAPI.scala index b9666620..f03a34a9 100644 --- a/example/src/main/scala/aecor/example/AccountAPI.scala +++ b/example/src/main/scala/aecor/example/AccountAPI.scala @@ -1,14 +1,15 @@ package aecor.example -import aecor.api.Router import aecor.core.aggregate.AggregateRegionRef import aecor.example.domain._ import akka.Done import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.server.Directives._ +import akka.http.scaladsl.server.Route import de.heikoseeberger.akkahttpcirce.CirceSupport._ import io.circe.generic.JsonCodec import cats.implicits._ + import scala.concurrent.{ExecutionContext, Future} class AccountAPI(account: AggregateRegionRef[AccountAggregateOp]) { @@ -47,7 +48,7 @@ object AccountAPI { case class OpenAccount(accountId: String) extends DTO } - implicit val router: Router[AccountAPI] = Router.instance { api => + val route: AccountAPI => Route = { api => path("accounts") { extractExecutionContext { implicit ec => post { diff --git a/example/src/main/scala/aecor/example/AppActor.scala b/example/src/main/scala/aecor/example/AppActor.scala index 116bc09c..90744092 100644 --- a/example/src/main/scala/aecor/example/AppActor.scala +++ b/example/src/main/scala/aecor/example/AppActor.scala @@ -2,7 +2,6 @@ package aecor.example import java.time.Clock -import aecor.api.Router.ops._ import aecor.core.aggregate._ import aecor.core.streaming._ import aecor.example.domain.CardAuthorization.CardAuthorizationCreated @@ -37,61 +36,80 @@ class AppActor extends Actor with ActorLogging { val queries = new CassandraOffsetStore.Queries(system) - val sessionWrapper = DefaultJournalCassandraSession(system, "app-session", queries.init) + val sessionWrapper = + DefaultJournalCassandraSession(system, "app-session", queries.init) val offsetStore = new CassandraOffsetStore(sessionWrapper, queries) val journal = AggregateJournal(system, offsetStore) val authorizationRegion = - AggregateSharding(system).start[CardAuthorization.Command](CardAuthorization()) + AggregateSharding(system) + .start[CardAuthorization.Command](CardAuthorization()) val accountRegion = - AggregateSharding(system).start[AccountAggregateOp](AccountAggregate(Clock.systemUTC())) + AggregateSharding(system) + .start[AccountAggregateOp](AccountAggregate(Clock.systemUTC())) val scheduleEntityName = "Schedule3" - val schedule: Schedule = Schedule(system, scheduleEntityName, 1.day, 10.seconds, offsetStore) - + val schedule: Schedule = + Schedule(system, scheduleEntityName, 1.day, 10.seconds, offsetStore) val cardAuthorizationEventStream = - new DefaultEventStream(system, journal.committableEventSourceFor[CardAuthorization]("CardAuthorization-API").map(_.value)) - - - val authorizePaymentAPI = new AuthorizePaymentAPI(authorizationRegion, cardAuthorizationEventStream, Logging(system, classOf[AuthorizePaymentAPI])) + new DefaultEventStream( + system, + journal + .committableEventSourceFor[CardAuthorization]("CardAuthorization-API") + .map(_.value)) + + val authorizePaymentAPI = new AuthorizePaymentAPI( + authorizationRegion, + cardAuthorizationEventStream, + Logging(system, classOf[AuthorizePaymentAPI])) val accountApi = new AccountAPI(accountRegion) val accountInterpreter = new (AccountAggregateOp ~> Future) { - override def apply[A](fa: AccountAggregateOp[A]): Future[A] = accountRegion.ask(fa) - } - val cardAuthorizationInterpreter = new (CardAuthorization.Command ~> Future) { - override def apply[A](fa: CardAuthorization.Command[A]): Future[A] = authorizationRegion.ask(fa) + override def apply[A](fa: AccountAggregateOp[A]): Future[A] = + accountRegion.ask(fa) } + val cardAuthorizationInterpreter = + new (CardAuthorization.Command ~> Future) { + override def apply[A](fa: CardAuthorization.Command[A]): Future[A] = + authorizationRegion.ask(fa) + } import freek._ val interpreter = accountInterpreter :&: cardAuthorizationInterpreter journal - .committableEventSourceFor[CardAuthorization]("processing") - .collect { - case CommittableJournalEntry(offset, _, _, e: CardAuthorizationCreated) => - (e, offset) - } - .via(AuthorizationProcess.flow(8, interpreter)) - .mapAsync(1)(_.commitScaladsl()) - .runWith(Sink.ignore) - + .committableEventSourceFor[CardAuthorization]("processing") + .collect { + case CommittableJournalEntry(offset, + _, + _, + e: CardAuthorizationCreated) => + (e, offset) + } + .via(AuthorizationProcess.flow(8, interpreter)) + .mapAsync(1)(_.commitScaladsl()) + .runWith(Sink.ignore) val route = path("check") { get { complete(StatusCodes.OK) } } ~ - authorizePaymentAPI.route ~ - accountApi.route - - Http().bindAndHandle(route, config.getString("http.interface"), config.getInt("http.port")) - .onComplete { result => log.info("Bind result [{}]", result) } + AuthorizePaymentAPI.route(authorizePaymentAPI) ~ + AccountAPI.route(accountApi) + + Http() + .bindAndHandle(route, + config.getString("http.interface"), + config.getInt("http.port")) + .onComplete { result => + log.info("Bind result [{}]", result) + } } diff --git a/example/src/main/scala/aecor/example/AuthorizePaymentAPI.scala b/example/src/main/scala/aecor/example/AuthorizePaymentAPI.scala index ea14bbab..065ee7cd 100644 --- a/example/src/main/scala/aecor/example/AuthorizePaymentAPI.scala +++ b/example/src/main/scala/aecor/example/AuthorizePaymentAPI.scala @@ -1,6 +1,5 @@ package aecor.example -import aecor.api.Router import aecor.core.aggregate.AggregateRegionRef import aecor.example.AuthorizePaymentAPI._ import aecor.example.domain.CardAuthorization.{ @@ -12,7 +11,7 @@ import aecor.example.domain._ import akka.event.LoggingAdapter import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.server.Directives._ - +import akka.http.scaladsl.server.Route import de.heikoseeberger.akkahttpcirce.CirceSupport._ import io.circe.generic.JsonCodec @@ -92,7 +91,7 @@ object AuthorizePaymentAPI { } - implicit val router: Router[AuthorizePaymentAPI] = Router.instance { api => + val route: AuthorizePaymentAPI => Route = { api => path("authorization") { extractExecutionContext { implicit ec => post { From e3e34ddd90c050f7198d08d61e5aa125964902e8 Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Thu, 8 Dec 2016 17:45:58 +0300 Subject: [PATCH 2/3] Remove aecor-bench --- build.sbt | 12 ++---------- project/plugins.sbt | 2 +- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/build.sbt b/build.sbt index 68dcdee7..99351d87 100644 --- a/build.sbt +++ b/build.sbt @@ -48,11 +48,10 @@ lazy val aecor = project .settings(moduleName := "aecor") .settings(aecorSettings) .settings(noPublishSettings) - .aggregate(core, example, schedule, tests, bench) + .aggregate(core, example, schedule, tests) .dependsOn(core, example % "compile-internal", - tests % "test-internal -> test", - bench % "compile-internal;test-internal -> test") + tests % "test-internal -> test") lazy val core = project .settings(moduleName := "aecor-core") @@ -65,13 +64,6 @@ lazy val schedule = project .settings(aecorSettings) .settings(scheduleSettings) -lazy val bench = project - .dependsOn(core, example) - .settings(moduleName := "aecor-bench") - .settings(aecorSettings) - .settings(noPublishSettings) - .enablePlugins(JmhPlugin) - lazy val tests = project .dependsOn(core, example, schedule) .settings(moduleName := "aecor-tests") diff --git a/project/plugins.sbt b/project/plugins.sbt index 4e4e3a80..a91f19e6 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -5,7 +5,7 @@ addSbtPlugin("com.thesamet" % "sbt-protoc" % "0.99.1") addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.2.0-M7") addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.3.2") addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.3") -addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.2.6") + addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "0.8.5") addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "1.1") From 9dc33a86d49f68155bc567465e8f0ac0aba101c3 Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Thu, 8 Dec 2016 17:46:06 +0300 Subject: [PATCH 3/3] Update Readme --- README.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 42dabb55..d51c5487 100644 --- a/README.md +++ b/README.md @@ -5,17 +5,14 @@ # Aecor -### Scalable, type safe CQRS DDD framework +### Typeful runtime for eventsourced behaviors -Aecor is an opinionated framework for building scalable, distributed CQRS DDD services written in Scala. It uses [Akka](https://github.com/akka/akka) as a runtime for pure functional behaviors (`Any => Unit`, not even once) and clustering. +Aecor is an opinionated library to help building scalable, distributed eventsourced services written in Scala. It uses [Akka](https://github.com/akka/akka) for distribution and fault tolerance. With the help of [Cats](https://github.com/typelevel/cats/) and [Shapeless](https://github.com/milessabin/shapeless) to reach type safety. -Aecor works on Scala 2.11 with Java 8. +Aecor works on Scala 2.11 and 2.12 with Java 8. The name `Aecor` (_lat. ocean_) is inspired by a vision of modern distributed applications, as an ocean of messages with pure behaviors floating in it. + + -Main goals: -1. Type safety -2. Pure behaviors -3. Easy to implement Aggregate Root behaviors -4. A simple DSL to describe Business Processes