summaryrefslogtreecommitdiff
path: root/haskell/src/SpaceTraders/APIClient
diff options
context:
space:
mode:
authorJulien Dessaux2023-07-02 22:58:30 +0200
committerJulien Dessaux2023-07-02 23:01:01 +0200
commita775330b4fa17fb367e55343e6fda6c7ae9e34b4 (patch)
tree8c572f799dbf434459d4659e32559c121421f120 /haskell/src/SpaceTraders/APIClient
parentMoved the nodejs agent to its own subfolder to make room for my haskell agent (diff)
downloadspacetraders-a775330b4fa17fb367e55343e6fda6c7ae9e34b4.tar.gz
spacetraders-a775330b4fa17fb367e55343e6fda6c7ae9e34b4.tar.bz2
spacetraders-a775330b4fa17fb367e55343e6fda6c7ae9e34b4.zip
Bootstrapped my haskell client
Diffstat (limited to '')
-rw-r--r--haskell/src/SpaceTraders/APIClient/Agent.hs34
-rw-r--r--haskell/src/SpaceTraders/APIClient/Client.hs69
2 files changed, 103 insertions, 0 deletions
diff --git a/haskell/src/SpaceTraders/APIClient/Agent.hs b/haskell/src/SpaceTraders/APIClient/Agent.hs
new file mode 100644
index 0000000..997d1e5
--- /dev/null
+++ b/haskell/src/SpaceTraders/APIClient/Agent.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module SpaceTraders.APIClient.Agent
+ ( RegisterMessage(..)
+ , myAgent
+ , register
+ ) where
+
+import Data.Aeson
+import GHC.Generics
+import qualified Data.Text as T
+import Network.HTTP.Simple
+
+import SpaceTraders.APIClient.Client
+import SpaceTraders.Model.Agent
+
+myAgent :: T.Text -> IO (Either APIError Agent)
+myAgent t = send $ setRequestPath "/v2/my/agent"
+ $ tokenReq t
+
+data RegisterRequest = RegisterRequest { symbol :: T.Text
+ , faction :: T.Text
+ } deriving (ToJSON, Generic, Show)
+data RegisterMessage = RegisterMessage { token :: T.Text
+ , agent :: Agent
+ } deriving (FromJSON, Generic, Show)
+
+register :: T.Text -> T.Text -> IO (Either APIError RegisterMessage)
+register s f = send $ setRequestPath "/v2/register"
+ $ setRequestMethod "POST"
+ $ setRequestBodyJSON RegisterRequest{symbol = s, faction = f}
+ $ defaultReq
diff --git a/haskell/src/SpaceTraders/APIClient/Client.hs b/haskell/src/SpaceTraders/APIClient/Client.hs
new file mode 100644
index 0000000..e4744aa
--- /dev/null
+++ b/haskell/src/SpaceTraders/APIClient/Client.hs
@@ -0,0 +1,69 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module SpaceTraders.APIClient.Client
+ ( APIError(..)
+ , APIMessage(..)
+ , defaultReq
+ , fromJSONValue
+ , send
+ , tokenReq
+ ) where
+
+import Control.Exception
+import Control.Monad
+import Data.Aeson
+import Data.Aeson.Types
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import Network.HTTP.Simple
+import Network.HTTP.Types.Status
+
+data APIError = APIError { apiErrorCode :: Int
+ , apiErrorMessage :: T.Text
+ } deriving Show
+instance Exception APIError
+instance FromJSON APIError where
+ parseJSON (Object o) = do
+ e <- o .: "error"
+ APIError <$> e .: "code"
+ <*> e .: "message"
+ parseJSON _ = mzero
+
+data APIMessage = APIMessage { data_ :: Value } deriving (Show)
+instance FromJSON APIMessage where
+ parseJSON (Object o) = APIMessage <$> o .: "data"
+ parseJSON _ = mzero
+
+defaultReq :: Request
+defaultReq = setRequestHost "api.spacetraders.io"
+ $ setRequestPort 443
+ $ setRequestSecure True
+ $ setRequestHeader "Content-Type" ["application/json"]
+ $ defaultRequest
+
+tokenReq :: T.Text -> Request
+tokenReq token = setRequestHeader "Authorization" [T.encodeUtf8 $ "Bearer " <> token]
+ $ defaultReq
+
+fromJSONValue :: FromJSON a => Value -> Either String a
+fromJSONValue = parseEither parseJSON
+
+send :: FromJSON a => Request -> IO (Either APIError a)
+send request = do
+ response <- httpLbs request
+ let status = statusCode $ getResponseStatus response
+ body = getResponseBody response
+ if status >= 200 && status <= 299
+ then case eitherDecode body of
+ Left e -> return $ Left APIError{apiErrorCode = -1000, apiErrorMessage = T.pack $ concat ["Error decoding JSON APIMessage: ", e]}
+ Right r -> case fromJSONValue (data_ r) of
+ Left e -> return $ Left APIError{apiErrorCode = -1001, apiErrorMessage = T.pack $ concat ["Error decoding JSON message contents: ", e]}
+ Right m -> return $ Right m
+ else case eitherDecode body of
+ Left e -> return $ Left APIError{apiErrorCode = -status, apiErrorMessage = T.pack $ concat ["Error decoding JSON APIError: ", e, ". Got HTTP body: ", show body]}
+ Right e -> return $ Left e
+
+--handleAPIError :: SomeException -> IO (Maybe RegisterMessage)
+--handleAPIError e = do
+-- print e
+-- return Nothing