summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bench/Main.hs2
-rw-r--r--krpc.cabal1
-rw-r--r--src/Network/KRPC.hs3
-rw-r--r--src/Network/KRPC/Manager.hs60
-rw-r--r--tests/Network/KRPCSpec.hs7
5 files changed, 57 insertions, 16 deletions
diff --git a/bench/Main.hs b/bench/Main.hs
index 13727ff9..8466f4a3 100644
--- a/bench/Main.hs
+++ b/bench/Main.hs
@@ -22,7 +22,7 @@ addr :: SockAddr
22addr = SockAddrInet 6000 (256 * 256 * 256 + 127) 22addr = SockAddrInet 6000 (256 * 256 * 256 + 127)
23 23
24main :: IO () 24main :: IO ()
25main = withManager addr [echo] $ \ m -> (`runReaderT` m) $ do 25main = withManager def addr [echo] $ \ m -> (`runReaderT` m) $ do
26 listen 26 listen
27 liftIO $ defaultMain (benchmarks m) 27 liftIO $ defaultMain (benchmarks m)
28 where 28 where
diff --git a/krpc.cabal b/krpc.cabal
index b5004026..be19775f 100644
--- a/krpc.cabal
+++ b/krpc.cabal
@@ -46,6 +46,7 @@ library
46 build-depends: base == 4.* 46 build-depends: base == 4.*
47 , bytestring >= 0.10 47 , bytestring >= 0.10
48 , text >= 0.11 48 , text >= 0.11
49 , data-default-class
49 , lifted-base >= 0.1.1 50 , lifted-base >= 0.1.1
50 , transformers >= 0.2 51 , transformers >= 0.2
51 , mtl 52 , mtl
diff --git a/src/Network/KRPC.hs b/src/Network/KRPC.hs
index a1767161..7c02702c 100644
--- a/src/Network/KRPC.hs
+++ b/src/Network/KRPC.hs
@@ -62,6 +62,8 @@ module Network.KRPC
62 62
63 -- * Manager 63 -- * Manager
64 , MonadKRPC (..) 64 , MonadKRPC (..)
65 , Options (..)
66 , def
65 , Manager 67 , Manager
66 , newManager 68 , newManager
67 , closeManager 69 , closeManager
@@ -76,6 +78,7 @@ module Network.KRPC
76 , SockAddr (..) 78 , SockAddr (..)
77 ) where 79 ) where
78 80
81import Data.Default.Class
79import Network.KRPC.Message 82import Network.KRPC.Message
80import Network.KRPC.Method 83import Network.KRPC.Method
81import Network.KRPC.Manager 84import Network.KRPC.Manager
diff --git a/src/Network/KRPC/Manager.hs b/src/Network/KRPC/Manager.hs
index 4d1cfb69..7edcf72d 100644
--- a/src/Network/KRPC/Manager.hs
+++ b/src/Network/KRPC/Manager.hs
@@ -18,6 +18,7 @@
18module Network.KRPC.Manager 18module Network.KRPC.Manager
19 ( -- * Manager 19 ( -- * Manager
20 MonadKRPC (..) 20 MonadKRPC (..)
21 , Options (..)
21 , Manager 22 , Manager
22 , newManager 23 , newManager
23 , closeManager 24 , closeManager
@@ -43,6 +44,7 @@ import Data.BEncode as BE
43import Data.ByteString as BS 44import Data.ByteString as BS
44import Data.ByteString.Char8 as BC 45import Data.ByteString.Char8 as BC
45import Data.ByteString.Lazy as BL 46import Data.ByteString.Lazy as BL
47import Data.Default.Class
46import Data.IORef 48import Data.IORef
47import Data.List as L 49import Data.List as L
48import Data.Map as M 50import Data.Map as M
@@ -58,6 +60,41 @@ import System.IO.Error
58import System.Timeout 60import System.Timeout
59 61
60 62
63{-----------------------------------------------------------------------
64-- Options
65-----------------------------------------------------------------------}
66
67-- | RPC manager options.
68data Options = Options
69 { -- | Initial 'TransactionId' incremented with each 'query';
70 optSeedTransaction :: Int
71
72 -- | Time to wait for response from remote node, in seconds.
73 , optQueryTimeout :: Int
74 } deriving (Show, Eq)
75
76defaultSeedTransaction :: Int
77defaultSeedTransaction = 0
78
79defaultQueryTimeout :: Int
80defaultQueryTimeout = 120
81
82-- | Permissive defaults.
83instance Default Options where
84 def = Options
85 { optSeedTransaction = defaultSeedTransaction
86 , optQueryTimeout = defaultQueryTimeout
87 }
88
89validateOptions :: Options -> IO ()
90validateOptions Options {..}
91 | optQueryTimeout < 1 = throwIO (userError "non-positive query timeout")
92 | otherwise = return ()
93
94{-----------------------------------------------------------------------
95-- Options
96-----------------------------------------------------------------------}
97
61type KResult = Either KError KResponse 98type KResult = Either KError KResponse
62 99
63type TransactionCounter = IORef Int 100type TransactionCounter = IORef Int
@@ -108,23 +145,19 @@ sockAddrFamily (SockAddrInet _ _ ) = AF_INET
108sockAddrFamily (SockAddrInet6 _ _ _ _) = AF_INET6 145sockAddrFamily (SockAddrInet6 _ _ _ _) = AF_INET6
109sockAddrFamily (SockAddrUnix _ ) = AF_UNIX 146sockAddrFamily (SockAddrUnix _ ) = AF_UNIX
110 147
111seedTransaction :: Int
112seedTransaction = 0
113
114defaultQueryTimeout :: Int
115defaultQueryTimeout = 120
116
117-- | Bind socket to the specified address. To enable query handling 148-- | Bind socket to the specified address. To enable query handling
118-- run 'listen'. 149-- run 'listen'.
119newManager :: SockAddr -- ^ address to listen on; 150newManager :: Options -- ^ various protocol options;
151 -> SockAddr -- ^ address to listen on;
120 -> [Handler h] -- ^ handlers to run on incoming queries. 152 -> [Handler h] -- ^ handlers to run on incoming queries.
121 -> IO (Manager h) -- ^ new manager. 153 -> IO (Manager h) -- ^ new rpc manager.
122newManager servAddr handlers = do 154newManager opts @ Options {..} servAddr handlers = do
155 validateOptions opts
123 sock <- bindServ 156 sock <- bindServ
124 tref <- newEmptyMVar 157 tref <- newEmptyMVar
125 tran <- newIORef seedTransaction 158 tran <- newIORef optSeedTransaction
126 calls <- newIORef M.empty 159 calls <- newIORef M.empty
127 return $ Manager sock defaultQueryTimeout tref tran calls handlers 160 return $ Manager sock optQueryTimeout tref tran calls handlers
128 where 161 where
129 bindServ = do 162 bindServ = do
130 let family = sockAddrFamily servAddr 163 let family = sockAddrFamily servAddr
@@ -143,8 +176,9 @@ closeManager Manager {..} = do
143 176
144-- | Normally you should use Control.Monad.Trans.Resource.allocate 177-- | Normally you should use Control.Monad.Trans.Resource.allocate
145-- function. 178-- function.
146withManager :: SockAddr -> [Handler h] -> (Manager h -> IO a) -> IO a 179withManager :: Options -> SockAddr -> [Handler h]
147withManager addr hs = bracket (newManager addr hs) closeManager 180 -> (Manager h -> IO a) -> IO a
181withManager opts addr hs = bracket (newManager opts addr hs) closeManager
148 182
149{----------------------------------------------------------------------- 183{-----------------------------------------------------------------------
150-- Logging 184-- Logging
diff --git a/tests/Network/KRPCSpec.hs b/tests/Network/KRPCSpec.hs
index 7f5b2794..e73b1ec0 100644
--- a/tests/Network/KRPCSpec.hs
+++ b/tests/Network/KRPCSpec.hs
@@ -20,18 +20,21 @@ handlers =
20instance MonadLogger IO where 20instance MonadLogger IO where
21 monadLoggerLog _ _ _ _ = return () 21 monadLoggerLog _ _ _ _ = return ()
22 22
23opts :: Options
24opts = def { optQueryTimeout = 1 }
25
23spec :: Spec 26spec :: Spec
24spec = do 27spec = do
25 describe "query" $ do 28 describe "query" $ do
26 it "run handlers" $ do 29 it "run handlers" $ do
27 let int = 0xabcd :: Int 30 let int = 0xabcd :: Int
28 (withManager servAddr handlers $ runReaderT $ do 31 (withManager opts servAddr handlers $ runReaderT $ do
29 listen 32 listen
30 query servAddr (Echo int)) 33 query servAddr (Echo int))
31 `shouldReturn` Echo int 34 `shouldReturn` Echo int
32 35
33 it "throw timeout exception" $ do 36 it "throw timeout exception" $ do
34 (withManager servAddr handlers $ runReaderT $ do 37 (withManager opts servAddr handlers $ runReaderT $ do
35 query servAddr (Echo (0xabcd :: Int)) 38 query servAddr (Echo (0xabcd :: Int))
36 ) 39 )
37 `shouldThrow` (== KError GenericError "timeout expired" "0") 40 `shouldThrow` (== KError GenericError "timeout expired" "0")