summaryrefslogtreecommitdiff
path: root/src/Network/KRPC
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2017-06-05 03:21:25 -0400
committerjoe <joe@jerkface.net>2017-06-05 03:31:23 -0400
commit24df9a12a9240aaed8741d60e4b0b9cbf59a9fd9 (patch)
tree04791746bb576c40851f441ebc851c9d0d8da777 /src/Network/KRPC
parent219d72ebde4bab5a516a86608dcb3aede75c1611 (diff)
WIP: Adapting DHT to Tox network (part 2).
Diffstat (limited to 'src/Network/KRPC')
-rw-r--r--src/Network/KRPC/Manager.hs43
-rw-r--r--src/Network/KRPC/Message.hs51
-rw-r--r--src/Network/KRPC/Method.hs15
3 files changed, 59 insertions, 50 deletions
diff --git a/src/Network/KRPC/Manager.hs b/src/Network/KRPC/Manager.hs
index e7f0563b..b1e93101 100644
--- a/src/Network/KRPC/Manager.hs
+++ b/src/Network/KRPC/Manager.hs
@@ -76,6 +76,7 @@ import Data.Text as T
76import Data.Text.Encoding as T 76import Data.Text.Encoding as T
77import Data.Tuple 77import Data.Tuple
78import Data.Typeable 78import Data.Typeable
79import Network.RPC
79import Network.KRPC.Message 80import Network.KRPC.Message
80import Network.KRPC.Method 81import Network.KRPC.Method
81import Network.Socket hiding (listen) 82import Network.Socket hiding (listen)
@@ -136,11 +137,11 @@ type CallId = (TransactionId, SockAddr)
136type CallRes = MVar (KQueryArgs, KResult) -- (raw response, decoded response) 137type CallRes = MVar (KQueryArgs, KResult) -- (raw response, decoded response)
137type PendingCalls = IORef (Map CallId CallRes) 138type PendingCalls = IORef (Map CallId CallRes)
138 139
139type HandlerBody h = SockAddr -> KQueryArgs -> h (Either String KQueryArgs) 140type HandlerBody h msg v = SockAddr -> msg v -> h (Either String v)
140 141
141-- | Handler is a function which will be invoked then some /remote/ 142-- | Handler is a function which will be invoked then some /remote/
142-- node querying /this/ node. 143-- node querying /this/ node.
143type Handler h = (MethodName, HandlerBody h) 144type Handler h msg v = (MethodName, HandlerBody h msg v)
144 145
145-- | Keep track pending queries made by /this/ node and handle queries 146-- | Keep track pending queries made by /this/ node and handle queries
146-- made by /remote/ nodes. 147-- made by /remote/ nodes.
@@ -150,7 +151,7 @@ data Manager h = Manager
150 , listenerThread :: !(MVar ThreadId) 151 , listenerThread :: !(MVar ThreadId)
151 , transactionCounter :: {-# UNPACK #-} !TransactionCounter 152 , transactionCounter :: {-# UNPACK #-} !TransactionCounter
152 , pendingCalls :: {-# UNPACK #-} !PendingCalls 153 , pendingCalls :: {-# UNPACK #-} !PendingCalls
153 , handlers :: [Handler h] 154 , handlers :: [Handler h KMessageOf BValue]
154 } 155 }
155 156
156-- | A monad which can perform or handle queries. 157-- | A monad which can perform or handle queries.
@@ -182,10 +183,10 @@ sockAddrFamily (SockAddrCan _ ) = AF_CAN
182 183
183-- | Bind socket to the specified address. To enable query handling 184-- | Bind socket to the specified address. To enable query handling
184-- run 'listen'. 185-- run 'listen'.
185newManager :: Options -- ^ various protocol options; 186newManager :: Options -- ^ various protocol options;
186 -> SockAddr -- ^ address to listen on; 187 -> SockAddr -- ^ address to listen on;
187 -> [Handler h] -- ^ handlers to run on incoming queries. 188 -> [Handler h KMessageOf BValue] -- ^ handlers to run on incoming queries.
188 -> IO (Manager h) -- ^ new rpc manager. 189 -> IO (Manager h) -- ^ new rpc manager.
189newManager opts @ Options {..} servAddr handlers = do 190newManager opts @ Options {..} servAddr handlers = do
190 validateOptions opts 191 validateOptions opts
191 sock <- bindServ 192 sock <- bindServ
@@ -217,7 +218,7 @@ isActive Manager {..} = liftIO $ isBound sock
217 218
218-- | Normally you should use Control.Monad.Trans.Resource.allocate 219-- | Normally you should use Control.Monad.Trans.Resource.allocate
219-- function. 220-- function.
220withManager :: Options -> SockAddr -> [Handler h] 221withManager :: Options -> SockAddr -> [Handler h KMessageOf BValue]
221 -> (Manager h -> IO a) -> IO a 222 -> (Manager h -> IO a) -> IO a
222withManager opts addr hs = bracket (newManager opts addr hs) closeManager 223withManager opts addr hs = bracket (newManager opts addr hs) closeManager
223 224
@@ -408,35 +409,25 @@ prettyQF e = T.encodeUtf8 $ "handler fail while performing query: "
408-- If the handler make some 'query' normally it /should/ handle 409-- If the handler make some 'query' normally it /should/ handle
409-- corresponding 'QueryFailure's. 410-- corresponding 'QueryFailure's.
410-- 411--
411handler :: forall h a b. (KRPC a b, Monad h) 412handler :: forall h a b msg. (KRPC a b, Applicative h, Functor msg)
412 => (SockAddr -> a -> h b) -> Handler h 413 => Messaging msg TransactionId (Envelope a b) -> (SockAddr -> a -> h b) -> Handler h msg (Envelope a b)
413handler body = (name, wrapper) 414handler msging body = (name, wrapper)
414 where 415 where
415 Method name = method :: Method a b 416 Method name = method :: Method a b
416 wrapper addr args = 417 wrapper addr args =
417#ifdef VERSION_bencoding 418 case unseal $ messagePayload msging args of
418 case fromBEncode args of 419 Left e -> pure $ Left e
419#else 420 Right a -> Right . seal <$> body addr a
420 case S.decode args of
421#endif
422 Left e -> return $ Left e
423 Right a -> do
424 r <- body addr a
425#ifdef VERSION_bencoding
426 return $ Right $ toBEncode r
427#else
428 return $ Right $ S.encode r
429#endif
430 421
431runHandler :: MonadKRPC h m 422runHandler :: MonadKRPC h m
432 => HandlerBody h -> SockAddr -> KQuery -> m KResult 423 => HandlerBody h KMessageOf BValue -> SockAddr -> KQuery -> m KResult
433runHandler h addr m = Lifted.catches wrapper failbacks 424runHandler h addr m = Lifted.catches wrapper failbacks
434 where 425 where
435 signature = querySignature (queryMethod m) (queryId m) addr 426 signature = querySignature (queryMethod m) (queryId m) addr
436 427
437 wrapper = do 428 wrapper = do
438 $(logDebugS) "handler.quered" signature 429 $(logDebugS) "handler.quered" signature
439 result <- liftHandler (h addr (queryArgs m)) 430 result <- liftHandler (h addr (Q m))
440 431
441 case result of 432 case result of
442 Left msg -> do 433 Left msg -> do
diff --git a/src/Network/KRPC/Message.hs b/src/Network/KRPC/Message.hs
index d48fa8ac..19f9fc9e 100644
--- a/src/Network/KRPC/Message.hs
+++ b/src/Network/KRPC/Message.hs
@@ -13,14 +13,16 @@
13-- See <http://www.bittorrent.org/beps/bep_0005.html#krpc-protocol> 13-- See <http://www.bittorrent.org/beps/bep_0005.html#krpc-protocol>
14-- 14--
15{-# LANGUAGE CPP #-} 15{-# LANGUAGE CPP #-}
16{-# LANGUAGE OverloadedStrings #-} 16{-# LANGUAGE DefaultSignatures #-}
17{-# LANGUAGE DeriveDataTypeable #-}
18{-# LANGUAGE DeriveFunctor #-}
19{-# LANGUAGE DeriveTraversable #-}
17{-# LANGUAGE FlexibleContexts #-} 20{-# LANGUAGE FlexibleContexts #-}
18{-# LANGUAGE FlexibleInstances #-} 21{-# LANGUAGE FlexibleInstances #-}
19{-# LANGUAGE TypeSynonymInstances #-}
20{-# LANGUAGE MultiParamTypeClasses #-}
21{-# LANGUAGE FunctionalDependencies #-} 22{-# LANGUAGE FunctionalDependencies #-}
22{-# LANGUAGE DefaultSignatures #-} 23{-# LANGUAGE MultiParamTypeClasses #-}
23{-# LANGUAGE DeriveDataTypeable #-} 24{-# LANGUAGE OverloadedStrings #-}
25{-# LANGUAGE TypeSynonymInstances #-}
24module Network.KRPC.Message 26module Network.KRPC.Message
25 ( -- * Transaction 27 ( -- * Transaction
26 TransactionId 28 TransactionId
@@ -32,7 +34,8 @@ module Network.KRPC.Message
32 , unknownMessage 34 , unknownMessage
33 35
34 -- * Query 36 -- * Query
35 , KQuery(..) 37 , KQueryOf(..)
38 , KQuery
36#ifndef VERSION_bencoding 39#ifndef VERSION_bencoding
37 , queryArgs 40 , queryArgs
38 , queryMethod 41 , queryMethod
@@ -41,11 +44,13 @@ module Network.KRPC.Message
41 , MethodName 44 , MethodName
42 45
43 -- * Response 46 -- * Response
44 , KResponse(..) 47 , KResponseOf(..)
48 , KResponse
45 , ReflectedIP(..) 49 , ReflectedIP(..)
46 50
47 -- * Message 51 -- * Message
48 , KMessage (..) 52 , KMessageOf (..)
53 , KMessage
49 , KQueryArgs 54 , KQueryArgs
50 55
51 ) where 56 ) where
@@ -208,11 +213,13 @@ type KQueryArgs = ByteString -- msgPayload
208-- callee and pass arguments in. Therefore query may be only sent from 213-- callee and pass arguments in. Therefore query may be only sent from
209-- client to server but not in the opposite direction. 214-- client to server but not in the opposite direction.
210-- 215--
211data KQuery = KQuery 216data KQueryOf a = KQuery
212 { queryArgs :: !KQueryArgs -- ^ values to be passed to method; 217 { queryArgs :: !a -- ^ values to be passed to method;
213 , queryMethod :: !MethodName -- ^ method to call; 218 , queryMethod :: !MethodName -- ^ method to call;
214 , queryId :: !TransactionId -- ^ one-time query token. 219 , queryId :: !TransactionId -- ^ one-time query token.
215 } deriving ( Show, Eq, Ord, Typeable, Read ) 220 } deriving ( Show, Eq, Ord, Typeable, Read, Functor, Foldable, Traversable )
221
222type KQuery = KQueryOf KQueryArgs
216 223
217-- | Queries, or KRPC message dictionaries with a \"y\" value of 224-- | Queries, or KRPC message dictionaries with a \"y\" value of
218-- \"q\", contain two additional keys; \"q\" and \"a\". Key \"q\" has 225-- \"q\", contain two additional keys; \"q\" and \"a\". Key \"q\" has
@@ -223,7 +230,7 @@ data KQuery = KQuery
223-- 230--
224-- > { "t" : "aa", "y" : "q", "q" : "ping", "a" : { "msg" : "hi!" } } 231-- > { "t" : "aa", "y" : "q", "q" : "ping", "a" : { "msg" : "hi!" } }
225-- 232--
226instance BEncode KQuery where 233instance (Typeable a, BEncode a) => BEncode (KQueryOf a) where
227 toBEncode KQuery {..} = toDict $ 234 toBEncode KQuery {..} = toDict $
228 "a" .=! queryArgs 235 "a" .=! queryArgs
229 .: "q" .=! queryMethod 236 .: "q" .=! queryMethod
@@ -288,11 +295,13 @@ encodeAddr _ = B.empty
288-- * KResponse can be only sent from server to client. 295-- * KResponse can be only sent from server to client.
289-- 296--
290#ifdef VERSION_bencoding 297#ifdef VERSION_bencoding
291data KResponse = KResponse 298data KResponseOf a = KResponse
292 { respVals :: KQueryArgs -- ^ 'BDict' containing return values; 299 { respVals :: a -- ^ 'BDict' containing return values;
293 , respId :: TransactionId -- ^ match to the corresponding 'queryId'. 300 , respId :: TransactionId -- ^ match to the corresponding 'queryId'.
294 , respIP :: Maybe ReflectedIP 301 , respIP :: Maybe ReflectedIP
295 } deriving (Show, Eq, Ord, Typeable) 302 } deriving (Show, Eq, Ord, Typeable, Functor, Foldable, Traversable)
303
304type KResponse = KResponseOf KQueryArgs
296 305
297-- | Responses, or KRPC message dictionaries with a \"y\" value of 306-- | Responses, or KRPC message dictionaries with a \"y\" value of
298-- \"r\", contain one additional key \"r\". The value of \"r\" is a 307-- \"r\", contain one additional key \"r\". The value of \"r\" is a
@@ -302,7 +311,7 @@ data KResponse = KResponse
302-- 311--
303-- > { "t" : "aa", "y" : "r", "r" : { "msg" : "you've sent: hi!" } } 312-- > { "t" : "aa", "y" : "r", "r" : { "msg" : "you've sent: hi!" } }
304-- 313--
305instance BEncode KResponse where 314instance (Typeable a, BEncode a) => BEncode (KResponseOf a) where
306 toBEncode KResponse {..} = toDict $ 315 toBEncode KResponse {..} = toDict $
307 "ip" .=? respIP 316 "ip" .=? respIP
308 .: "r" .=! respVals 317 .: "r" .=! respVals
@@ -329,11 +338,13 @@ respIP = Nothing :: Maybe ReflectedIP
329 338
330#ifdef VERSION_bencoding 339#ifdef VERSION_bencoding
331-- | Generic KRPC message. 340-- | Generic KRPC message.
332data KMessage 341data KMessageOf a
333 = Q KQuery 342 = Q (KQueryOf a)
334 | R KResponse 343 | R (KResponseOf a)
335 | E KError 344 | E KError
336 deriving (Show, Eq) 345 deriving (Show, Eq, Functor, Foldable, Traversable)
346
347type KMessage = KMessageOf KQueryArgs
337 348
338instance BEncode KMessage where 349instance BEncode KMessage where
339 toBEncode (Q q) = toBEncode q 350 toBEncode (Q q) = toBEncode q
diff --git a/src/Network/KRPC/Method.hs b/src/Network/KRPC/Method.hs
index 2a791924..ad93cb8b 100644
--- a/src/Network/KRPC/Method.hs
+++ b/src/Network/KRPC/Method.hs
@@ -8,11 +8,13 @@
8-- Normally, you don't need to import this module. 8-- Normally, you don't need to import this module.
9-- 9--
10{-# LANGUAGE CPP #-} 10{-# LANGUAGE CPP #-}
11{-# LANGUAGE RankNTypes #-} 11{-# LANGUAGE DefaultSignatures #-}
12{-# LANGUAGE MultiParamTypeClasses #-}
13{-# LANGUAGE GeneralizedNewtypeDeriving #-} 12{-# LANGUAGE GeneralizedNewtypeDeriving #-}
13{-# LANGUAGE MultiParamTypeClasses #-}
14{-# LANGUAGE RankNTypes #-}
14{-# LANGUAGE ScopedTypeVariables #-} 15{-# LANGUAGE ScopedTypeVariables #-}
15{-# LANGUAGE DefaultSignatures #-} 16{-# LANGUAGE TypeFamilies #-}
17{-# LANGUAGE FunctionalDependencies #-}
16module Network.KRPC.Method 18module Network.KRPC.Method
17 ( Method (..) 19 ( Method (..)
18 , KRPC (..) 20 , KRPC (..)
@@ -93,7 +95,9 @@ class ( Typeable req, Typeable resp
93 , Serialize req, Serialize resp 95 , Serialize req, Serialize resp
94#endif 96#endif
95 ) 97 )
96 => KRPC req resp where 98 => KRPC req resp | req -> resp, resp -> req where
99
100 type Envelope req resp
97 101
98 -- | Method name. Default implementation uses lowercased @req@ 102 -- | Method name. Default implementation uses lowercased @req@
99 -- datatype name. 103 -- datatype name.
@@ -107,3 +111,6 @@ class ( Typeable req, Typeable resp
107 where 111 where
108 hole = error "krpc.method: impossible" :: req 112 hole = error "krpc.method: impossible" :: req
109#endif 113#endif
114
115 unseal :: Envelope req resp -> Either String req
116 seal :: resp -> Envelope req resp