|
|
|
@ -15,9 +15,11 @@ import Control.Concurrent.BoundedChan |
|
|
|
import Control.Concurrent.MVar |
|
|
|
import Control.Concurrent.MVar |
|
|
|
import Control.Exception |
|
|
|
import Control.Exception |
|
|
|
import Control.Monad |
|
|
|
import Control.Monad |
|
|
|
|
|
|
|
import Control.Monad.Loops |
|
|
|
import Data.Aeson |
|
|
|
import Data.Aeson |
|
|
|
import Data.Int |
|
|
|
import Data.Int |
|
|
|
import Data.IORef |
|
|
|
import Data.IORef |
|
|
|
|
|
|
|
import Data.Maybe |
|
|
|
import Data.List.NonEmpty |
|
|
|
import Data.List.NonEmpty |
|
|
|
import qualified Data.Text as T |
|
|
|
import qualified Data.Text as T |
|
|
|
import qualified Data.ByteString.Lazy as BL |
|
|
|
import qualified Data.ByteString.Lazy as BL |
|
|
|
@ -28,6 +30,7 @@ import System.Log.Logger |
|
|
|
data BrokerClientHandle = BrokerClientHandle { |
|
|
|
data BrokerClientHandle = BrokerClientHandle { |
|
|
|
tid :: ThreadId, |
|
|
|
tid :: ThreadId, |
|
|
|
completionMvar :: MVar (), |
|
|
|
completionMvar :: MVar (), |
|
|
|
|
|
|
|
killMvar :: MVar (), |
|
|
|
submitOrder :: Order -> IO (Either T.Text OrderId), |
|
|
|
submitOrder :: Order -> IO (Either T.Text OrderId), |
|
|
|
cancelOrder :: OrderId -> IO (Either T.Text ()), |
|
|
|
cancelOrder :: OrderId -> IO (Either T.Text ()), |
|
|
|
getNotifications :: IO (Either T.Text [Notification]), |
|
|
|
getNotifications :: IO (Either T.Text [Notification]), |
|
|
|
@ -35,32 +38,41 @@ data BrokerClientHandle = BrokerClientHandle { |
|
|
|
respVar :: MVar BrokerServerResponse |
|
|
|
respVar :: MVar BrokerServerResponse |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
brokerClientThread ctx ep cmd resp comp = do |
|
|
|
brokerClientThread :: Context -> T.Text -> MVar BrokerServerRequest -> MVar BrokerServerResponse -> MVar () -> MVar () -> IO () |
|
|
|
|
|
|
|
brokerClientThread ctx ep cmd resp comp killMv = finally brokerClientThread' cleanup |
|
|
|
|
|
|
|
where |
|
|
|
|
|
|
|
cleanup = putMVar comp () |
|
|
|
|
|
|
|
brokerClientThread' = whileM_ (isNothing <$> tryReadMVar killMv) $ do |
|
|
|
sock <- socket ctx Req |
|
|
|
sock <- socket ctx Req |
|
|
|
connect sock $ T.unpack ep |
|
|
|
connect sock $ T.unpack ep |
|
|
|
finally (brokerClientThread' sock) (cleanup sock) |
|
|
|
setReceiveTimeout (restrict 1000) sock |
|
|
|
where |
|
|
|
finally (brokerClientThread'' sock) (close sock) |
|
|
|
cleanup sock = close sock >> putMVar comp () |
|
|
|
brokerClientThread'' sock = whileM_ (isNothing <$> tryReadMVar killMv) $ do |
|
|
|
brokerClientThread' sock = do |
|
|
|
|
|
|
|
forever $ do |
|
|
|
|
|
|
|
request <- takeMVar cmd |
|
|
|
request <- takeMVar cmd |
|
|
|
send sock [] (BL.toStrict $ encode request) |
|
|
|
send sock [] (BL.toStrict $ encode request) |
|
|
|
|
|
|
|
events <- poll 1000 [Sock sock [In] Nothing] |
|
|
|
|
|
|
|
if (not . null) events |
|
|
|
|
|
|
|
then do |
|
|
|
maybeResponse <- decode . BL.fromStrict <$> receive sock |
|
|
|
maybeResponse <- decode . BL.fromStrict <$> receive sock |
|
|
|
case maybeResponse of |
|
|
|
case maybeResponse of |
|
|
|
Just response -> putMVar resp response |
|
|
|
Just response -> putMVar resp response |
|
|
|
Nothing -> putMVar resp (ResponseError "Unable to decode response") |
|
|
|
Nothing -> putMVar resp (ResponseError "Unable to decode response") |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
putMVar resp (ResponseError "Response timeout") |
|
|
|
|
|
|
|
|
|
|
|
startBrokerClient :: Context -> T.Text -> IO BrokerClientHandle |
|
|
|
startBrokerClient :: Context -> T.Text -> IO BrokerClientHandle |
|
|
|
startBrokerClient ctx endpoint = do |
|
|
|
startBrokerClient ctx endpoint = do |
|
|
|
idCounter <- newIORef 1 |
|
|
|
idCounter <- newIORef 1 |
|
|
|
compMv <- newEmptyMVar |
|
|
|
compMv <- newEmptyMVar |
|
|
|
|
|
|
|
killMv <- newEmptyMVar |
|
|
|
cmdVar <- newEmptyMVar :: IO (MVar BrokerServerRequest) |
|
|
|
cmdVar <- newEmptyMVar :: IO (MVar BrokerServerRequest) |
|
|
|
respVar <- newEmptyMVar :: IO (MVar BrokerServerResponse) |
|
|
|
respVar <- newEmptyMVar :: IO (MVar BrokerServerResponse) |
|
|
|
tid <- forkIO (brokerClientThread ctx endpoint cmdVar respVar compMv) |
|
|
|
tid <- forkIO (brokerClientThread ctx endpoint cmdVar respVar compMv killMv) |
|
|
|
|
|
|
|
|
|
|
|
return BrokerClientHandle { |
|
|
|
return BrokerClientHandle { |
|
|
|
tid = tid, |
|
|
|
tid = tid, |
|
|
|
completionMvar = compMv, |
|
|
|
completionMvar = compMv, |
|
|
|
|
|
|
|
killMvar = killMv, |
|
|
|
submitOrder = bcSubmitOrder idCounter cmdVar respVar, |
|
|
|
submitOrder = bcSubmitOrder idCounter cmdVar respVar, |
|
|
|
cancelOrder = bcCancelOrder idCounter cmdVar respVar, |
|
|
|
cancelOrder = bcCancelOrder idCounter cmdVar respVar, |
|
|
|
getNotifications = bcGetNotifications idCounter cmdVar respVar, |
|
|
|
getNotifications = bcGetNotifications idCounter cmdVar respVar, |
|
|
|
@ -69,7 +81,7 @@ startBrokerClient ctx endpoint = do |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
stopBrokerClient :: BrokerClientHandle -> IO () |
|
|
|
stopBrokerClient :: BrokerClientHandle -> IO () |
|
|
|
stopBrokerClient handle = yield >> killThread (tid handle) >> readMVar (completionMvar handle) |
|
|
|
stopBrokerClient handle = putMVar (killMvar handle) () >> yield >> killThread (tid handle) >> readMVar (completionMvar handle) |
|
|
|
|
|
|
|
|
|
|
|
nextId cnt = atomicModifyIORef' cnt (\v -> (v + 1, v)) |
|
|
|
nextId cnt = atomicModifyIORef' cnt (\v -> (v + 1, v)) |
|
|
|
|
|
|
|
|
|
|
|
|