summaryrefslogtreecommitdiff
path: root/cask/src/cask/main/Main.scala
blob: 28c77705a6945d9357e308a1a35de3fffd36bbf8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package cask.main

import cask.model.{BaseResponse, ParamContext, 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(
            ParamContext(exchange, remaining), bindings, routes,
            metadata.entryPoint.asInstanceOf[
              EntryPoint[metadata.metadata.InputType, cask.main.Routes, cask.model.ParamContext]
            ]
          )

          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()
  }
}