summaryrefslogtreecommitdiff
path: root/src/Network/QueryResponse.hs
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2017-09-30 16:21:51 -0400
committerjoe <joe@jerkface.net>2017-09-30 16:21:51 -0400
commitf1622c7135cdb8725dc1e13c8d1adb49c269cc2d (patch)
treea01eabfed62897822952ff619d65f9d31792fa6d /src/Network/QueryResponse.hs
parenta89c59ed151a41f46355187363957c3c292b60bc (diff)
This makes TransactionMethods into STM actions so that they can be
synced with an auxiliary data structure. I also made Contravariant instances since we depend on contravariant anyway now.
Diffstat (limited to 'src/Network/QueryResponse.hs')
-rw-r--r--src/Network/QueryResponse.hs44
1 files changed, 25 insertions, 19 deletions
diff --git a/src/Network/QueryResponse.hs b/src/Network/QueryResponse.hs
index b7a402b4..8c793a1a 100644
--- a/src/Network/QueryResponse.hs
+++ b/src/Network/QueryResponse.hs
@@ -22,6 +22,7 @@ import Control.Monad
22import qualified Data.ByteString as B 22import qualified Data.ByteString as B
23 ;import Data.ByteString (ByteString) 23 ;import Data.ByteString (ByteString)
24import Data.Function 24import Data.Function
25import Data.Functor.Contravariant
25import qualified Data.IntMap.Strict as IntMap 26import qualified Data.IntMap.Strict as IntMap
26 ;import Data.IntMap.Strict (IntMap) 27 ;import Data.IntMap.Strict (IntMap)
27import qualified Data.Map.Strict as Map 28import qualified Data.Map.Strict as Map
@@ -160,7 +161,7 @@ sendQuery (Client net d err pending whoami _) meth q addr = do
160 mvar <- newEmptyMVar 161 mvar <- newEmptyMVar
161 tid <- atomically $ do 162 tid <- atomically $ do
162 tbl <- readTVar pending 163 tbl <- readTVar pending
163 let (tid, tbl') = dispatchRegister (tableMethods d) mvar tbl 164 (tid, tbl') <- dispatchRegister (tableMethods d) mvar tbl
164 writeTVar pending tbl' 165 writeTVar pending tbl'
165 return tid 166 return tid
166 self <- whoami (Just addr) 167 self <- whoami (Just addr)
@@ -169,7 +170,7 @@ sendQuery (Client net d err pending whoami _) meth q addr = do
169 case mres of 170 case mres of
170 Just x -> return $ Just $ unwrapResponse meth x 171 Just x -> return $ Just $ unwrapResponse meth x
171 Nothing -> do 172 Nothing -> do
172 atomically $ modifyTVar' pending (dispatchCancel (tableMethods d) tid) 173 atomically $ readTVar pending >>= dispatchCancel (tableMethods d) tid >>= writeTVar pending
173 reportTimeout err (method meth) tid addr 174 reportTimeout err (method meth) tid addr
174 return Nothing 175 return Nothing
175 176
@@ -278,15 +279,15 @@ data TransactionMethods d tid x = TransactionMethods
278 -- response will be written too. The returned /tid/ is a transaction id 279 -- response will be written too. The returned /tid/ is a transaction id
279 -- that can be used to forget the 'MVar' if the remote peer is not 280 -- that can be used to forget the 'MVar' if the remote peer is not
280 -- responding. 281 -- responding.
281 dispatchRegister :: MVar x -> d -> (tid, d) 282 dispatchRegister :: MVar x -> d -> STM (tid, d)
282 -- | This method is invoked when an incomming packet /x/ indicates it is 283 -- | This method is invoked when an incomming packet /x/ indicates it is
283 -- a response to the transaction with id /tid/. The returned IO action 284 -- a response to the transaction with id /tid/. The returned IO action
284 -- is will write the packet to the correct 'MVar' thus completing the 285 -- is will write the packet to the correct 'MVar' thus completing the
285 -- dispatch. 286 -- dispatch.
286 , dispatchResponse :: tid -> x -> d -> (d, IO ()) 287 , dispatchResponse :: tid -> x -> d -> STM (d, IO ())
287 -- | When a timeout interval elapses, this method is called to remove the 288 -- | When a timeout interval elapses, this method is called to remove the
288 -- transaction from the table. 289 -- transaction from the table.
289 , dispatchCancel :: tid -> d -> d 290 , dispatchCancel :: tid -> d -> STM d
290 } 291 }
291 292
292-- | The standard lookup table methods for use as input to 'transactionMethods' 293-- | The standard lookup table methods for use as input to 'transactionMethods'
@@ -314,10 +315,12 @@ mapMethods = TableMethods Map.insert Map.delete Map.lookup
314-- only a part of the generated /tid/ value. This is useful for /tid/ types 315-- only a part of the generated /tid/ value. This is useful for /tid/ types
315-- that are especially large due their use for other purposes, such as secure 316-- that are especially large due their use for other purposes, such as secure
316-- nonces for encryption. 317-- nonces for encryption.
317contramapT f (TableMethods ins del lookup) = 318instance Contravariant (TableMethods t) where
318 TableMethods (\k v t -> ins (f k) v t) 319 -- contramap :: (tid -> t1) -> TableMethods t t1 -> TableMethods t tid
319 (\k t -> del (f k) t) 320 contramap f (TableMethods ins del lookup) =
320 (\k t -> lookup (f k) t) 321 TableMethods (\k v t -> ins (f k) v t)
322 (\k t -> del (f k) t)
323 (\k t -> lookup (f k) t)
321 324
322-- | Since 'Int' may be 32 or 64 bits, this function is provided as a 325-- | Since 'Int' may be 32 or 64 bits, this function is provided as a
323-- convenience to test if an integral type, such as 'Data.Word.Word64', can be 326-- convenience to test if an integral type, such as 'Data.Word.Word64', can be
@@ -338,16 +341,16 @@ transactionMethods ::
338 -> (g -> (tid,g)) -- ^ Generate a new unique /tid/ value and update the generator state /g/. 341 -> (g -> (tid,g)) -- ^ Generate a new unique /tid/ value and update the generator state /g/.
339 -> TransactionMethods (g,t (MVar x)) tid x 342 -> TransactionMethods (g,t (MVar x)) tid x
340transactionMethods (TableMethods insert delete lookup) generate = TransactionMethods 343transactionMethods (TableMethods insert delete lookup) generate = TransactionMethods
341 { dispatchCancel = \tid (g,t) -> (g, delete tid t) 344 { dispatchCancel = \tid (g,t) -> return (g, delete tid t)
342 , dispatchRegister = \v (g,t) -> 345 , dispatchRegister = \v (g,t) ->
343 let (tid,g') = generate g 346 let (tid,g') = generate g
344 t' = insert tid v t 347 t' = insert tid v t
345 in ( tid, (g',t') ) 348 in return ( tid, (g',t') )
346 , dispatchResponse = \tid x (g,t) -> 349 , dispatchResponse = \tid x (g,t) ->
347 case lookup tid t of 350 case lookup tid t of
348 Just v -> let t' = delete tid t 351 Just v -> let t' = delete tid t
349 in ((g,t'),void $ tryPutMVar v x) 352 in return ((g,t'),void $ tryPutMVar v x)
350 Nothing -> ((g,t), return ()) 353 Nothing -> return ((g,t), return ())
351 } 354 }
352 355
353-- | A set of methods neccessary for dispatching incomming packets. 356-- | A set of methods neccessary for dispatching incomming packets.
@@ -402,11 +405,13 @@ printErrors h = ErrorReporter
402 } 405 }
403 406
404-- Change the /err/ type for an 'ErrorReporter'. 407-- Change the /err/ type for an 'ErrorReporter'.
405contramapE f (ErrorReporter pe mh unk tim) 408instance Contravariant (ErrorReporter addr x meth tid) where
406 = ErrorReporter (\e -> pe (f e)) 409 -- contramap :: (t5 -> t4) -> ErrorReporter t3 t2 t1 t t4 -> ErrorReporter t3 t2 t1 t t5
407 mh 410 contramap f (ErrorReporter pe mh unk tim)
408 (\addr x e -> unk addr x (f e)) 411 = ErrorReporter (\e -> pe (f e))
409 tim 412 mh
413 (\addr x e -> unk addr x (f e))
414 tim
410 415
411-- | Handle a single inbound packet and then invoke the given continuation. 416-- | Handle a single inbound packet and then invoke the given continuation.
412-- The 'forkListener' function is implemeneted by passing this function to 417-- The 'forkListener' function is implemeneted by passing this function to
@@ -436,7 +441,7 @@ handleMessage (Client net d err pending whoami responseID) addr plain = do
436 IsResponse tid -> do 441 IsResponse tid -> do
437 action <- atomically $ do 442 action <- atomically $ do
438 ts0 <- readTVar pending 443 ts0 <- readTVar pending
439 let (ts, action) = dispatchResponse (tableMethods d) tid plain ts0 444 (ts, action) <- dispatchResponse (tableMethods d) tid plain ts0
440 writeTVar pending ts 445 writeTVar pending ts
441 return action 446 return action
442 action 447 action
@@ -458,6 +463,7 @@ sockAddrFamily (SockAddrCan _ ) = AF_CAN
458-- | Packets with an empty payload may trigger eof exception. 463-- | Packets with an empty payload may trigger eof exception.
459-- 'udpTransport' uses this function to avoid throwing in that 464-- 'udpTransport' uses this function to avoid throwing in that
460-- case. 465-- case.
466ignoreEOF :: a -> IOError -> IO a
461ignoreEOF def e | isEOFError e = pure def 467ignoreEOF def e | isEOFError e = pure def
462 | otherwise = throwIO e 468 | otherwise = throwIO e
463 469