packages feed

hexpress-0.1.0.0: src/Network/Hexpress/Types.hs

module Network.Hexpress.Types
( Server
, Middleware
, passthrough
, serverToApp
, addHeader
, sendByteString
, setStatus
, getRequest
, performIO
) where

import qualified Network.Wai as WAI
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.State.Lazy
import Data.ByteString.Lazy.Char8 as LB
import Data.ByteString.Char8 as SB
import Network.HTTP.Types.Status
import Network.HTTP.Types.Header
import Control.Monad.State.Class as ST
import Control.Monad.IO.Class
import Data.Binary.Builder as Builder

data ServerState = ServerState {
  req :: WAI.Request,
  toSend :: Builder,
  responseStatus :: Status,
  headers :: [Header]
}

type ServerIO = StateT ServerState IO

type Server = MaybeT ServerIO
type Middleware a b = a -> Server b

passthrough :: Server a -> (b -> Server b)
passthrough srv = \val -> srv >> return val

addHeader :: (HeaderName, SB.ByteString) -> Server ()
addHeader hd = do
  st <- ST.get
  let newST = st {headers=(headers st) ++ [hd]}
  ST.put newST

sendByteString :: LB.ByteString -> Server ()
sendByteString str = do
  st <- ST.get
  let newStr = Builder.fromLazyByteString str
  let newSt = st {toSend=Builder.append (toSend st) newStr}
  ST.put newSt

setStatus :: Status -> Server ()
setStatus stat = do
  st <- ST.get
  let newST = st {responseStatus=stat}
  ST.put newST

getRequest :: Server WAI.Request
getRequest = do
  st <- ST.get
  return $ req st

performIO :: IO a -> Server a
performIO ioact = liftIO ioact

serverToApp :: Server () -> IO WAI.Application
serverToApp serv = return $ \request resp -> do
  let st = runMaybeT serv -- ServerIO type
  endState <- execStateT st (ServerState request Builder.empty status200 [])
  let responseString = Builder.toLazyByteString $ toSend endState
  resp $ WAI.responseLBS (responseStatus endState) (headers endState) responseString