Config.hs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. {-# LANGUAGE OverloadedStrings #-}
  2. {-# LANGUAGE TypeFamilies #-}
  3. {-# OPTIONS_GHC -Wno-orphans #-}
  4. module Database.Persist.Redis.Config
  5. ( RedisAuth (..)
  6. , RedisConf (..)
  7. , R.RedisCtx
  8. , R.Redis
  9. , R.Connection
  10. , R.PortID (..)
  11. , RedisT
  12. , runRedisPool
  13. , withRedisConn
  14. , thisConnection
  15. , module Database.Persist
  16. ) where
  17. import Control.Monad.IO.Class (MonadIO (..))
  18. import Control.Monad.Reader(ReaderT(..))
  19. import Control.Monad.Reader.Class
  20. import Data.Aeson (Value (Object, Number, String), (.:?), (.!=), FromJSON(..))
  21. import qualified Data.ByteString.Char8 as B
  22. import Control.Monad (mzero, MonadPlus(..))
  23. import Data.Scientific() -- we require only RealFrac instance of Scientific
  24. import Data.Text (Text, unpack, pack)
  25. import qualified Database.Redis as R
  26. import Database.Persist
  27. newtype RedisAuth = RedisAuth Text deriving (Eq, Show)
  28. -- | Information required to connect to a Redis server
  29. data RedisConf = RedisConf {
  30. rdHost :: Text, -- ^ Host
  31. rdPort :: R.PortID, -- ^ Port
  32. rdAuth :: Maybe RedisAuth, -- ^ Auth info
  33. rdMaxConn :: Int -- ^ Maximum number of connections
  34. } deriving (Show)
  35. instance FromJSON R.PortID where
  36. parseJSON (Number x) = (return . R.PortNumber . fromInteger . truncate) x
  37. parseJSON _ = fail "persistent Redis: couldn't parse port number"
  38. instance FromJSON RedisAuth where
  39. parseJSON (String t) = (return . RedisAuth) t
  40. parseJSON _ = fail "persistent ResisAuth: couldn't parse auth"
  41. -- | Monad reader transformer keeping Redis connection through out the work
  42. type RedisT = ReaderT R.Connection
  43. -- | Extracts connection from RedisT monad transformer
  44. thisConnection :: Monad m => RedisT m R.Connection
  45. thisConnection = ask
  46. -- | Run a connection reader function against a Redis configuration
  47. withRedisConn :: (MonadIO m) => RedisConf -> (R.Connection -> m a) -> m a
  48. withRedisConn conf connectionReader = do
  49. conn <- liftIO $ createPoolConfig conf
  50. connectionReader conn
  51. runRedisPool :: RedisT m a -> R.Connection -> m a
  52. runRedisPool r = runReaderT r
  53. instance PersistConfig RedisConf where
  54. type PersistConfigBackend RedisConf = RedisT
  55. type PersistConfigPool RedisConf = R.Connection
  56. loadConfig (Object o) = do
  57. host <- o .:? "host" .!= R.connectHost R.defaultConnectInfo
  58. port <- o .:? "port" .!= R.connectPort R.defaultConnectInfo
  59. mPass <- o .:? "password"
  60. maxConn <- o .:? "maxConn" .!= R.connectMaxConnections R.defaultConnectInfo
  61. return RedisConf {
  62. rdHost = pack host,
  63. rdPort = port,
  64. rdAuth = mPass,
  65. rdMaxConn = maxConn
  66. }
  67. loadConfig _ = mzero
  68. createPoolConfig (RedisConf h p Nothing m) =
  69. R.connect $
  70. R.defaultConnectInfo {
  71. R.connectHost = unpack h,
  72. R.connectPort = p,
  73. R.connectMaxConnections = m
  74. }
  75. createPoolConfig (RedisConf h p (Just (RedisAuth pwd)) m) =
  76. R.connect $
  77. R.defaultConnectInfo {
  78. R.connectHost = unpack h,
  79. R.connectPort = p,
  80. R.connectAuth = Just $ B.pack $ unpack pwd,
  81. R.connectMaxConnections = m
  82. }
  83. runPool _ = runRedisPool