summaryrefslogtreecommitdiff
path: root/cask/src/cask/main
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2018-07-25 16:17:50 +0800
committerLi Haoyi <haoyi.sg@gmail.com>2018-07-25 16:30:07 +0800
commitc4476471f4ff4b38c518b5478996bc178a129e6b (patch)
tree63078ea3da9b866bd1edab7a6a4db2a9c9f13ab1 /cask/src/cask/main
parent603dfa8946f8c78580568613cd268ad05c6c38f6 (diff)
downloadcask-c4476471f4ff4b38c518b5478996bc178a129e6b.tar.gz
cask-c4476471f4ff4b38c518b5478996bc178a129e6b.tar.bz2
cask-c4476471f4ff4b38c518b5478996bc178a129e6b.zip
Split up `cask` package into subpackages
Diffstat (limited to 'cask/src/cask/main')
-rw-r--r--cask/src/cask/main/Main.scala86
-rw-r--r--cask/src/cask/main/Routes.scala60
2 files changed, 146 insertions, 0 deletions
diff --git a/cask/src/cask/main/Main.scala b/cask/src/cask/main/Main.scala
new file mode 100644
index 0000000..77bac94
--- /dev/null
+++ b/cask/src/cask/main/Main.scala
@@ -0,0 +1,86 @@
+package cask.main
+
+import cask.model.{BaseResponse, Response, Status}
+import cask.Cookie
+import cask.internal.Router.EntryPoint
+import cask.internal.{DispatchTrie, Router, Util}
+import io.undertow.Undertow
+import io.undertow.server.{HttpHandler, HttpServerExchange}
+import io.undertow.server.handlers.BlockingHandler
+import io.undertow.util.HttpString
+
+
+class MainRoutes extends BaseMain with Routes{
+ def allRoutes = Seq(this)
+}
+class Main(servers0: Routes*) extends BaseMain{
+ def allRoutes = servers0.toSeq
+}
+abstract class BaseMain{
+ def allRoutes: Seq[Routes]
+ val port: Int = 8080
+ val host: String = "localhost"
+
+ lazy val routeList = for{
+ routes <- allRoutes
+ route <- routes.caskMetadata.value.map(x => x: Routes.EndpointMetadata[_])
+ } yield (routes, route)
+
+ lazy val routeTrie = DispatchTrie.construct[(Routes, Routes.EndpointMetadata[_])](0,
+ for((route, metadata) <- routeList)
+ yield (Util.splitPath(metadata.metadata.path): IndexedSeq[String], (route, metadata), metadata.metadata.subpath)
+ )
+
+ def handleError(statusCode: Int): Response = {
+ Response(
+ s"Error $statusCode: ${Status.codesToStatus(statusCode).reason}",
+ statusCode = statusCode
+ )
+ }
+
+ def writeResponse(exchange: HttpServerExchange, response: BaseResponse) = {
+ response.headers.foreach{case (k, v) =>
+ exchange.getResponseHeaders.put(new HttpString(k), v)
+ }
+ response.cookies.foreach(c => exchange.setResponseCookie(Cookie.toUndertow(c)))
+
+ exchange.setStatusCode(response.statusCode)
+ response.data.write(exchange.getOutputStream)
+ }
+
+ lazy val defaultHandler = new HttpHandler() {
+ def handleRequest(exchange: HttpServerExchange): Unit = {
+ routeTrie.lookup(Util.splitPath(exchange.getRequestPath).toList, Map()) match{
+ case None => writeResponse(exchange, handleError(404))
+ case Some(((routes, metadata), bindings, remaining)) =>
+ val result = metadata.metadata.handle(
+ exchange, remaining, bindings, routes,
+ metadata.entryPoint.asInstanceOf[EntryPoint[metadata.metadata.InputType, cask.main.Routes, (HttpServerExchange, Seq[String])]]
+ )
+
+ result match{
+ case Router.Result.Success(response) => writeResponse(exchange, response)
+ case Router.Result.Error.Exception(e) =>
+ println(e)
+ e.printStackTrace()
+ writeResponse(exchange, handleError(500))
+ case err: Router.Result.Error =>
+ println(err)
+ writeResponse(exchange, handleError(400))
+ }
+
+
+ }
+ }
+ }
+
+ def main(args: Array[String]): Unit = {
+ val server = Undertow.builder
+ .addHttpListener(port, host)
+ .setHandler(new BlockingHandler(defaultHandler))
+ .build
+ server.start()
+ }
+}
+
+
diff --git a/cask/src/cask/main/Routes.scala b/cask/src/cask/main/Routes.scala
new file mode 100644
index 0000000..fdd39bd
--- /dev/null
+++ b/cask/src/cask/main/Routes.scala
@@ -0,0 +1,60 @@
+package cask.main
+
+import cask.endpoints.Endpoint
+import cask.internal.Router.EntryPoint
+import io.undertow.server.HttpServerExchange
+
+import scala.reflect.macros.blackbox.Context
+import language.experimental.macros
+
+object Routes{
+ case class EndpointMetadata[T](metadata: Endpoint[_],
+ entryPoint: EntryPoint[_, T, (HttpServerExchange, Seq[String])])
+ case class RoutesEndpointsMetadata[T](value: EndpointMetadata[T]*)
+ object RoutesEndpointsMetadata{
+ implicit def initialize[T] = macro initializeImpl[T]
+ implicit def initializeImpl[T: c.WeakTypeTag](c: Context): c.Expr[RoutesEndpointsMetadata[T]] = {
+ import c.universe._
+ val router = new cask.internal.Router[c.type](c)
+
+ val routeParts = for{
+ m <- c.weakTypeOf[T].members
+ annot <- m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[Endpoint[_]])
+ } yield {
+ val annotObject = q"new ${annot.tree.tpe}(..${annot.tree.children.tail})"
+ val annotObjectSym = c.universe.TermName(c.freshName("annotObject"))
+ val route = router.extractMethod(
+ m.asInstanceOf[MethodSymbol],
+ weakTypeOf[T],
+ (t: router.c.universe.Tree) => q"$annotObjectSym.wrapMethodOutput($t)",
+ c.weakTypeOf[(io.undertow.server.HttpServerExchange, Seq[String])],
+ q"$annotObjectSym.parseMethodInput",
+ tq"$annotObjectSym.InputType"
+ )
+
+
+ q"""{
+ val $annotObjectSym = $annotObject
+ cask.main.Routes.EndpointMetadata(
+ $annotObjectSym,
+ $route
+ )
+ }"""
+ }
+
+ c.Expr[RoutesEndpointsMetadata[T]](q"""cask.main.Routes.RoutesEndpointsMetadata(..$routeParts)""")
+ }
+ }
+}
+
+trait Routes{
+ private[this] var metadata0: Routes.RoutesEndpointsMetadata[this.type] = null
+ def caskMetadata =
+ if (metadata0 != null) metadata0
+ else throw new Exception("Routes not yet initialize")
+
+ protected[this] def initialize()(implicit routes: Routes.RoutesEndpointsMetadata[this.type]): Unit = {
+ metadata0 = routes
+ }
+}
+