marquise-4.0.0: lib/Marquise/IO/Connection.hs
--
-- Copyright © 2013-2014 Anchor Systems, Pty Ltd and Others
--
-- The code in this file, and the program it is a part of, is
-- made available to you by its authors as open source software:
-- you can redistribute it and/or modify it under the terms of
-- the 3-clause BSD licence.
--
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
-- Hide warnings for the deprecated ErrorT transformer:
{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}
module Marquise.IO.Connection
( withConnection,
send,
recv,
SocketState(..),
) where
import qualified Control.Exception as E
import Data.List.NonEmpty (fromList)
import System.ZMQ4 (Dealer (..), Event (..), Poll (..), Socket)
import qualified System.ZMQ4 as Z
import Marquise.Types
import Vaultaire.Types
-- | Wrapped ZMQ4 Socket + broker/IP
data SocketState = SocketState (Socket Dealer) String
-- | Performs operation f through broker.
withConnection :: String -> (SocketState -> IO a) -> IO a
withConnection broker f =
Z.withContext $ \ctx ->
Z.withSocket ctx Dealer $ \s -> do
Z.connect s broker
f (SocketState s broker)
send :: WireFormat request
=> request
-> Origin
-> SocketState
-> IO ()
send request (Origin origin) (SocketState sock _)
= Z.sendMulti sock (fromList [origin, toWire request])
recv :: WireFormat response
=> SocketState
-> IO response
recv (SocketState sock endpoint) = do
poll_result <- Z.poll timeout [Sock sock [In] Nothing]
case poll_result of
[[In]] -> do
resp <- Z.receiveMulti sock
case resp of
[msg] -> either E.throw return $ fromWire msg
[] -> E.throw $ MarquiseException "expected one message, received none"
_ -> E.throw $ MarquiseException "expected one message, received multiple"
[[]] -> do
-- Timeout, reconnect the socket so that we can be sure that a late
-- response on the current connection isn't confused with a
-- response to a later request.
Z.disconnect sock endpoint
Z.connect sock endpoint
E.throw $ MarquiseException "timeout"
_ -> E.throw $ MarquiseException "Marquise.IO.Connection.recv: impossible"
where timeout = 30 * 60 * 1000 -- milliseconds, 30m