packages feed

n2o-0.11.0: src/Network/N2O/Types.hs

{-# LANGUAGE KindSignatures #-}

{-|
Module      : Network.N2O.Types
Description : Basic types
Copyright   : (c) Marat Khafizov, 2018
License     : BSD-3
Maintainer  : xafizoff@gmail.com
Stability   : experimental
Portability : not portable

Basic types

-}
module Network.N2O.Types where

import qualified Data.Binary as B
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import Data.IORef
import Data.Map.Strict (Map, (!?), insert)
import qualified Data.Text.Lazy as TL

-- | An HTTP header
type Header = (BS.ByteString, BS.ByteString)

-- | An HTTP request
data Req = Req
  { reqPath :: BS.ByteString
  , reqMeth :: BS.ByteString
  , reqVers :: BS.ByteString
  , reqHead :: [Header]
  }

-- | The N2O context data type
-- This is the key data type of the N2O. @(f :: * -> *)@ - type constructor
-- for the protocol handler's input type. @(a :: *)@ - base type for the
-- event handler's input type. I.e. @(f a)@ gives input type for the
-- protocol handler. @(Event a)@ gives input type for the event handler.
data Context (f :: * -> *) a = Context
  { cxHandler :: Event a -> N2O f a (Result a)
  , cxReq :: Req
  , cxMiddleware :: [Context f a -> Context f a]
  , cxProtos :: [Proto f a]
  , cxDePickle :: BL.ByteString -> Maybe a
  , cxPickle :: a -> BL.ByteString
  , cxState :: Map BS.ByteString BL.ByteString
  }

-- | Result of the message processing
data Result a
  = Reply a
  | Ok
  | Unknown
  | Empty
  deriving (Show, Eq)

-- | N2O protocol handler
newtype Proto f a = Proto
  { protoInfo :: f a -> N2O f a (Result (f a))
  }

-- | Event data type
data Event a
  = Init
  | Message a
  | Terminate

-- | Local mutable state
type State f a = IORef (Context f a)

-- | 'N2OT' over 'IO' with 'N2OState' as env
type N2O f a = N2OT (State f a) IO

-- | Reader monad transformer
newtype N2OT state m a = N2OT
  { runN2O :: state -> m a
  }

instance Functor m => Functor (N2OT state m) where
  fmap f (N2OT g) = N2OT (fmap f . g)

instance Applicative m => Applicative (N2OT state m) where
  pure = N2OT . const . pure
  (N2OT f) <*> (N2OT g) = N2OT $ \state -> f state <*> g state

instance Monad m => Monad (N2OT state m) where
  m >>= k =
    N2OT $ \state -> do
      a <- runN2O m state
      runN2O (k a) state