packages feed

salvia-0.0.5: src/Network/Salvia/Core/Handler.hs

{-# LANGUAGE FlexibleInstances, TemplateHaskell #-}

module Network.Salvia.Core.Handler (
    SendAction
  , SendQueue
  , Context (..)

  , config
  , request
  , response
  , sock
  , address
  , queue

  , mkContext

  , Handler
  , ResourceHandler
  , UriHandler
  ) where

import Control.Applicative (Applicative, pure, (<*>))
import Control.Monad.State (StateT, ap)
import Data.Record.Label
import Network.Protocol.Http (Message, emptyRequest, emptyResponse)
import Network.Protocol.Uri (URI)
import Network.Salvia.Core.Config
import Network.Socket (SockAddr)
import System.IO

-------- single request/response context --------------------------------------

type SendAction = Handle -> IO ()
type SendQueue  = [SendAction]

data Context =
  Context {
    _config   :: HttpdConfig -- ^ The HTTP server configuration.
  , _request  :: Message     -- ^ The HTTP request header.
  , _response :: Message     -- ^ The HTTP response header.
  , _sock     :: Handle      -- ^ The socket handle for the connection with the client.
  , _address  :: SockAddr    -- ^ The client addres.
  , _queue    :: SendQueue   -- ^ The queue of send actions.
  }

$(mkLabels [''Context])

queue    :: Label Context SendQueue
address  :: Label Context SockAddr
sock     :: Label Context Handle
response :: Label Context Message
request  :: Label Context Message
config   :: Label Context HttpdConfig

-- Create and empty server context.
mkContext :: HttpdConfig -> SockAddr -> Handle -> Context
mkContext c a s = Context {
    _config   = c
  , _request  = emptyRequest
  , _response = emptyResponse  -- 200 OK, by default.
  , _sock     = s
  , _address  = a
  , _queue    = []
  }

-------- request handlers -----------------------------------------------------

-- HTTP handler types.
type Handler         a = StateT Context IO a
type ResourceHandler a = FilePath -> Handler a
type UriHandler      a = URI -> Handler a

-- Make handlers applicative.
instance Applicative (StateT Context IO) where
  pure  = return
  (<*>) = ap