module Network.Wai.Session.TokyoCabinet (tokyocabinetStore, tokyocabinetStore_) where
import Control.Monad
import Data.ByteString (ByteString)
import Control.Monad.IO.Class (liftIO, MonadIO)
import Network.Wai.Session (Session, SessionStore, genSessionId)
import Control.Error (hush)
import qualified Data.ByteString as BS
import Database.TokyoCabinet
import Data.Serialize (encode, decode, Serialize)
-- | Session store that keeps all content in TokyoCabinet
--
-- WARNING: This session is vulnerable to sidejacking,
-- use with TLS for security.
tokyocabinetStore :: (TCDB a, Serialize k, Serialize v, MonadIO m) =>
IO ByteString
-- ^ 'IO' action to generate unique session IDs
-> a
-- ^ TokyoCabinet handle
-> SessionStore m k v
tokyocabinetStore _ db (Just sk) = backend db sk
tokyocabinetStore genNewKey db Nothing = genNewKey >>= backend db
-- | Store using simple session ID generator based on time and 'Data.Unique'
tokyocabinetStore_ :: (TCDB a, Serialize k, Serialize v, MonadIO m) => a -> SessionStore m k v
tokyocabinetStore_ = tokyocabinetStore genSessionId
backend :: (TCDB a, Serialize k, Serialize v, MonadIO m) => a -> ByteString -> IO (Session m k v, IO ByteString)
backend db sk =
return ((
liftTCM . liftM (join . liftM (hush . decode)) . get db . fullKey,
(\k v -> liftTCM $ put db (fullKey k) (encode v) >> return ())
), return sk)
where
liftTCM = liftIO . runTCM
fullKey k = sk `BS.append` encode k