{-# LANGUAGE CPP, FlexibleContexts #-}
module Network.Wai.Session.Map (mapStore, mapStore_) where
import Control.Monad
import Data.StateVar
import Data.ByteString (ByteString)
import Control.Monad.IO.Class (liftIO, MonadIO)
import Data.IORef
import Network.Wai.Session (Session, SessionStore, genSessionId)
import Data.Map (Map)
import qualified Data.Map as Map
mapStore :: (Ord k, MonadIO m) =>
IO ByteString
-> IO (SessionStore m k v)
mapStore gen =
liftM (mapStore' gen) (newThreadSafeStateVar Map.empty)
where
mapStore' _ ssv (Just k) = do
m <- get ssv
case Map.lookup k m of
Just sv -> return (sessionFromMapStateVar sv, return k)
Nothing -> mapStore' gen ssv Nothing
mapStore' genNewKey ssv Nothing = do
newKey <- genNewKey
sv <- newThreadSafeStateVar Map.empty
ssv $~ Map.insert newKey sv
return (sessionFromMapStateVar sv, return newKey)
mapStore_ :: (Ord k, MonadIO m) => IO (SessionStore m k v)
mapStore_ = mapStore genSessionId
newThreadSafeStateVar :: a -> IO (StateVar a)
newThreadSafeStateVar a = do
ref <- newIORef a
return $ makeStateVar
(atomicModifyIORef ref (\x -> (x,x)))
(\x -> atomicModifyIORef ref (const (x,())))
#if MIN_VERSION_StateVar(1,1,0)
sessionFromMapStateVar :: (Ord k, MonadIO m) =>
StateVar (Map k v) ->
#else
sessionFromMapStateVar :: (HasGetter sv, HasSetter sv, Ord k, MonadIO m) =>
sv (Map k v) ->
#endif
Session m k v
sessionFromMapStateVar sv = (
(\k -> liftIO (Map.lookup k `liftM` get sv)),
(\k v -> liftIO (sv $~ Map.insert k v))
)