module Coinbase.Exchange.Types
( ApiType (..)
, Endpoint
, Path
, website
, sandboxRest
, sandboxSocket
, liveRest
, liveSocket
, liveRealCoinbaseRest
, sandboxRealCoinbaseRest
, Key
, Secret
, Passphrase
, Token
, key
, secret
, passphrase
, mkToken
, ExchangeConf (..)
, ExchangeFailure (..)
, Exchange
, ExchangeT
, ExceptT
, runExchange
, runExchangeT
, execExchange
, execExchangeT
, getManager
) where
import Control.Applicative
import Control.Monad.Base
import Control.Monad.Catch
import Control.Monad.Except
import Control.Monad.Reader
import Control.Monad.Trans.Resource
import Data.ByteString
import qualified Data.ByteString.Base64 as Base64
import Data.Data
import Data.Text (Text)
import GHC.Generics
import Network.HTTP.Conduit
data ApiType
= Sandbox
| Live
deriving (Show)
type Endpoint = String
type Path = String
website :: Endpoint
website = "https://public.sandbox.gdax.com"
sandboxRest :: Endpoint
sandboxRest = "https://api-public.sandbox.gdax.com"
sandboxSocket :: Endpoint
sandboxSocket = "ws-feed-public.sandbox.gdax.com"
liveRest :: Endpoint
liveRest = "https://api.gdax.com"
liveSocket :: Endpoint
liveSocket = "ws-feed.gdax.com"
liveRealCoinbaseRest :: Endpoint
liveRealCoinbaseRest = "https://api.coinbase.com"
sandboxRealCoinbaseRest :: Endpoint
sandboxRealCoinbaseRest = "https://api.sandbox.coinbase.com"
type Key = ByteString
type Secret = ByteString
type Passphrase = ByteString
data Token
= Token
{ key :: ByteString
, secret :: ByteString
, passphrase :: ByteString
}
mkToken :: Key -> Secret -> Passphrase -> Either String Token
mkToken k s p = case Base64.decode s of
Right s' -> Right $ Token k s' p
Left e -> Left e
data ExchangeConf
= ExchangeConf
{ manager :: Manager
, authToken :: Maybe Token
, apiType :: ApiType
}
data ExchangeFailure = ParseFailure Text
| ApiFailure Text
| AuthenticationRequiredFailure Text
| AuthenticationRequiresByteStrings
deriving (Show, Data, Typeable, Generic)
instance Exception ExchangeFailure
type Exchange a = ExchangeT IO a
newtype ExchangeT m a = ExchangeT { unExchangeT :: ResourceT (ReaderT ExchangeConf (ExceptT ExchangeFailure m)) a }
deriving ( Functor, Applicative, Monad, MonadIO, MonadThrow
, MonadError ExchangeFailure
, MonadReader ExchangeConf
)
deriving instance (MonadBase IO m) => MonadBase IO (ExchangeT m)
deriving instance (Monad m, MonadThrow m, MonadIO m, MonadBase IO m) => MonadResource (ExchangeT m)
runExchange :: ExchangeConf -> Exchange a -> IO (Either ExchangeFailure a)
runExchange = runExchangeT
runExchangeT :: MonadBaseControl IO m => ExchangeConf -> ExchangeT m a -> m (Either ExchangeFailure a)
runExchangeT conf = runExceptT . flip runReaderT conf . runResourceT . unExchangeT
execExchange :: ExchangeConf -> Exchange a -> IO a
execExchange = execExchangeT
execExchangeT :: (MonadThrow m, MonadBaseControl IO m) => ExchangeConf -> ExchangeT m a -> m a
execExchangeT conf act = do
v <- runExceptT . flip runReaderT conf . runResourceT . unExchangeT $ act
case v of
Left er -> throwM er
Right v -> return v
getManager :: (MonadReader ExchangeConf m) => m Manager
getManager = do
conf <- ask
return $ manager conf