module Bittrex.Internal where
import Bittrex.Types
import qualified Control.Lens as Lens
import Data.Aeson
import Data.Aeson.Lens (key, nth)
import qualified Data.ByteString.Char8 as BSC8
import qualified Data.ByteString.Lazy as LBS
import Data.Char (toLower)
import Data.Digest.Pure.SHA
import Data.List (intercalate)
import Data.List.Split (splitOn)
import Data.Monoid
import qualified Data.Text as Text
import Data.Time.Clock.POSIX
import Debug.Trace
import Flow ((.>), (|>))
import Network.Wreq
defOpts :: APIOpts
defOpts = APIOpts PublicAPI [] "v1.1" mempty (APIKeys mempty mempty)
callAPI
:: (FromJSON v)
=> APIOpts
-> IO (Either ErrorMessage v)
callAPI (APIOpts {..}) = do
let (APIKeys {..}) = apiOptsKeys
nonce <- head . splitOn "." . show <$> getPOSIXTime
let addAuth = apiOptsAPIType `elem` [AccountAPI, MarketAPI]
let authParams = [ [("apikey", apiKey) | addAuth]
, [("nonce", nonce) | addAuth]
] |> mconcat
let url = [ "https://bittrex.com/api"
, Text.unpack apiOptsVersion
, toLower <$> show apiOptsAPIType
, Text.unpack apiOptsPath
] |> intercalate "/"
let go (k, v) = k <> "=" <> v <> "&"
let urlForHash = [ url, "?", go =<< do apiOptsQueryParams ++ authParams
] |> mconcat |> init
let addHeader o = let secretLBS = LBS.fromStrict (BSC8.pack secretKey)
apisign = BSC8.pack
$ showDigest
$ hmacSha512 secretLBS
$ LBS.fromStrict (BSC8.pack urlForHash)
in if addAuth
then o |> Lens.set (header "apisign") [apisign]
else o
r <- getWith (addHeader defaults) urlForHash
let Just (Bool success) = r |> Lens.preview (responseBody . key "success")
let Just result = r |> Lens.preview (responseBody . key "result")
let Just msg = r |> Lens.preview (responseBody . key "message")
pure $ if success
then case fromJSON result of
Error s -> Left (DecodeFailure s result)
Success m -> Right m
else case fromJSON msg of
Error s -> Left (DecodeFailure s msg)
Success m -> Left (BittrexError m)