{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-} {-| Module : Network.N2O.Core Description : Core functions Copyright : (c) Marat Khafizov, 2018 License : BSD 3-Clause Maintainer : xafizoff@gmail.com Stability : experimental Portability : not portable Core functions -} module Network.N2O.Core (lift, ask, put, get, mkCx, mkReq, protoRun) where import Data.IORef import qualified Data.Map.Strict as M import qualified Data.Binary as B import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL import qualified Data.Text.Lazy as TL import Control.Exception (SomeException) import Network.N2O.Types import Data.Map.Strict (insert, (!?)) -- | 'Context' constructor mkCx = Context { cxReq = undefined , cxHandler = undefined , cxMiddleware = [] , cxDePickle = undefined , cxPickle = undefined , cxProtos = [] , cxState = M.empty } -- | 'Req' constructor mkReq = Req { reqPath = "/", reqMeth = "GET", reqVers = "HTTP/1.1", reqHead = [] } -- | NO-OP result nop :: Result a nop = Empty -- | N2O protocol loop protoRun :: f a -> [Proto f a] -> N2O f a (Result (f a)) protoRun = loop [] where loop _ _ [] = return nop loop acc msg (proto:protos) = do res <- protoInfo proto msg case res of Unknown -> loop acc msg protos Empty -> return Empty Reply msg1 -> return $ Reply msg1 a -> loop (a : acc) msg protos -- | Lift underlying monad to the N2O monad lift :: m a -> N2OT state m a lift m = N2OT (const m) -- | Get current state (env) ask :: (Monad m) => N2OT state m state ask = N2OT return getContext = do ref <- ask lift $ readIORef ref -- | Put data to the local state put :: (B.Binary bin) => BS.ByteString -> bin -> N2O f a () put k v = do state <- ask lift $ modifyIORef state (\cx@Context{cxState=m} -> cx{cxState=insert k (B.encode v) m}) -- | Get data from the local state get :: (B.Binary bin) => BS.ByteString -> N2O f a (Maybe bin) get k = do state <- N2OT return cx <- lift $ readIORef state let mp = cxState cx case mp !? k of Just v -> return $ Just (B.decode v) _ -> return Nothing