summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2019-09-15 17:23:34 +0800
committerLi Haoyi <haoyi.sg@gmail.com>2019-09-15 17:23:34 +0800
commit7a83582a623e7319827731ed95f100965a8d28dd (patch)
tree01dcc9e9b2164a8f3c200add903805a15a06ab22
parentdd34f0ba76b930b0d3972afb42ae3e7f830b85d2 (diff)
downloadcask-7a83582a623e7319827731ed95f100965a8d28dd.tar.gz
cask-7a83582a623e7319827731ed95f100965a8d28dd.tar.bz2
cask-7a83582a623e7319827731ed95f100965a8d28dd.zip
re-expose handleNotFound and handleEndpointError, update docs
-rw-r--r--cask/src/cask/main/Main.scala36
-rw-r--r--docs/pages/1 - Cask: a Scala HTTP micro-framework.md29
-rw-r--r--docs/pages/2 - Main Customization.md9
3 files changed, 47 insertions, 27 deletions
diff --git a/cask/src/cask/main/Main.scala b/cask/src/cask/main/Main.scala
index 949eff5..fddd9b7 100644
--- a/cask/src/cask/main/Main.scala
+++ b/cask/src/cask/main/Main.scala
@@ -38,9 +38,17 @@ abstract class Main{
def routeTries = Main.prepareRouteTries(allRoutes)
def defaultHandler = new BlockingHandler(
- new Main.DefaultHandler(routeTries, mainDecorators, debugMode)
+ new Main.DefaultHandler(routeTries, mainDecorators, debugMode, handleNotFound, handleEndpointError)
)
+ def handleNotFound() = Main.defaultHandleNotFound()
+
+ def handleEndpointError(routes: Routes,
+ metadata: EndpointMetadata[_],
+ e: Router.Result.Error) = {
+ Main.defaultHandleError(routes, metadata, e, debugMode)
+ }
+
def main(args: Array[String]): Unit = {
val server = Undertow.builder
.addHttpListener(port, host)
@@ -48,12 +56,15 @@ abstract class Main{
.build
server.start()
}
+
}
object Main{
class DefaultHandler(routeTries: Map[String, DispatchTrie[(Routes, EndpointMetadata[_])]],
mainDecorators: Seq[RawDecorator],
- debugMode: Boolean)
+ debugMode: Boolean,
+ handleNotFound: () => Response.Raw,
+ handleError: (Routes, EndpointMetadata[_], Router.Result.Error) => Response.Raw)
(implicit log: Logger) extends HttpHandler() {
def handleRequest(exchange: HttpServerExchange): Unit = try {
// println("Handling Request: " + exchange.getRequestPath)
@@ -91,13 +102,7 @@ object Main{
case e: Router.Result.Error =>
Main.writeResponse(
exchange,
- Main.handleEndpointError(
- exchange,
- routes,
- metadata,
- e,
- debugMode
- ).map(Response.Data.StringData)
+ handleError(routes, metadata, e)
)
None
}
@@ -108,7 +113,7 @@ object Main{
}
}
- def handleNotFound(): Response.Raw = {
+ def defaultHandleNotFound(): Response.Raw = {
Response(
s"Error 404: ${Status.codesToStatus(404).reason}",
statusCode = 404
@@ -138,12 +143,11 @@ object Main{
response.data.write(exchange.getOutputStream)
}
- def handleEndpointError(exchange: HttpServerExchange,
- routes: Routes,
- metadata: EndpointMetadata[_],
- e: Router.Result.Error,
- debugMode: Boolean)
- (implicit log: Logger) = {
+ def defaultHandleError(routes: Routes,
+ metadata: EndpointMetadata[_],
+ e: Router.Result.Error,
+ debugMode: Boolean)
+ (implicit log: Logger) = {
e match {
case e: Router.Result.Error.Exception => log.exception(e.t)
case _ => // do nothing
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 52653d2..a7ed073 100644
--- a/docs/pages/1 - Cask: a Scala HTTP micro-framework.md
+++ b/docs/pages/1 - Cask: a Scala HTTP micro-framework.md
@@ -349,21 +349,30 @@ $$$websockets
Cask's Websocket endpoints are very similar to Cask's HTTP endpoints. Annotated
with `@cask.websocket` instead of `@cask.get` or `@cask.post`, the primary
difference is that instead of only returning a `cask.Response`, you now have an
-option of returning a `io.undertow.websockets.WebSocketConnectionCallback`.
-
-The `WebSocketConnectionCallback` allows you to pro-actively start sending
-websocket messages once a connection has been made, and it lets you register a
-`AbstractReceiveListener` that allows you to react to any messages the client on
-the other side of the websocket connection sends you. You can use these two APIs
-to perform full bi-directional, asynchronous communications, as websockets are
-intended to be used for.
+option of returning a `cask.WsHandler`.
+
+The `cask.WsHandler` allows you to pro-actively start sending websocket messages
+once a connection has been made, via the `channel: WsChannelActor` it exposes,
+and lets you react to messages via the `cask.WsActor` you create. You can use
+these two APIs to perform full bi-directional, asynchronous communications, as
+websockets are intended to be used for. Note that all messages received on a
+each individual Websocket connection by your `cask.WsActor` are handled in a
+single-threaded fashion by default: this means you can work with local mutable
+state in your `@cask.websocket` endpoint without worrying about race conditions
+or multithreading. If you want further parallelism, you can explicitly spin off
+`scala.concurrent.Future`s or other `cask.BatchActor`s to perform that parallel
+processing.
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
+Cask also provides a lower-lever websocket interface, which allows you directly
+work with the underlying `io.undertow.websockets.WebSocketConnectionCallback`:
+
+$$$websockets2
+
+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
diff --git a/docs/pages/2 - Main Customization.md b/docs/pages/2 - Main Customization.md
index 25434bd..687587a 100644
--- a/docs/pages/2 - Main Customization.md
+++ b/docs/pages/2 - Main Customization.md
@@ -13,6 +13,12 @@ fails; useful for debugging, should be disabled for production.
The cask program entrypoint. By default just spins up a webserver, but you can
override it to do whatever you like before or after the webserver runs.
+## def log
+
+A logger that gets passed around the application. Used for convenient debug
+logging, as well as logging exceptions either to the terminal or to a
+centralized exception handler.
+
## def defaultHandler
Cask is built on top of the [Undertow](http://undertow.io/) web server. If you
@@ -41,4 +47,5 @@ useful stack traces or metadata for debugging if `debugMode = true`.
## def mainDecorators
Any `cask.Decorator`s that you want to apply to all routes and all endpoints in
-the entire web application
+the entire web application. Useful for inserting application-wide
+instrumentation, logging, security-checks, and similar things.