summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Network/BitTorrent/DHT/Message.hs29
-rw-r--r--src/Network/BitTorrent/DHT/Query.hs9
-rw-r--r--src/Network/BitTorrent/DHT/Session.hs4
-rw-r--r--src/Network/DHT/Mainline.hs22
-rw-r--r--src/Network/KRPC/Manager.hs43
-rw-r--r--src/Network/KRPC/Message.hs51
-rw-r--r--src/Network/KRPC/Method.hs15
-rw-r--r--src/Network/RPC.hs15
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 #-}
64module Network.BitTorrent.DHT.Message 65module 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\"
218instance KRPC (Query Ping) (Response Ping) where 219instance 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
232newtype FindNode = FindNode NodeId 236newtype FindNode ip = FindNode NodeId
233#else 237#else
234data FindNode = FindNode NodeId Tox.Nonce8 -- Tox: Get Nodes 238data 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
239target_key = "target" 243target_key = "target"
240 244
241#ifdef VERSION_bencoding 245#ifdef VERSION_bencoding
242instance BEncode FindNode where 246instance 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
246instance Serialize (Query FindNode) where 250instance 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\"
306instance (Address ip, Typeable ip) 310instance (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.
320newtype GetPeers = GetPeers InfoHash 327newtype GetPeers ip = GetPeers InfoHash
321 deriving (Show, Eq, Typeable) 328 deriving (Show, Eq, Typeable)
322 329
323info_hash_key :: BKey 330info_hash_key :: BKey
324info_hash_key = "info_hash" 331info_hash_key = "info_hash"
325 332
326instance BEncode GetPeers where 333instance 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\"
375instance (Typeable ip, Serialize ip) => 382instance (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\"
448instance KRPC (Query Announce) (Response Announced) where 458instance 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 #-}
17module Network.BitTorrent.DHT.Query 18module 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
71import Data.List as L 72import Data.List as L
72import Data.Monoid 73import Data.Monoid
73import Data.Text as T 74import Data.Text as T
75import Data.BEncode (BValue)
74import qualified Data.Set as Set 76import qualified Data.Set as Set
75 ;import Data.Set (Set) 77 ;import Data.Set (Set)
76import Network 78import Network
@@ -89,14 +91,17 @@ import Network.BitTorrent.DHT.Routing as R
89import Network.BitTorrent.DHT.Session 91import Network.BitTorrent.DHT.Session
90import Control.Concurrent.STM 92import Control.Concurrent.STM
91import qualified Network.BitTorrent.DHT.Search as Search 93import qualified Network.BitTorrent.DHT.Search as Search
94import Network.DHT.Mainline
92 95
93{----------------------------------------------------------------------- 96{-----------------------------------------------------------------------
94-- Handlers 97-- Handlers
95-----------------------------------------------------------------------} 98-----------------------------------------------------------------------}
96 99
97nodeHandler :: Address ip => KRPC (Query a) (Response b) 100nodeHandler :: ( 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
99nodeHandler action = handler $ \ sockAddr qry -> do 104nodeHandler 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
106import Data.Torrent as Torrent 106import Data.Torrent as Torrent
107import Network.KRPC as KRPC hiding (Options, def) 107import Network.KRPC as KRPC hiding (Options, def)
108import qualified Network.KRPC as KRPC (def) 108import qualified Network.KRPC as KRPC (def)
109import Network.KRPC.Message (KMessageOf)
110import Data.BEncode (BValue)
109import Network.BitTorrent.Address 111import Network.BitTorrent.Address
110import Network.BitTorrent.DHT.ContactInfo (PeerStore) 112import Network.BitTorrent.DHT.ContactInfo (PeerStore)
111import qualified Network.BitTorrent.DHT.ContactInfo as P 113import 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
315type NodeHandler ip = Handler (DHT ip) 317type 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 #-}
2module Network.DHT.Mainline where
3
4import Network.RPC
5import Network.KRPC.Message
6import Data.BEncode as BE
7import qualified Data.ByteString.Lazy as L
8
9mainline :: Messaging KMessageOf TransactionId BValue
10mainline = 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
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
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 #-}
2module Network.RPC where
3
4import Data.ByteString (ByteString)
5
6data MessageClass = Error | Query | Response
7 deriving (Eq,Ord,Enum,Bounded,Show,Read)
8
9data 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 }