summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2018-07-21 22:32:38 +0800
committerLi Haoyi <haoyi.sg@gmail.com>2018-07-21 22:33:55 +0800
commit3f61791c57b450de84a6599e2338b1afcf172a05 (patch)
tree264da592c6e2085f2b862239d70e94d8792e8ca2
parentaa67cc44e7154601bdccd852ce43585b9f138215 (diff)
downloadcask-3f61791c57b450de84a6599e2338b1afcf172a05.tar.gz
cask-3f61791c57b450de84a6599e2338b1afcf172a05.tar.bz2
cask-3f61791c57b450de84a6599e2338b1afcf172a05.zip
WIP moving logic into annotations themselves
-rw-r--r--cask/src/cask/Annotations.scala69
-rw-r--r--cask/src/cask/Main.scala22
-rw-r--r--cask/src/cask/Router.scala14
-rw-r--r--cask/src/cask/Routes.scala8
4 files changed, 81 insertions, 32 deletions
diff --git a/cask/src/cask/Annotations.scala b/cask/src/cask/Annotations.scala
index e77d98c..fa0e25e 100644
--- a/cask/src/cask/Annotations.scala
+++ b/cask/src/cask/Annotations.scala
@@ -1,20 +1,67 @@
package cask
-import scala.annotation.StaticAnnotation
+import cask.Router.EntryPoint
+import io.undertow.server.HttpServerExchange
+import collection.JavaConverters._
-
-trait AnnotationBase{
- def wrapMethodOutput(t: Response): Any
+trait EndpointAnnotation[R]{
+ val path: String
+ def wrapMethodOutput(t: R): Any
def parseMethodInput[T](implicit p: ParamReader[T]) = p
+
+ def handle(exchange: HttpServerExchange,
+ bindings: Map[String, String],
+ routes: Routes,
+ entryPoint: EntryPoint[Routes, HttpServerExchange]): Router.Result[Response]
}
-trait RouteBase extends AnnotationBase{
- val path: String
+trait RouteBase extends EndpointAnnotation[Response]{
def wrapMethodOutput(t: Response) = t
+ def handle(exchange: HttpServerExchange,
+ bindings: Map[String, String],
+ routes: Routes,
+ entryPoint: EntryPoint[Routes, HttpServerExchange]): Router.Result[Response] = {
+ val allBindings =
+ bindings.toSeq ++
+ exchange.getQueryParameters
+ .asScala
+ .toSeq
+ .flatMap{case (k, vs) => vs.asScala.map((k, _))}
+
+ entryPoint.invoke(routes, exchange, allBindings.map{case (k, v) => (k, Some(v))})
+ .asInstanceOf[Router.Result[Response]]
+ }
}
-class get(val path: String) extends StaticAnnotation with RouteBase
-class post(val path: String) extends StaticAnnotation with RouteBase
-class put(val path: String) extends StaticAnnotation with RouteBase
-class route(val path: String, val methods: Seq[String]) extends StaticAnnotation with RouteBase
-class static(val path: String) extends StaticAnnotation{
+class get(val path: String) extends RouteBase
+class post(val path: String) extends RouteBase
+class put(val path: String) extends RouteBase
+class route(val path: String, val methods: Seq[String]) extends RouteBase
+class static(val path: String) extends EndpointAnnotation[String] {
def wrapOutput(t: String) = t
+
+ def wrapMethodOutput(t: String) = t
+
+ def handle(exchange: HttpServerExchange,
+ bindings: Map[String, String],
+ routes: Routes,
+ entryPoint: EntryPoint[Routes, HttpServerExchange]): Router.Result[Response] = {
+ entryPoint.invoke(routes, exchange, Nil).asInstanceOf[Router.Result[String]] match{
+ case Router.Result.Success(s) =>
+ println("XXX STATIC")
+ val relPath = java.nio.file.Paths.get(
+ s + Util.splitPath(exchange.getRequestPath).drop(Util.splitPath(path).length).mkString("/")
+ )
+ println("Y")
+ if (java.nio.file.Files.exists(relPath) && java.nio.file.Files.isRegularFile(relPath)){
+ Router.Result.Success(Response(java.nio.file.Files.newInputStream(relPath)))
+ }else{
+ Router.Result.Success(Response("", 404))
+ }
+
+ case e: Router.Result.Error =>
+ println("XXX")
+ e
+
+ }
+
+ }
}
diff --git a/cask/src/cask/Main.scala b/cask/src/cask/Main.scala
index d16172c..dcbc807 100644
--- a/cask/src/cask/Main.scala
+++ b/cask/src/cask/Main.scala
@@ -3,6 +3,7 @@ import cask.Router.EntryPoint
import java.io.OutputStream
import java.nio.ByteBuffer
+import cask.Routes.Metadata
import io.undertow.Undertow
import io.undertow.server.handlers.BlockingHandler
import io.undertow.server.{HttpHandler, HttpServerExchange}
@@ -24,9 +25,9 @@ abstract class BaseMain{
route <- routes.caskMetadata.value.map(x => x: Routes.RouteMetadata[_])
} yield (routes, route)
- lazy val routeTrie = DispatchTrie.construct[(Routes, Router.EntryPoint[_, HttpServerExchange])](0,
+ lazy val routeTrie = DispatchTrie.construct[(Routes, Routes.RouteMetadata[_])](0,
for((route, metadata) <- routeList)
- yield (Util.splitPath(metadata.metadata.path): IndexedSeq[String], (route, metadata.entryPoint))
+ yield (Util.splitPath(metadata.metadata.path): IndexedSeq[String], (route, metadata))
)
def handleError(statusCode: Int): Response = {
@@ -49,18 +50,11 @@ abstract class BaseMain{
def handleRequest(exchange: HttpServerExchange): Unit = {
routeTrie.lookup(Util.splitPath(exchange.getRequestPath).toList, Map()) match{
case None => writeResponse(exchange, handleError(404))
- case Some(((routes, entrypoint), bindings)) =>
- import collection.JavaConverters._
- val allBindings =
- bindings.toSeq ++
- exchange.getQueryParameters
- .asScala
- .toSeq
- .flatMap{case (k, vs) => vs.asScala.map((k, _))}
-
- val result = entrypoint
- .asInstanceOf[EntryPoint[routes.type, HttpServerExchange]]
- .invoke(routes, exchange, allBindings.map{case (k, v) => (k, Some(v))})
+ case Some(((routes, metadata), bindings)) =>
+ val result = metadata.metadata.handle(
+ exchange, bindings, routes,
+ metadata.entryPoint.asInstanceOf[EntryPoint[Routes, HttpServerExchange]]
+ )
result match{
case Router.Result.Success(response: Response) => writeResponse(exchange, response)
diff --git a/cask/src/cask/Router.scala b/cask/src/cask/Router.scala
index 65192a1..e2a6e9e 100644
--- a/cask/src/cask/Router.scala
+++ b/cask/src/cask/Router.scala
@@ -42,6 +42,7 @@ object Router{
else if (s.startsWith("-")) s.drop(1)
else s
}
+
/**
* What is known about a single endpoint for our routes. It has a [[name]],
* [[argSignatures]] for each argument, and a macro-generated [[invoke0]]
@@ -52,10 +53,10 @@ object Router{
* calling a Scala method.
*/
case class EntryPoint[T, C](name: String,
- argSignatures: Seq[ArgSig[T, _, C]],
- doc: Option[String],
- varargs: Boolean,
- invoke0: (T, C, Map[String, Seq[String]], Seq[String]) => Result[Any]){
+ argSignatures: Seq[ArgSig[T, _, C]],
+ doc: Option[String],
+ varargs: Boolean,
+ invoke0: (T, C, Map[String, Seq[String]], Seq[String]) => Result[Any]){
def invoke(target: T, ctx: C, groupedArgs: Seq[(String, Option[String])]): Result[Any] = {
var remainingArgSignatures = argSignatures.toList.filter(_.reads.arity > 0)
@@ -373,6 +374,9 @@ class Router [C <: Context](val c: C) {
}.unzip
+ val methCall =
+ if (meth.paramLists.isEmpty) q"$baseArgSym.${meth.name.toTermName}"
+ else q"$baseArgSym.${meth.name.toTermName}(..$argNameCasts)"
val res = q"""
cask.Router.EntryPoint[$curCls, $ctx](
${meth.name.toString},
@@ -386,7 +390,7 @@ class Router [C <: Context](val c: C) {
cask.Router.validate(Seq(..$readArgs)) match{
case cask.Router.Result.Success(List(..$argNames)) =>
cask.Router.Result.Success(
- ${wrapOutput(q"$baseArgSym.${meth.name.toTermName}(..$argNameCasts)")}
+ ${wrapOutput(methCall)}
)
case x: cask.Router.Result.Error => x
}
diff --git a/cask/src/cask/Routes.scala b/cask/src/cask/Routes.scala
index 5ce8f6c..3ab5906 100644
--- a/cask/src/cask/Routes.scala
+++ b/cask/src/cask/Routes.scala
@@ -6,6 +6,7 @@ import cask.Router.EntryPoint
import io.undertow.server.HttpServerExchange
import scala.reflect.macros.blackbox.Context
+import java.io.InputStream
case class Response(data: Response.Data,
@@ -23,11 +24,14 @@ object Response{
implicit class BytesData(b: Array[Byte]) extends Data{
def write(out: OutputStream) = out.write(b)
}
+ implicit class StreamData(b: InputStream) extends Data{
+ def write(out: OutputStream) = b.transferTo(out)
+ }
}
}
object Routes{
- case class RouteMetadata[T](metadata: RouteBase,
+ case class RouteMetadata[T](metadata: EndpointAnnotation[_],
entryPoint: EntryPoint[T, HttpServerExchange])
case class Metadata[T](value: RouteMetadata[T]*)
object Metadata{
@@ -38,7 +42,7 @@ object Routes{
val routeParts = for{
m <- c.weakTypeOf[T].members
- annot <- m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[AnnotationBase])
+ annot <- m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[EndpointAnnotation[_]])
} yield {
val annotObject = q"new ${annot.tree.tpe}(..${annot.tree.children.tail})"
val annotObjectSym = c.universe.TermName(c.freshName("annotObject"))