summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2018-08-13 15:00:14 +0800
committerLi Haoyi <haoyi.sg@gmail.com>2018-08-13 15:25:11 +0800
commita873d77fbeb4590dceeb893ab067beb9058db241 (patch)
tree3132f93c3f78206ad3ca7af8dd7f04a116c216ed
parent3ff5a5079080de524375cd43425c1515bf128274 (diff)
downloadcask-a873d77fbeb4590dceeb893ab067beb9058db241.tar.gz
cask-a873d77fbeb4590dceeb893ab067beb9058db241.tar.bz2
cask-a873d77fbeb4590dceeb893ab067beb9058db241.zip
Tweak websocket tests, example and docs
-rw-r--r--cask/src/cask/endpoints/FormEndpoint.scala2
-rw-r--r--cask/src/cask/endpoints/JsonEndpoint.scala2
-rw-r--r--cask/src/cask/endpoints/StaticEndpoints.scala7
-rw-r--r--cask/src/cask/main/Main.scala19
-rwxr-xr-xci/test.sh2
-rw-r--r--docs/pages/1 - Cask: a Scala HTTP micro-framework .md11
-rw-r--r--example/endpoints/app/src/Endpoints.scala6
-rw-r--r--example/websockets/app/src/Websockets.scala8
-rw-r--r--example/websockets/app/test/src/ExampleTests.scala2
9 files changed, 29 insertions, 30 deletions
diff --git a/cask/src/cask/endpoints/FormEndpoint.scala b/cask/src/cask/endpoints/FormEndpoint.scala
index eb882fa..a952a2a 100644
--- a/cask/src/cask/endpoints/FormEndpoint.scala
+++ b/cask/src/cask/endpoints/FormEndpoint.scala
@@ -43,7 +43,7 @@ object FormReader{
def read(ctx: ParamContext, label: String, input: Seq[FormEntry]) = input.map(_.asInstanceOf[FormFile])
}
}
-class postForm(val path: String, override val subpath: Boolean = false) extends Endpoint with HttpDecorator{
+class postForm(val path: String, override val subpath: Boolean = false) extends Endpoint {
type Output = Response
val methods = Seq("post")
diff --git a/cask/src/cask/endpoints/JsonEndpoint.scala b/cask/src/cask/endpoints/JsonEndpoint.scala
index f3b0cae..f91b888 100644
--- a/cask/src/cask/endpoints/JsonEndpoint.scala
+++ b/cask/src/cask/endpoints/JsonEndpoint.scala
@@ -26,7 +26,7 @@ object JsReader{
}
}
}
-class postJson(val path: String, override val subpath: Boolean = false) extends Endpoint with HttpDecorator{
+class postJson(val path: String, override val subpath: Boolean = false) extends Endpoint{
type Output = Response
val methods = Seq("post")
type Input = ujson.Js.Value
diff --git a/cask/src/cask/endpoints/StaticEndpoints.scala b/cask/src/cask/endpoints/StaticEndpoints.scala
index a9b3193..726af21 100644
--- a/cask/src/cask/endpoints/StaticEndpoints.scala
+++ b/cask/src/cask/endpoints/StaticEndpoints.scala
@@ -1,10 +1,9 @@
package cask.endpoints
-import cask.internal.Router
-import cask.main.{Endpoint, HttpDecorator}
-import cask.model.{ParamContext, Response}
+import cask.main.Endpoint
+import cask.model.ParamContext
-class static(val path: String) extends Endpoint with HttpDecorator{
+class static(val path: String) extends Endpoint{
type Output = String
val methods = Seq("get")
type Input = Seq[String]
diff --git a/cask/src/cask/main/Main.scala b/cask/src/cask/main/Main.scala
index 94d0e14..1b69597 100644
--- a/cask/src/cask/main/Main.scala
+++ b/cask/src/cask/main/Main.scala
@@ -53,8 +53,8 @@ abstract class BaseMain{
)
}
- def genericWebsocketHandler(exchange0: HttpServerExchange) =
- hello(exchange0, "websocket", ParamContext(exchange0, _), exchange0.getRequestPath).foreach{ r =>
+ def websocketEndpointHandler(exchange0: HttpServerExchange) =
+ invokeEndpointFunction(exchange0, "websocket", exchange0.getRequestPath).foreach{ r =>
r.asInstanceOf[WebsocketResult] match{
case l: WebsocketResult.Listener =>
io.undertow.Handlers.websocket(l.value).handleRequest(exchange0)
@@ -67,10 +67,9 @@ abstract class BaseMain{
new HttpHandler() {
def handleRequest(exchange: HttpServerExchange): Unit = {
if (exchange.getRequestHeaders.getFirst("Upgrade") == "websocket") {
-
- genericWebsocketHandler(exchange)
+ websocketEndpointHandler(exchange)
} else {
- defaultHttpHandler.handleRequest(exchange)
+ httpEndpointHandler.handleRequest(exchange)
}
}
}
@@ -82,24 +81,24 @@ abstract class BaseMain{
}
}
)
- def defaultHttpHandler = new BlockingHandler(
+
+ def httpEndpointHandler = new BlockingHandler(
new HttpHandler() {
def handleRequest(exchange: HttpServerExchange) = {
- hello(exchange, exchange.getRequestMethod.toString.toLowerCase(), ParamContext(exchange, _), exchange.getRequestPath).foreach{ r =>
+ invokeEndpointFunction(exchange, exchange.getRequestMethod.toString.toLowerCase(), exchange.getRequestPath).foreach{ r =>
writeResponse(exchange, r.asInstanceOf[Response])
}
}
}
)
- def hello(exchange0: HttpServerExchange, effectiveMethod: String, ctx0: Seq[String] => ParamContext, path: String) = {
+ def invokeEndpointFunction(exchange0: HttpServerExchange, effectiveMethod: String, path: String) = {
routeTries(effectiveMethod).lookup(Util.splitPath(path).toList, Map()) match{
case None =>
writeResponse(exchange0, handleNotFound())
None
case Some(((routes, metadata), extBindings, remaining)) =>
val ctx = ParamContext(exchange0, remaining)
- val ctx1 = ctx0(remaining)
def rec(remaining: List[Decorator],
bindings: List[Map[String, Any]]): Router.Result[Any] = try {
remaining match {
@@ -110,7 +109,7 @@ abstract class BaseMain{
metadata.endpoint.wrapFunction(ctx, epBindings =>
metadata.entryPoint
.asInstanceOf[EntryPoint[cask.main.Routes, cask.model.ParamContext]]
- .invoke(routes, ctx1, (epBindings ++ extBindings.mapValues(metadata.endpoint.wrapPathSegment)) :: bindings.reverse)
+ .invoke(routes, ctx, (epBindings ++ extBindings.mapValues(metadata.endpoint.wrapPathSegment)) :: bindings.reverse)
.asInstanceOf[Router.Result[Nothing]]
)
}
diff --git a/ci/test.sh b/ci/test.sh
index a493514..3c955b9 100755
--- a/ci/test.sh
+++ b/ci/test.sh
@@ -2,4 +2,4 @@
set -eux
-mill -i __.testLocal \ No newline at end of file
+mill -i --disable-ticker __.testLocal \ No newline at end of file
diff --git a/docs/pages/1 - Cask: a Scala HTTP micro-framework .md b/docs/pages/1 - Cask: a Scala HTTP micro-framework .md
index 131d06b..df79f09 100644
--- a/docs/pages/1 - Cask: a Scala HTTP micro-framework .md
+++ b/docs/pages/1 - Cask: a Scala HTTP micro-framework .md
@@ -319,6 +319,13 @@ Returning a `cask.Response` immediately closes the websocket connection, and is
useful if you want to e.g. return a 404 or 403 due to the initial request being
invalid.
+Cask intentionally provides a relatively low-level websocket interface. It
+leaves it up to you to manage open channels, react to incoming messages, or
+pro-actively send them out, mostly using the underlying Undertow webserver
+interface. While Cask does not model streams, backpressure, iteratees, or
+provide any higher level API, it should not be difficult to take the Cask API
+and build whatever higher-level abstractions you prefer to use.
+
### TodoMVC Api Server
@@ -396,9 +403,7 @@ need some low-level functionality not exposed by the Cask API, you can override
`defaultHandler` to make use of Undertow's own
[handler API](http://undertow.io/undertow-docs/undertow-docs-2.0.0/index.html#built-in-handlers)
for customizing your webserver. This allows for things that Cask itself doesn't
-internally support: asynchronous requests & response,
-[Websockets](http://undertow.io/undertow-docs/undertow-docs-2.0.0/index.html#websockets),
-etc.
+internally support.
### def port: Int = 8080, def host: String = "localhost"
diff --git a/example/endpoints/app/src/Endpoints.scala b/example/endpoints/app/src/Endpoints.scala
index 9eadf39..5450029 100644
--- a/example/endpoints/app/src/Endpoints.scala
+++ b/example/endpoints/app/src/Endpoints.scala
@@ -1,10 +1,6 @@
package app
-import cask.main.HttpDecorator
-import cask.model.ParamContext
-
-
-class custom(val path: String, val methods: Seq[String]) extends cask.Endpoint with HttpDecorator{
+class custom(val path: String, val methods: Seq[String]) extends cask.Endpoint{
type Output = Int
def wrapFunction(ctx: cask.ParamContext, delegate: Delegate): Returned = {
delegate(Map()).map{num =>
diff --git a/example/websockets/app/src/Websockets.scala b/example/websockets/app/src/Websockets.scala
index 277b06f..a6ceb73 100644
--- a/example/websockets/app/src/Websockets.scala
+++ b/example/websockets/app/src/Websockets.scala
@@ -13,14 +13,14 @@ object Websockets extends cask.MainRoutes{
channel.getReceiveSetter.set(
new AbstractReceiveListener() {
override def onFullTextMessage(channel: WebSocketChannel, message: BufferedTextMessage) = {
- val data = message.getData
- if (data == "") channel.close()
- else WebSockets.sendTextBlocking(userName + " " + data, channel)
+ message.getData match{
+ case "" => channel.close()
+ case data => WebSockets.sendTextBlocking(userName + " " + data, channel)
+ }
}
}
)
channel.resumeReceives()
-
}
}
}
diff --git a/example/websockets/app/test/src/ExampleTests.scala b/example/websockets/app/test/src/ExampleTests.scala
index 403fde0..969750c 100644
--- a/example/websockets/app/test/src/ExampleTests.scala
+++ b/example/websockets/app/test/src/ExampleTests.scala
@@ -105,7 +105,7 @@ object ExampleTests extends TestSuite{
w.sendTextFrame("")
Thread.sleep(1)
}
- Thread.sleep(1500)
+ Thread.sleep(2000)
out.length ==> 2000
}finally{