diff options
author | joe <joe@jerkface.net> | 2017-06-05 03:21:25 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-06-05 03:31:23 -0400 |
commit | 24df9a12a9240aaed8741d60e4b0b9cbf59a9fd9 (patch) | |
tree | 04791746bb576c40851f441ebc851c9d0d8da777 | |
parent | 219d72ebde4bab5a516a86608dcb3aede75c1611 (diff) |
WIP: Adapting DHT to Tox network (part 2).
-rw-r--r-- | src/Network/BitTorrent/DHT/Message.hs | 29 | ||||
-rw-r--r-- | src/Network/BitTorrent/DHT/Query.hs | 9 | ||||
-rw-r--r-- | src/Network/BitTorrent/DHT/Session.hs | 4 | ||||
-rw-r--r-- | src/Network/DHT/Mainline.hs | 22 | ||||
-rw-r--r-- | src/Network/KRPC/Manager.hs | 43 | ||||
-rw-r--r-- | src/Network/KRPC/Message.hs | 51 | ||||
-rw-r--r-- | src/Network/KRPC/Method.hs | 15 | ||||
-rw-r--r-- | src/Network/RPC.hs | 15 |
8 files changed, 127 insertions, 61 deletions
diff --git a/src/Network/BitTorrent/DHT/Message.hs b/src/Network/BitTorrent/DHT/Message.hs index 44dc9b2f..0e2bfdd9 100644 --- a/src/Network/BitTorrent/DHT/Message.hs +++ b/src/Network/BitTorrent/DHT/Message.hs | |||
@@ -61,6 +61,7 @@ | |||
61 | {-# LANGUAGE MultiParamTypeClasses #-} | 61 | {-# LANGUAGE MultiParamTypeClasses #-} |
62 | {-# LANGUAGE UndecidableInstances #-} | 62 | {-# LANGUAGE UndecidableInstances #-} |
63 | {-# LANGUAGE ScopedTypeVariables #-} | 63 | {-# LANGUAGE ScopedTypeVariables #-} |
64 | {-# LANGUAGE TypeFamilies #-} | ||
64 | module Network.BitTorrent.DHT.Message | 65 | module Network.BitTorrent.DHT.Message |
65 | ( -- * Envelopes | 66 | ( -- * Envelopes |
66 | Query (..) | 67 | Query (..) |
@@ -217,6 +218,9 @@ instance Serialize (Response Ping) where | |||
217 | -- | \"q\" = \"ping\" | 218 | -- | \"q\" = \"ping\" |
218 | instance KRPC (Query Ping) (Response Ping) where | 219 | instance KRPC (Query Ping) (Response Ping) where |
219 | #ifdef VERSION_bencoding | 220 | #ifdef VERSION_bencoding |
221 | type Envelope (Query Ping) (Response Ping) = BValue | ||
222 | seal = toBEncode | ||
223 | unseal = fromBEncode | ||
220 | method = "ping" | 224 | method = "ping" |
221 | #else | 225 | #else |
222 | method = Method Tox.Ping -- response: Tox.Pong | 226 | method = Method Tox.Ping -- response: Tox.Pong |
@@ -229,9 +233,9 @@ instance KRPC (Query Ping) (Response Ping) where | |||
229 | -- | Find node is used to find the contact information for a node | 233 | -- | Find node is used to find the contact information for a node |
230 | -- given its ID. | 234 | -- given its ID. |
231 | #ifdef VERSION_bencoding | 235 | #ifdef VERSION_bencoding |
232 | newtype FindNode = FindNode NodeId | 236 | newtype FindNode ip = FindNode NodeId |
233 | #else | 237 | #else |
234 | data FindNode = FindNode NodeId Tox.Nonce8 -- Tox: Get Nodes | 238 | data FindNode ip = FindNode NodeId Tox.Nonce8 -- Tox: Get Nodes |
235 | #endif | 239 | #endif |
236 | deriving (Show, Eq, Typeable) | 240 | deriving (Show, Eq, Typeable) |
237 | 241 | ||
@@ -239,11 +243,11 @@ target_key :: BKey | |||
239 | target_key = "target" | 243 | target_key = "target" |
240 | 244 | ||
241 | #ifdef VERSION_bencoding | 245 | #ifdef VERSION_bencoding |
242 | instance BEncode FindNode where | 246 | instance Typeable ip => BEncode (FindNode ip) where |
243 | toBEncode (FindNode nid) = toDict $ target_key .=! nid .: endDict | 247 | toBEncode (FindNode nid) = toDict $ target_key .=! nid .: endDict |
244 | fromBEncode = fromDict $ FindNode <$>! target_key | 248 | fromBEncode = fromDict $ FindNode <$>! target_key |
245 | #else | 249 | #else |
246 | instance Serialize (Query FindNode) where | 250 | instance Serialize (Query (FindNode ip)) where |
247 | get = do | 251 | get = do |
248 | nid <- get | 252 | nid <- get |
249 | nonce <- get | 253 | nonce <- get |
@@ -304,8 +308,11 @@ instance Serialize (Response (NodeFound ip)) where | |||
304 | 308 | ||
305 | -- | \"q\" == \"find_node\" | 309 | -- | \"q\" == \"find_node\" |
306 | instance (Address ip, Typeable ip) | 310 | instance (Address ip, Typeable ip) |
307 | => KRPC (Query FindNode) (Response (NodeFound ip)) where | 311 | => KRPC (Query (FindNode ip)) (Response (NodeFound ip)) where |
308 | #ifdef VERSION_bencoding | 312 | #ifdef VERSION_bencoding |
313 | type Envelope (Query (FindNode ip)) (Response (NodeFound ip)) = BValue | ||
314 | seal = toBEncode | ||
315 | unseal = fromBEncode | ||
309 | method = "find_node" | 316 | method = "find_node" |
310 | #else | 317 | #else |
311 | method = Method Tox.GetNodes -- response: Tox.SendNodes | 318 | method = Method Tox.GetNodes -- response: Tox.SendNodes |
@@ -317,13 +324,13 @@ instance (Address ip, Typeable ip) | |||
317 | -----------------------------------------------------------------------} | 324 | -----------------------------------------------------------------------} |
318 | 325 | ||
319 | -- | Get peers associated with a torrent infohash. | 326 | -- | Get peers associated with a torrent infohash. |
320 | newtype GetPeers = GetPeers InfoHash | 327 | newtype GetPeers ip = GetPeers InfoHash |
321 | deriving (Show, Eq, Typeable) | 328 | deriving (Show, Eq, Typeable) |
322 | 329 | ||
323 | info_hash_key :: BKey | 330 | info_hash_key :: BKey |
324 | info_hash_key = "info_hash" | 331 | info_hash_key = "info_hash" |
325 | 332 | ||
326 | instance BEncode GetPeers where | 333 | instance Typeable ip => BEncode (GetPeers ip) where |
327 | toBEncode (GetPeers ih) = toDict $ info_hash_key .=! ih .: endDict | 334 | toBEncode (GetPeers ih) = toDict $ info_hash_key .=! ih .: endDict |
328 | fromBEncode = fromDict $ GetPeers <$>! info_hash_key | 335 | fromBEncode = fromDict $ GetPeers <$>! info_hash_key |
329 | 336 | ||
@@ -373,7 +380,10 @@ instance (Typeable ip, Serialize ip) => BEncode (GotPeers ip) where | |||
373 | 380 | ||
374 | -- | \"q" = \"get_peers\" | 381 | -- | \"q" = \"get_peers\" |
375 | instance (Typeable ip, Serialize ip) => | 382 | instance (Typeable ip, Serialize ip) => |
376 | KRPC (Query GetPeers) (Response (GotPeers ip)) where | 383 | KRPC (Query (GetPeers ip)) (Response (GotPeers ip)) where |
384 | type Envelope (Query (GetPeers ip)) (Response (GotPeers ip)) = BValue | ||
385 | seal = toBEncode | ||
386 | unseal = fromBEncode | ||
377 | method = "get_peers" | 387 | method = "get_peers" |
378 | 388 | ||
379 | {----------------------------------------------------------------------- | 389 | {----------------------------------------------------------------------- |
@@ -446,6 +456,9 @@ instance BEncode Announced where | |||
446 | 456 | ||
447 | -- | \"q" = \"announce\" | 457 | -- | \"q" = \"announce\" |
448 | instance KRPC (Query Announce) (Response Announced) where | 458 | instance KRPC (Query Announce) (Response Announced) where |
459 | type Envelope (Query Announce) (Response Announced) = BValue | ||
460 | seal = toBEncode | ||
461 | unseal = fromBEncode | ||
449 | method = "announce_peer" | 462 | method = "announce_peer" |
450 | 463 | ||
451 | -- endif VERSION_bencoding | 464 | -- endif VERSION_bencoding |
diff --git a/src/Network/BitTorrent/DHT/Query.hs b/src/Network/BitTorrent/DHT/Query.hs index c7e48920..a1934014 100644 --- a/src/Network/BitTorrent/DHT/Query.hs +++ b/src/Network/BitTorrent/DHT/Query.hs | |||
@@ -14,6 +14,7 @@ | |||
14 | {-# LANGUAGE ScopedTypeVariables #-} | 14 | {-# LANGUAGE ScopedTypeVariables #-} |
15 | {-# LANGUAGE TemplateHaskell #-} | 15 | {-# LANGUAGE TemplateHaskell #-} |
16 | {-# LANGUAGE TupleSections #-} | 16 | {-# LANGUAGE TupleSections #-} |
17 | {-# LANGUAGE GADTs #-} | ||
17 | module Network.BitTorrent.DHT.Query | 18 | module Network.BitTorrent.DHT.Query |
18 | ( -- * Handler | 19 | ( -- * Handler |
19 | -- | To bind specific set of handlers you need to pass | 20 | -- | To bind specific set of handlers you need to pass |
@@ -71,6 +72,7 @@ import Data.Either | |||
71 | import Data.List as L | 72 | import Data.List as L |
72 | import Data.Monoid | 73 | import Data.Monoid |
73 | import Data.Text as T | 74 | import Data.Text as T |
75 | import Data.BEncode (BValue) | ||
74 | import qualified Data.Set as Set | 76 | import qualified Data.Set as Set |
75 | ;import Data.Set (Set) | 77 | ;import Data.Set (Set) |
76 | import Network | 78 | import Network |
@@ -89,14 +91,17 @@ import Network.BitTorrent.DHT.Routing as R | |||
89 | import Network.BitTorrent.DHT.Session | 91 | import Network.BitTorrent.DHT.Session |
90 | import Control.Concurrent.STM | 92 | import Control.Concurrent.STM |
91 | import qualified Network.BitTorrent.DHT.Search as Search | 93 | import qualified Network.BitTorrent.DHT.Search as Search |
94 | import Network.DHT.Mainline | ||
92 | 95 | ||
93 | {----------------------------------------------------------------------- | 96 | {----------------------------------------------------------------------- |
94 | -- Handlers | 97 | -- Handlers |
95 | -----------------------------------------------------------------------} | 98 | -----------------------------------------------------------------------} |
96 | 99 | ||
97 | nodeHandler :: Address ip => KRPC (Query a) (Response b) | 100 | nodeHandler :: ( Address ip |
101 | , KRPC (Query a) (Response b) | ||
102 | , Envelope (Query a) (Response b) ~ BValue ) | ||
98 | => (NodeAddr ip -> a -> DHT ip b) -> NodeHandler ip | 103 | => (NodeAddr ip -> a -> DHT ip b) -> NodeHandler ip |
99 | nodeHandler action = handler $ \ sockAddr qry -> do | 104 | nodeHandler action = handler mainline $ \ sockAddr qry -> do |
100 | let remoteId = queringNodeId qry | 105 | let remoteId = queringNodeId qry |
101 | read_only = queryIsReadOnly qry | 106 | read_only = queryIsReadOnly qry |
102 | q = queryParams qry | 107 | q = queryParams qry |
diff --git a/src/Network/BitTorrent/DHT/Session.hs b/src/Network/BitTorrent/DHT/Session.hs index 82926b28..db8e7cff 100644 --- a/src/Network/BitTorrent/DHT/Session.hs +++ b/src/Network/BitTorrent/DHT/Session.hs | |||
@@ -106,6 +106,8 @@ import Data.Serialize as S | |||
106 | import Data.Torrent as Torrent | 106 | import Data.Torrent as Torrent |
107 | import Network.KRPC as KRPC hiding (Options, def) | 107 | import Network.KRPC as KRPC hiding (Options, def) |
108 | import qualified Network.KRPC as KRPC (def) | 108 | import qualified Network.KRPC as KRPC (def) |
109 | import Network.KRPC.Message (KMessageOf) | ||
110 | import Data.BEncode (BValue) | ||
109 | import Network.BitTorrent.Address | 111 | import Network.BitTorrent.Address |
110 | import Network.BitTorrent.DHT.ContactInfo (PeerStore) | 112 | import Network.BitTorrent.DHT.ContactInfo (PeerStore) |
111 | import qualified Network.BitTorrent.DHT.ContactInfo as P | 113 | import qualified Network.BitTorrent.DHT.ContactInfo as P |
@@ -312,7 +314,7 @@ instance MonadLogger (DHT ip) where | |||
312 | logger <- asks loggerFun | 314 | logger <- asks loggerFun |
313 | liftIO $ logger loc src lvl (toLogStr msg) | 315 | liftIO $ logger loc src lvl (toLogStr msg) |
314 | 316 | ||
315 | type NodeHandler ip = Handler (DHT ip) | 317 | type NodeHandler ip = Handler (DHT ip) KMessageOf BValue |
316 | 318 | ||
317 | -- | Run DHT session. You /must/ properly close session using | 319 | -- | Run DHT session. You /must/ properly close session using |
318 | -- 'closeNode' function, otherwise socket or other scarce resources may | 320 | -- 'closeNode' function, otherwise socket or other scarce resources may |
diff --git a/src/Network/DHT/Mainline.hs b/src/Network/DHT/Mainline.hs new file mode 100644 index 00000000..7cd33c0d --- /dev/null +++ b/src/Network/DHT/Mainline.hs | |||
@@ -0,0 +1,22 @@ | |||
1 | {-# LANGUAGE LambdaCase #-} | ||
2 | module Network.DHT.Mainline where | ||
3 | |||
4 | import Network.RPC | ||
5 | import Network.KRPC.Message | ||
6 | import Data.BEncode as BE | ||
7 | import qualified Data.ByteString.Lazy as L | ||
8 | |||
9 | mainline :: Messaging KMessageOf TransactionId BValue | ||
10 | mainline = Messaging | ||
11 | { messageClass = \case Q _ -> Query | ||
12 | R _ -> Response | ||
13 | E _ -> Error | ||
14 | , messageTransaction = \case Q q -> queryId q | ||
15 | R r -> respId r | ||
16 | E e -> errorId e | ||
17 | , messagePayload = \case Q q -> queryArgs q | ||
18 | R r -> respVals r | ||
19 | E e -> error "TODO: messagePayload for KError" | ||
20 | , encodePayload = fmap (L.toStrict . BE.encode) | ||
21 | , decodePayload = sequence . fmap BE.decode | ||
22 | } | ||
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 | |||
76 | import Data.Text.Encoding as T | 76 | import Data.Text.Encoding as T |
77 | import Data.Tuple | 77 | import Data.Tuple |
78 | import Data.Typeable | 78 | import Data.Typeable |
79 | import Network.RPC | ||
79 | import Network.KRPC.Message | 80 | import Network.KRPC.Message |
80 | import Network.KRPC.Method | 81 | import Network.KRPC.Method |
81 | import Network.Socket hiding (listen) | 82 | import Network.Socket hiding (listen) |
@@ -136,11 +137,11 @@ type CallId = (TransactionId, SockAddr) | |||
136 | type CallRes = MVar (KQueryArgs, KResult) -- (raw response, decoded response) | 137 | type CallRes = MVar (KQueryArgs, KResult) -- (raw response, decoded response) |
137 | type PendingCalls = IORef (Map CallId CallRes) | 138 | type PendingCalls = IORef (Map CallId CallRes) |
138 | 139 | ||
139 | type HandlerBody h = SockAddr -> KQueryArgs -> h (Either String KQueryArgs) | 140 | type 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. |
143 | type Handler h = (MethodName, HandlerBody h) | 144 | type 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'. |
185 | newManager :: Options -- ^ various protocol options; | 186 | newManager :: 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. |
189 | newManager opts @ Options {..} servAddr handlers = do | 190 | newManager 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. |
220 | withManager :: Options -> SockAddr -> [Handler h] | 221 | withManager :: Options -> SockAddr -> [Handler h KMessageOf BValue] |
221 | -> (Manager h -> IO a) -> IO a | 222 | -> (Manager h -> IO a) -> IO a |
222 | withManager opts addr hs = bracket (newManager opts addr hs) closeManager | 223 | withManager 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 | -- |
411 | handler :: forall h a b. (KRPC a b, Monad h) | 412 | handler :: 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) |
413 | handler body = (name, wrapper) | 414 | handler 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 | ||
431 | runHandler :: MonadKRPC h m | 422 | runHandler :: MonadKRPC h m |
432 | => HandlerBody h -> SockAddr -> KQuery -> m KResult | 423 | => HandlerBody h KMessageOf BValue -> SockAddr -> KQuery -> m KResult |
433 | runHandler h addr m = Lifted.catches wrapper failbacks | 424 | runHandler 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 #-} | ||
24 | module Network.KRPC.Message | 26 | module 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 | -- |
211 | data KQuery = KQuery | 216 | data 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 | |||
222 | type 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 | -- |
226 | instance BEncode KQuery where | 233 | instance (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 |
291 | data KResponse = KResponse | 298 | data 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 | |||
304 | type 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 | -- |
305 | instance BEncode KResponse where | 314 | instance (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. |
332 | data KMessage | 341 | data 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 | |||
347 | type KMessage = KMessageOf KQueryArgs | ||
337 | 348 | ||
338 | instance BEncode KMessage where | 349 | instance 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 #-} | ||
16 | module Network.KRPC.Method | 18 | module 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 | ||
diff --git a/src/Network/RPC.hs b/src/Network/RPC.hs new file mode 100644 index 00000000..2e9356e8 --- /dev/null +++ b/src/Network/RPC.hs | |||
@@ -0,0 +1,15 @@ | |||
1 | {-# LANGUAGE RankNTypes #-} | ||
2 | module Network.RPC where | ||
3 | |||
4 | import Data.ByteString (ByteString) | ||
5 | |||
6 | data MessageClass = Error | Query | Response | ||
7 | deriving (Eq,Ord,Enum,Bounded,Show,Read) | ||
8 | |||
9 | data Messaging msg tid payload = Messaging | ||
10 | { messageClass :: forall a. msg a -> MessageClass | ||
11 | , messageTransaction :: forall a. msg a -> tid | ||
12 | , messagePayload :: forall a. msg a -> a | ||
13 | , encodePayload :: msg payload -> msg ByteString | ||
14 | , decodePayload :: msg ByteString -> Either String (msg payload) | ||
15 | } | ||