1
0
Fork 0

[haskell] Finalized the agent initialization, refresh and reset

This commit is contained in:
Julien Dessaux 2023-07-20 00:24:31 +02:00
parent b763823376
commit 24f6c8eb90
Signed by: adyxax
GPG key ID: F92E51B86E07177E
9 changed files with 105 additions and 46 deletions

View file

@ -8,29 +8,25 @@ import System.Posix.Process
import SpaceTraders import SpaceTraders
import SpaceTraders.Automation.Init import SpaceTraders.Automation.Init
import SpaceTraders.APIClient.Agent(myAgent) import SpaceTraders.APIClient.Errors
import SpaceTraders.APIClient.Client
import SpaceTraders.APIClient.Ships
import SpaceTraders.APIClient.Systems import SpaceTraders.APIClient.Systems
import SpaceTraders.Database.Agents
import SpaceTraders.Database.Contracts
import SpaceTraders.Database.Ships
main :: IO () main :: IO ()
main = do main = do
env <- initST env <- initST
ma <- runSpaceTradersT myAgent env runSpaceTradersT getAgent env >>= print
case ma of s <- runSpaceTradersT initSystems env
Left (APIResetHappened _) -> do
p <- getExecutablePath
a <- getArgs
e <- getEnvironment
executeFile p False a (Just e)
Left e -> throwIO e
Right ma' -> print ma'
s <- runSpaceTradersT listSystems env
case s of case s of
Left (APIResetHappened _) -> do
p <- getExecutablePath
a <- getArgs
e <- getEnvironment
executeFile p False a (Just e)
Left e -> throwIO e Left e -> throwIO e
Right s' -> print $ length s' Right s' -> print $ length s'
ships <- runSpaceTradersT listShips env runSpaceTradersT getContracts env >>= print
case ships of runSpaceTradersT getShips env >>= print
Left e -> throwIO e
Right s' -> print $ s'
deinitST env deinitST env

View file

