module Control.Monad.Twilio
(
Twilio
, runTwilio
, runTwilio'
, TwilioT(..)
, runTwilioT
, runTwilioT'
, Credentials
, TwilioException(..)
) where
import Control.Exception
import Control.Monad
import Control.Monad.Catch
import Control.Monad.IO.Class
import Control.Monad.Reader.Class
import Control.Monad.Trans.Class
import Control.Monad.Trans.Free
import qualified Data.ByteString.Lazy as LBS
import Data.Text (Text)
import qualified Data.Text as T
import Data.Typeable
import Network.HTTP.Client
import Twilio.Internal.Request
import Twilio.Types.AuthToken
import Twilio.Types.SID
type Twilio = TwilioT IO
runTwilio :: Credentials -> Twilio a -> IO a
runTwilio = runTwilioT
runTwilio' :: IO String
-> IO String
-> Twilio a
-> IO a
runTwilio' = runTwilioT'
newtype TwilioT m a = TwilioT (Monad m => (Credentials, AccountSID) -> RequestT m a)
getTwilioT :: Monad m => TwilioT m a -> (Credentials, AccountSID) -> RequestT m a
getTwilioT (TwilioT f) = f
instance Monad m => MonadRequest (TwilioT m) where
request go r
= TwilioT $ \config -> RequestT . FreeT . return . Free
$ RequestF (r, \response -> runRequestT $ getTwilioT (go response) config)
runTwilioT :: MonadIO m => Credentials -> TwilioT m a -> m a
runTwilioT credentials@(accountSID, authToken) (TwilioT go) = do
let basicAuthCredentials = (getSID accountSID, getAuthToken authToken)
let requestM = go (credentials, accountSID)
runRequest' basicAuthCredentials requestM
runTwilioT' :: (MonadThrow m, MonadIO m)
=> m String
-> m String
-> TwilioT m a
-> m a
runTwilioT' getAccountSID getAuthToken twilio = do
accountSID <- T.pack <$> getAccountSID
authToken <- T.pack <$> getAuthToken
case parseCredentials accountSID authToken of
Nothing -> throwM InvalidCredentials
Just credentials -> runTwilioT credentials twilio
instance Functor (TwilioT m) where
fmap f ma = TwilioT $ \credentials -> do
a <- getTwilioT ma credentials
return $ f a
liftTwilioT :: m a -> TwilioT m a
liftTwilioT m = TwilioT (const (lift m))
instance Applicative m => Applicative (TwilioT m) where
pure = liftTwilioT . pure
f <*> v = TwilioT $ \r -> getTwilioT f r <*> getTwilioT v r
instance Monad m => Monad (TwilioT m) where
return a = TwilioT (return . const a)
m >>= k = TwilioT $ \client -> do
a <- getTwilioT m client
getTwilioT (k a) client
instance Monad m => MonadReader (Credentials, AccountSID) (TwilioT m) where
ask = TwilioT return
local f m = TwilioT $ getTwilioT m . f
instance MonadThrow m => MonadThrow (TwilioT m) where
throwM = liftTwilioT . throwM
instance MonadTrans TwilioT where
lift m = TwilioT $ const (lift m)
instance MonadIO m => MonadIO (TwilioT m) where
liftIO = lift . liftIO
type Credentials = (AccountSID, AuthToken)
parseCredentials
:: Text
-> Text
-> Maybe Credentials
parseCredentials accountSID authToken = uncurry (liftM2 (,))
( parseSID accountSID :: Maybe AccountSID
, parseAuthToken authToken )
data TwilioException
= InvalidSID !Text
| InvalidAuthToken !Text
| InvalidCredentials
| UnexpectedResponse !(Response LBS.ByteString)
deriving (Show, Eq, Typeable)
instance Exception TwilioException