summaryrefslogtreecommitdiff
path: root/src/Network/KRPC/Manager.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/KRPC/Manager.hs')
-rw-r--r--src/Network/KRPC/Manager.hs31
1 files changed, 21 insertions, 10 deletions
diff --git a/src/Network/KRPC/Manager.hs b/src/Network/KRPC/Manager.hs
index 4a3dc93f..0b090e6b 100644
--- a/src/Network/KRPC/Manager.hs
+++ b/src/Network/KRPC/Manager.hs
@@ -37,6 +37,7 @@ import Network.KRPC.Message
37import Network.KRPC.Method 37import Network.KRPC.Method
38import Network.Socket hiding (listen) 38import Network.Socket hiding (listen)
39import Network.Socket.ByteString as BS 39import Network.Socket.ByteString as BS
40import System.Timeout
40 41
41 42
42type KResult = Either KError KResponse 43type KResult = Either KError KResponse
@@ -51,6 +52,7 @@ type Handler h = (MethodName, HandlerBody h)
51 52
52data Manager h = Manager 53data Manager h = Manager
53 { sock :: !Socket 54 { sock :: !Socket
55 , queryTimeout :: !Int -- ^ in seconds
54 , transactionCounter :: {-# UNPACK #-} !TransactionCounter 56 , transactionCounter :: {-# UNPACK #-} !TransactionCounter
55 , pendingCalls :: {-# UNPACK #-} !PendingCalls 57 , pendingCalls :: {-# UNPACK #-} !PendingCalls
56 , handlers :: [Handler h] 58 , handlers :: [Handler h]
@@ -76,12 +78,15 @@ sockAddrFamily (SockAddrUnix _ ) = AF_UNIX
76seedTransaction :: Int 78seedTransaction :: Int
77seedTransaction = 0 79seedTransaction = 0
78 80
81defaultQueryTimeout :: Int
82defaultQueryTimeout = 10
83
79newManager :: SockAddr -> [Handler h] -> IO (Manager h) 84newManager :: SockAddr -> [Handler h] -> IO (Manager h)
80newManager servAddr handlers = do 85newManager servAddr handlers = do
81 sock <- bindServ 86 sock <- bindServ
82 tran <- newIORef seedTransaction 87 tran <- newIORef seedTransaction
83 calls <- newIORef M.empty 88 calls <- newIORef M.empty
84 return $ Manager sock tran calls handlers 89 return $ Manager sock defaultQueryTimeout tran calls handlers
85 where 90 where
86 bindServ = do 91 bindServ = do
87 let family = sockAddrFamily servAddr 92 let family = sockAddrFamily servAddr
@@ -116,6 +121,8 @@ registerQuery cid ref = do
116 atomicModifyIORef' ref $ \ m -> (M.insert cid ares m, ()) 121 atomicModifyIORef' ref $ \ m -> (M.insert cid ares m, ())
117 return ares 122 return ares
118 123
124-- simultaneous M.lookup and M.delete guarantees that we never get two
125-- or more responses to the same query
119unregisterQuery :: CallId -> PendingCalls -> IO (Maybe CallRes) 126unregisterQuery :: CallId -> PendingCalls -> IO (Maybe CallRes)
120unregisterQuery cid ref = do 127unregisterQuery cid ref = do
121 atomicModifyIORef' ref $ swap . 128 atomicModifyIORef' ref $ swap .
@@ -123,13 +130,11 @@ unregisterQuery cid ref = do
123 130
124queryResponse :: BEncode a => CallRes -> IO a 131queryResponse :: BEncode a => CallRes -> IO a
125queryResponse ares = do 132queryResponse ares = do
126 res <- readMVar ares 133 res <- readMVar ares
127 case res of 134 KResponse {..} <- either throwIO pure res
128 Left e -> throwIO e 135 case fromBEncode respVals of
129 Right (KResponse {..}) -> 136 Right r -> pure r
130 case fromBEncode respVals of 137 Left e -> throwIO $ decodeError e respId
131 Left e -> throwIO (KError ProtocolError (BC.pack e) respId)
132 Right a -> return a
133 138
134query :: forall h m a b. (MonadKRPC h m, KRPC a b) => SockAddr -> a -> m b 139query :: forall h m a b. (MonadKRPC h m, KRPC a b) => SockAddr -> a -> m b
135query addr params = do 140query addr params = do
@@ -138,11 +143,17 @@ query addr params = do
138 tid <- genTransactionId transactionCounter 143 tid <- genTransactionId transactionCounter
139 let Method name = method :: Method a b 144 let Method name = method :: Method a b
140 let q = KQuery (toBEncode params) name tid 145 let q = KQuery (toBEncode params) name tid
146
141 ares <- registerQuery (tid, addr) pendingCalls 147 ares <- registerQuery (tid, addr) pendingCalls
142 sendMessage sock addr q 148 sendMessage sock addr q
143 `onException` unregisterQuery (tid, addr) pendingCalls 149 `onException` unregisterQuery (tid, addr) pendingCalls
144 res <- queryResponse ares 150
145 return res 151 mres <- timeout (queryTimeout * 10 ^ 6) $ queryResponse ares
152 case mres of
153 Just res -> return res
154 Nothing -> do
155 unregisterQuery (tid, addr) pendingCalls
156 throwIO $ timeoutExpired tid
146 157
147{----------------------------------------------------------------------- 158{-----------------------------------------------------------------------
148-- Handlers 159-- Handlers