@ -2,8 +2,7 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
module SpaceTraders.APIClient.Client module SpaceTraders.APIClient.Client
( APIError(..) ( APIMessage(..)
, APIMessage(..)
, APIPaginatedResponse , APIPaginatedResponse
, APIResponse , APIResponse
, defaultReq , defaultReq

View file

@ -3,34 +3,28 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
module SpaceTraders.APIClient.Ships module SpaceTraders.APIClient.Ships
( listShips ( myShips
) where ) where
import Control.Exception
--import qualified Data.Text as T
--import qualified Database.SQLite.Simple as S
import Network.HTTP.Simple import Network.HTTP.Simple
import SpaceTraders import SpaceTraders
import SpaceTraders.APIClient.Client import SpaceTraders.APIClient.Client
import SpaceTraders.APIClient.Pagination import SpaceTraders.APIClient.Pagination
--import SpaceTraders.Database.Ships import SpaceTraders.Database.Ships
import SpaceTraders.Model.Ship(Ship) import SpaceTraders.Model.Ship(Ship)
import Debug.Trace
listShips :: SpaceTradersT (APIResponse [Ship]) myShips :: SpaceTradersT (APIResponse [Ship])
listShips = do myShips = do
listShips' Pagination{limit=20, page=1, total=0} listShips' Pagination{limit=20, page=1, total=0}
where where
listShips' :: Pagination -> SpaceTradersT (APIResponse [Ship]) listShips' :: Pagination -> SpaceTradersT (APIResponse [Ship])
listShips' p = do listShips' p = do
resp <- sendPaginated (Just p) $ setRequestPath "/v2/my/ships" resp <- sendPaginated (Just p) $ setRequestPath "/v2/my/ships" :: SpaceTradersT (APIPaginatedResponse [Ship])
case resp of case resp of
Left e -> throw e Left e -> return $ Left e
Right (APIMessage r (Just p')) -> do Right (APIMessage r (Just p')) -> do
liftIO $ traceIO $ show p' mapM_ setShip r
--if (length r == 0 || ((page p') * (limit p') if (limit p' * page p' < total p') then listShips' (nextPage p')
--addShips conn r else Right <$> getShips
--listShips' (nextPage p')
return $ Right r
_ -> undefined _ -> undefined

View file

@ -3,7 +3,7 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
module SpaceTraders.APIClient.Systems module SpaceTraders.APIClient.Systems
( listSystems ( initSystems
) where ) where
import Control.Exception import Control.Exception
@ -15,8 +15,8 @@ import SpaceTraders.APIClient.Pagination
import SpaceTraders.Database.Systems import SpaceTraders.Database.Systems
import SpaceTraders.Model.System(System) import SpaceTraders.Model.System(System)
listSystems :: SpaceTradersT (APIResponse [System]) initSystems :: SpaceTradersT (APIResponse [System])
listSystems = do initSystems = do
s <- getSystems s <- getSystems
listSystems' Pagination{limit=20, page=((length s) `div` 20) + 1, total=0} listSystems' Pagination{limit=20, page=((length s) `div` 20) + 1, total=0}
where where
@ -25,8 +25,8 @@ listSystems = do
resp <- sendPaginated (Just p) $ setRequestPath "/v2/systems" resp <- sendPaginated (Just p) $ setRequestPath "/v2/systems"
case resp of case resp of
Left e -> throw e Left e -> throw e
Right (APIMessage [] _) -> Right <$> getSystems
Right (APIMessage r (Just p')) -> do Right (APIMessage r (Just p')) -> do
addSystems r addSystems r
listSystems' (nextPage p') if (limit p' * page p' < total p') then listSystems' (nextPage p')
else Right <$> getSystems
_ -> undefined _ -> undefined

View file

@ -14,10 +14,12 @@ import System.Directory
import SpaceTraders import SpaceTraders
import SpaceTraders.APIClient.Agent import SpaceTraders.APIClient.Agent
import SpaceTraders.APIClient.Client import SpaceTraders.APIClient.Client
import SpaceTraders.APIClient.Contracts
import SpaceTraders.APIClient.Errors
import SpaceTraders.APIClient.Ships
import SpaceTraders.Database import SpaceTraders.Database
import SpaceTraders.Database.Agents import SpaceTraders.Database.Agents
import SpaceTraders.Database.Contracts import SpaceTraders.Database.Contracts
import SpaceTraders.Database.Ships
import SpaceTraders.Database.Tokens import SpaceTraders.Database.Tokens
deinitST :: Env -> IO () deinitST :: Env -> IO ()
@ -29,11 +31,17 @@ initST = do
conn <- open conn <- open
t <- runReaderT getToken conn `catch` handleNoToken conn t <- runReaderT getToken conn `catch` handleNoToken conn
let env = Env conn (tokenReq t) let env = Env conn (tokenReq t)
ma <- runSpaceTradersT myAgent env ma <- runReaderT getAgent conn -- We compare the agent state in the database
case ma of ma' <- runSpaceTradersT myAgent env -- with the one on the servers
case ma' of
Left (APIResetHappened _) -> wipe conn Left (APIResetHappened _) -> wipe conn
Left e -> throwIO e Left e -> throwIO e
_ -> return $ env Right ma'' -> do
when (ma /= ma'') $ do
_ <- runReaderT myContracts env -- refresh contracts
_ <- runReaderT myShips env -- refresh ships
runReaderT (setAgent ma'') conn -- store the fresh agent state
return $ env
where where
handleNoToken :: S.Connection -> SomeException -> IO T.Text handleNoToken :: S.Connection -> SomeException -> IO T.Text
handleNoToken conn _ = runReaderT registerST (Env conn defaultReq) handleNoToken conn _ = runReaderT registerST (Env conn defaultReq)
@ -45,7 +53,7 @@ registerST = do
Right r' -> do Right r' -> do
addAgent $ agent r' addAgent $ agent r'
addContract $ contract r' addContract $ contract r'
addShip $ ship r' _ <- myShips -- in order to fetch the starting probe that is not advertised in the register message
let t = token r' let t = token r'
addToken t addToken t
return t return t

View file

@ -2,16 +2,31 @@
module SpaceTraders.Database.Agents module SpaceTraders.Database.Agents
( addAgent ( addAgent
, getAgent
, setAgent
) where ) where
import Control.Monad.Reader import Control.Monad.Reader
import Data.Aeson import Data.Aeson
import Data.Maybe
import qualified Database.SQLite.Simple as S import qualified Database.SQLite.Simple as S
import SpaceTraders import SpaceTraders
import SpaceTraders.Model.Agent import SpaceTraders.Model.Agent
import SpaceTraders.Utils
addAgent :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Agent -> m () addAgent :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Agent -> m ()
addAgent agent = do addAgent agent = do
env <- ask env <- ask
liftIO $ S.execute (getConn env) "INSERT INTO agents(data) VALUES (json(?));" (S.Only (encode agent)) liftIO $ S.execute (getConn env) "INSERT INTO agents(data) VALUES (json(?));" (S.Only (encode agent))
getAgent :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => m Agent
getAgent = do
env <- ask
ret <- liftIO $ S.query_ (getConn env) "SELECT data FROM agents;"
return . head . catMaybes $ map (decodeText . head) ret
setAgent :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Agent -> m ()
setAgent agent = do
env <- ask
liftIO $ S.execute (getConn env) "UPDATE agents SET data = json(?);" (S.Only (encode agent))

View file

@ -2,16 +2,39 @@
module SpaceTraders.Database.Contracts module SpaceTraders.Database.Contracts
( addContract ( addContract
, getContracts
, setContract
, updateContract
) where ) where
import Control.Monad.Reader import Control.Monad.Reader
import Data.Aeson import Data.Aeson
import Data.Maybe
import qualified Database.SQLite.Simple as S import qualified Database.SQLite.Simple as S
import SpaceTraders import SpaceTraders
import SpaceTraders.Model.Contract import SpaceTraders.Model.Contract
import SpaceTraders.Utils
addContract :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Contract -> m () addContract :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Contract -> m ()
addContract contract = do addContract contract = do
env <- ask env <- ask
liftIO $ S.execute (getConn env) "INSERT INTO contracts(data) VALUES (json(?));" (S.Only (encode contract)) liftIO $ S.execute (getConn env) "INSERT INTO contracts(data) VALUES (json(?));" (S.Only (encode contract))
getContracts :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => m [Contract]
getContracts = do
env <- ask
ret <- liftIO $ S.query_ (getConn env) "SELECT data FROM contracts;"
return . catMaybes $ map (decodeText . head) ret
setContract :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Contract -> m ()
setContract contract = do
env <- ask
count <- liftIO (S.query (getConn env) "SELECT count(id) FROM contracts WHERE data->>'contractId' = ?;" (S.Only $ contractId contract) :: IO [[Int]])
if count == [[0]] then addContract contract
else updateContract contract
updateContract :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Contract -> m ()
updateContract contract = do
env <- ask
liftIO $ S.execute (getConn env) "UPDATE contracts SET data = json(?) WHERE data->>'contractId' = ?;" (encode contract, contractId contract)

View file

@ -2,16 +2,40 @@
module SpaceTraders.Database.Ships module SpaceTraders.Database.Ships
( addShip ( addShip
, getShips
, setShip
, updateShip
) where ) where
import Control.Monad.Except
import Control.Monad.Reader import Control.Monad.Reader
import Data.Aeson import Data.Aeson
import Data.Maybe
import qualified Database.SQLite.Simple as S import qualified Database.SQLite.Simple as S
import SpaceTraders import SpaceTraders
import SpaceTraders.Model.Ship import SpaceTraders.Model.Ship
import SpaceTraders.Utils
addShip :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Ship -> m () addShip :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Ship -> m ()
addShip ship = do addShip ship = do
env <- ask env <- ask
liftIO $ S.execute (getConn env) "INSERT INTO ships(data) VALUES (json(?));" (S.Only (encode ship)) liftIO $ S.execute (getConn env) "INSERT INTO ships(data) VALUES (json(?));" (S.Only $ encode ship)
getShips :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => m [Ship]
getShips = do
env <- ask
ret <- liftIO $ S.query_ (getConn env) "SELECT data FROM ships;"
return . catMaybes $ map (decodeText . head) ret
setShip :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Ship -> m ()
setShip ship = do
env <- ask
count <- liftIO (S.query (getConn env) "SELECT count(id) FROM ships WHERE data->>'symbol' = ?;" (S.Only $ symbol ship) :: IO [[Int]])
if count == [[0]] then addShip ship
else updateShip ship
updateShip :: (HasDatabaseConn env, MonadIO m, MonadReader env m) => Ship -> m ()
updateShip ship = do
env <- ask
liftIO $ S.execute (getConn env) "UPDATE ships SET data = json(?) WHERE data->>'symbol' = ?;" (encode ship, symbol ship)

View file

@ -16,4 +16,4 @@ data Agent = Agent { accountId :: T.Text
, headquarters :: T.Text , headquarters :: T.Text
, startingFaction :: T.Text , startingFaction :: T.Text
, symbol :: T.Text , symbol :: T.Text
} deriving (FromJSON, Generic, Show, ToJSON) } deriving (Eq, FromJSON, Generic, Show, ToJSON)