summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2017-07-13 14:30:30 -0400
committerjoe <joe@jerkface.net>2017-07-13 14:31:18 -0400
commitb557ee2e70a1c451bb4cff402071f2f808e494df (patch)
treef6bec06474a779f73b59d808a4264d1d3089b051
parent922d1ceac1fd1ed54d855e5877fe4b07dbdbbd70 (diff)
Refactored transactionMethods arguments into ADT.
-rw-r--r--src/Network/QueryResponse.hs95
1 files changed, 72 insertions, 23 deletions
diff --git a/src/Network/QueryResponse.hs b/src/Network/QueryResponse.hs
index f6f2807d..4fc9438c 100644
--- a/src/Network/QueryResponse.hs
+++ b/src/Network/QueryResponse.hs
@@ -1,30 +1,36 @@
1-- | This module can implement any query\/response protocol. It was written 1-- | This module can implement any query\/response protocol. It was written
2-- with Kademlia implementations in mind. 2-- with Kademlia implementations in mind.
3 3
4{-# LANGUAGE CPP #-} 4{-# LANGUAGE CPP #-}
5{-# LANGUAGE RankNTypes #-} 5{-# LANGUAGE GADTs #-}
6{-# LANGUAGE LambdaCase #-} 6{-# LANGUAGE LambdaCase #-}
7{-# LANGUAGE PartialTypeSignatures #-} 7{-# LANGUAGE PartialTypeSignatures #-}
8{-# LANGUAGE GADTs #-} 8{-# LANGUAGE RankNTypes #-}
9{-# LANGUAGE ScopedTypeVariables #-}
9module Network.QueryResponse where 10module Network.QueryResponse where
10 11
11#ifdef THREAD_DEBUG 12#ifdef THREAD_DEBUG
12import Control.Concurrent.Lifted.Instrument 13import Control.Concurrent.Lifted.Instrument
13#else 14#else
14import GHC.Conc (labelThread)
15import Control.Concurrent 15import Control.Concurrent
16import GHC.Conc (labelThread)
16#endif 17#endif
17import Control.Concurrent.STM 18import Control.Concurrent.STM
18import System.Timeout
19import Data.Function
20import Control.Exception 19import Control.Exception
21import Control.Monad 20import Control.Monad
22import qualified Data.ByteString as B 21import qualified Data.ByteString as B
23 ;import Data.ByteString (ByteString) 22 ;import Data.ByteString (ByteString)
23import Data.Function
24import qualified Data.IntMap as IntMap
25 ;import Data.IntMap (IntMap)
26import qualified Data.Map as Map
27 ;import Data.Map (Map)
28import Data.Maybe
29import Data.Typeable
24import Network.Socket 30import Network.Socket
25import Network.Socket.ByteString as B 31import Network.Socket.ByteString as B
26import System.IO.Error 32import System.IO.Error
27import Data.Maybe 33import System.Timeout
28 34
29-- * Using a query\/response 'Client'. 35-- * Using a query\/response 'Client'.
30 36
@@ -184,12 +190,12 @@ layerTransport parse encode tr =
184 190
185 191
186-- | To dipatch responses to our outbound queries, we require three primitives. 192-- | To dipatch responses to our outbound queries, we require three primitives.
187-- See the 'transactionTableMethods' function to create these primitives out of a 193-- See the 'transactionMethods' function to create these primitives out of a
188-- lookup table and a generator for transaction ids. 194-- lookup table and a generator for transaction ids.
189-- 195--
190-- The type variable /d/ is used to represent the current state of the 196-- The type variable /d/ is used to represent the current state of the
191-- transaction generator and the table of pending transactions. 197-- transaction generator and the table of pending transactions.
192data TableMethods d tid x = TableMethods 198data TransactionMethods d tid x = TransactionMethods
193 { 199 {
194 -- | Before a query is sent, this function stores an 'MVar' to which the 200 -- | Before a query is sent, this function stores an 'MVar' to which the
195 -- response will be written too. The returned _tid_ is a transaction id 201 -- response will be written too. The returned _tid_ is a transaction id
@@ -206,19 +212,55 @@ data TableMethods d tid x = TableMethods
206 , dispatchCancel :: tid -> d -> d 212 , dispatchCancel :: tid -> d -> d
207 } 213 }
208 214
209-- | Construct 'TableMethods' methods out of 3 lookup table primitives and a 215-- | The standard lookup table methods for use as input to 'transactionMethods'
216-- in lieu of directly implementing 'TransactionMethods'.
217data TableMethods t tid = TableMethods
218 { -- | Insert a new _tid_ entry into the transaction table.
219 tblInsert :: forall a. tid -> a -> t a -> t a
220 -- | Delete transaction _tid_ from the transaction table.
221 , tblDelete :: forall a. tid -> t a -> t a
222 -- | Lookup the value associated with transaction /tid/.
223 , tblLookup :: forall a. tid -> t a -> Maybe a
224 }
225
226-- | Methods for using 'Data.IntMap.
227intMapMethods :: TableMethods IntMap Int
228intMapMethods = TableMethods IntMap.insert IntMap.delete IntMap.lookup
229
230-- | Methods for using 'Data.Map'
231mapMethods :: Ord tid => TableMethods (Map tid) tid
232mapMethods = TableMethods Map.insert Map.delete Map.lookup
233
234-- | Change the key type for a lookup table implementation.
235--
236-- This can be used with 'intMapMethods' or 'mapMethods' to restrict lookups to
237-- only a part of the generated /tid/ value. This is useful for /tid/ types
238-- that are especially large due their use for other purposes, such as secure
239-- nonces for encryption.
240contramapT f (TableMethods ins del lookup) =
241 TableMethods (\k v t -> ins (f k) v t)
242 (\k t -> del (f k) t)
243 (\k t -> lookup (f k) t)
244
245-- | Since 'Int' may be 32 or 64 bits, this function is provided as a
246-- convenience to test if an integral type, such as 'Data.Word.Word64', can be
247-- safely transformed into an 'Int' for use with 'IntMap'.
248--
249-- Returns 'True' if the proxied type can be losslessly convered to 'Int' using
250-- 'fromIntegral'.
251fitsInInt :: forall word. (Bounded word, Integral word) => Proxy word -> Bool
252fitsInInt Proxy = (original == casted)
253 where
254 original = div maxBound 2 :: word
255 casted = fromIntegral (fromIntegral original :: Int) :: word
256
257-- | Construct 'TransactionMethods' methods out of 3 lookup table primitives and a
210-- function for generating unique transaction ids. 258-- function for generating unique transaction ids.
211transactionTableMethods :: 259transactionMethods ::
212 (forall a. tid -> a -> t a -> t a) 260 TableMethods t tid -- ^ Table methods to lookup values by /tid/.
213 -- ^ Insert a new _tid_ entry into the transaction table. 261 -> (g -> (tid,g)) -- ^ Generate a new unique /tid/ value and update the generator state /g/.
214 -> (forall a. tid -> t a -> t a) 262 -> TransactionMethods (g,t (MVar x)) tid x
215 -- ^ Delete transaction _tid_ from the transaction table. 263transactionMethods (TableMethods insert delete lookup) generate = TransactionMethods
216 -> (forall a. tid -> t a -> Maybe a)
217 -- ^ Lookup the value associated with transaction _tid_.
218 -> (g -> (tid,g))
219 -- ^ Generate a new unique _tid_ value and update the generator state _g_.
220 -> TableMethods (g,t (MVar x)) tid x
221transactionTableMethods insert delete lookup generate = TableMethods
222 { dispatchCancel = \tid (g,t) -> (g, delete tid t) 264 { dispatchCancel = \tid (g,t) -> (g, delete tid t)
223 , dispatchRegister = \v (g,t) -> 265 , dispatchRegister = \v (g,t) ->
224 let (tid,g') = generate g 266 let (tid,g') = generate g
@@ -238,7 +280,7 @@ data DispatchMethods tbl err meth tid addr x ctx = DispatchMethods
238 -- | Lookup the handler for a inbound query. 280 -- | Lookup the handler for a inbound query.
239 , lookupHandler :: meth -> Maybe (MethodHandler err tid addr x ctx) 281 , lookupHandler :: meth -> Maybe (MethodHandler err tid addr x ctx)
240 -- | Methods for handling incomming responses. 282 -- | Methods for handling incomming responses.
241 , tableMethods :: TableMethods tbl tid x 283 , tableMethods :: TransactionMethods tbl tid x
242 } 284 }
243 285
244-- | These methods indicate what should be done upon various conditions. Write 286-- | These methods indicate what should be done upon various conditions. Write
@@ -264,6 +306,13 @@ data ErrorReporter addr x meth tid err = ErrorReporter
264 , reportTimeout :: meth -> tid -> addr -> IO () 306 , reportTimeout :: meth -> tid -> addr -> IO ()
265 } 307 }
266 308
309-- Change the /err/ type for an 'ErrorReporter'.
310contramapE f (ErrorReporter pe mh unk tim)
311 = ErrorReporter (\e -> pe (f e))
312 mh
313 (\addr x e -> unk addr x (f e))
314 tim
315
267-- | Handle a single inbound packet and then invoke the given continuation. 316-- | Handle a single inbound packet and then invoke the given continuation.
268-- The 'forkListener' function is implemeneted by passing this function to 317-- The 'forkListener' function is implemeneted by passing this function to
269-- 'fix' in a forked thread that loops until 'awaitMessage' returns 'Nothing' 318-- 'fix' in a forked thread that loops until 'awaitMessage' returns 'Nothing'