casualjim
9/8/2011 - 7:14 PM

gistfile1.scala

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