trait HandlerArgs {
def isInitial: Boolean
}
case object InitialArgs { val isInitial = true }
case object ContinuationArgs { val isInitial = false }
class Handler extends ((Request, HandlerArgs) => Response)
class Middleware extends (Handler => Handler)
object Server {
type ResponseWriter = Response => Result
val handler: Handler
object Executor {
@tailrec
def apply(handle: Handler, write: ResponseWriter, onError: ErrorHandler): Response = {
val res = handle(req, args)
(args, res match {
case (InitialArgs, r: BeginResponse) => write(r)
case (InitialArgs, _) => onError(new YouCantDoThisRightHereNowException())
case (ContinuationArgs, r: EndResponse) => r
case (ContinuationArgs, r: Response) => {
write(r)
apply(h => handle(req, ContinuationArgs), write, onError)
}
}
}
def apply(req: Request, args: HandlerArgs) = {
(future { Executor((r, a) => handler(r, a), socket.send _) } onComplete (socket.send _) onException (throw _)).get
}
}
sealed trait Response {
type ContentType
def headers: Map[String, String]
def content: ContentType
def update(statusLine: String, headers: Map[String, String], content: ContentType): ResponsePrelude
}
sealed trait ResponsePrelude extends Response {
def statusLine: String
def update(statusLine: String, headers: Map[String, String], content: ContentType): ResponsePrelude
}
sealed trait ResponseCompletion { self: Response =>
}
sealed trait ResponsePart extends Response {
def update(headers: Map[String, String], content: ContentType): ResponsePart
}
case class BeginResponse[T : Manifest](statusLine: String, headers: Map[String, String], content: T) extends ResponsePrelude {
type ContentType = T
def update(statusLine: String = this.statusLine, headers: Map[String, String] = headers, content: ContentType = content): ResponsePrelude =
copy(statusLine, headers, content)
}
case class ResponseChunk[T : Manifest](headers: Map[String, String], content: T) {
type ContentType = T
def update(headers: Map[String, String] = headers, content: ContentType = content): ResponsePrelude =
copy(headers, content)
}
case class EndResponse[T: Manifest](headers: Map[String, String], content: T) extends ResponseCompletion {
type ContentType = T
def update(headers: Map[String, String] = headers, content: ContentType = content): ResponsePrelude =
copy(headers, content)
}
case class DefaultResponse[T: Manifest](statusLine: String, headers: Map[String, String], content: T) extends ResponsePrelude with ResponseCompletion {
type ContentType = T
def update(statusLine: String = this.statusLine, headers: Map[String, String] = headers, content: ContentType = content): ResponsePrelude =
copy(statusLine, headers, content)
}