summaryrefslogtreecommitdiff
path: root/src/Network/KRPC
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2017-06-04 22:39:14 -0400
committerjoe <joe@jerkface.net>2017-06-04 22:39:14 -0400
commit219d72ebde4bab5a516a86608dcb3aede75c1611 (patch)
treedf111d38c3532b9342f30c1bad98ef095569d54f /src/Network/KRPC
parent713cee07450697e40811e74059739da02dd604c7 (diff)
WIP: Adapting DHT to Tox network.
Diffstat (limited to 'src/Network/KRPC')
-rw-r--r--src/Network/KRPC/Manager.hs137
-rw-r--r--src/Network/KRPC/Message.hs75
-rw-r--r--src/Network/KRPC/Method.hs26
3 files changed, 209 insertions, 29 deletions
diff --git a/src/Network/KRPC/Manager.hs b/src/Network/KRPC/Manager.hs
index 66de6548..e7f0563b 100644
--- a/src/Network/KRPC/Manager.hs
+++ b/src/Network/KRPC/Manager.hs
@@ -55,9 +55,13 @@ import Control.Monad
55import Control.Monad.Logger 55import Control.Monad.Logger
56import Control.Monad.Reader 56import Control.Monad.Reader
57import Control.Monad.Trans.Control 57import Control.Monad.Trans.Control
58#ifdef VERSION_bencoding
58import Data.BEncode as BE 59import Data.BEncode as BE
59import Data.BEncode.Internal as BE 60import Data.BEncode.Internal as BE
60import Data.BEncode.Pretty (showBEncode) 61import Data.BEncode.Pretty (showBEncode)
62#else
63import qualified Data.Tox as Tox
64#endif
61import qualified Data.ByteString.Base16 as Base16 65import qualified Data.ByteString.Base16 as Base16
62import Data.ByteString as BS 66import Data.ByteString as BS
63import Data.ByteString.Char8 as BC 67import Data.ByteString.Char8 as BC
@@ -67,6 +71,7 @@ import Data.IORef
67import Data.List as L 71import Data.List as L
68import Data.Map as M 72import Data.Map as M
69import Data.Monoid 73import Data.Monoid
74import Data.Serialize as S
70import Data.Text as T 75import Data.Text as T
71import Data.Text.Encoding as T 76import Data.Text.Encoding as T
72import Data.Tuple 77import Data.Tuple
@@ -128,10 +133,10 @@ type KResult = Either KError KResponse
128 133
129type TransactionCounter = IORef Int 134type TransactionCounter = IORef Int
130type CallId = (TransactionId, SockAddr) 135type CallId = (TransactionId, SockAddr)
131type CallRes = MVar (BValue, KResult) 136type CallRes = MVar (KQueryArgs, KResult) -- (raw response, decoded response)
132type PendingCalls = IORef (Map CallId CallRes) 137type PendingCalls = IORef (Map CallId CallRes)
133 138
134type HandlerBody h = SockAddr -> BValue -> h (BE.Result BValue) 139type HandlerBody h = SockAddr -> KQueryArgs -> h (Either String KQueryArgs)
135 140
136-- | Handler is a function which will be invoked then some /remote/ 141-- | Handler is a function which will be invoked then some /remote/
137-- node querying /this/ node. 142-- node querying /this/ node.
@@ -223,8 +228,13 @@ withManager opts addr hs = bracket (newManager opts addr hs) closeManager
223-- TODO prettify log messages 228-- TODO prettify log messages
224querySignature :: MethodName -> TransactionId -> SockAddr -> Text 229querySignature :: MethodName -> TransactionId -> SockAddr -> Text
225querySignature name transaction addr = T.concat 230querySignature name transaction addr = T.concat
231#ifdef VERSION_bencoding
226 [ "&", T.decodeUtf8 name 232 [ "&", T.decodeUtf8 name
227 , " #", T.decodeUtf8 (Base16.encode transaction) -- T.decodeUtf8 transaction 233 , " #", T.decodeUtf8 (Base16.encode transaction) -- T.decodeUtf8 transaction
234#else
235 [ "&", T.pack (show name)
236 , " #", T.decodeUtf8 (Base16.encode $ S.encode transaction)
237#endif
228 , " @", T.pack (show addr) 238 , " @", T.pack (show addr)
229 ] 239 ]
230 240
@@ -243,14 +253,24 @@ data QueryFailure
243 253
244instance Exception QueryFailure 254instance Exception QueryFailure
245 255
256#ifdef VERSION_bencoding
246sendMessage :: MonadIO m => BEncode a => Socket -> SockAddr -> a -> m () 257sendMessage :: MonadIO m => BEncode a => Socket -> SockAddr -> a -> m ()
247sendMessage sock addr a = do 258sendMessage sock addr a = do
248 liftIO $ sendManyTo sock (BL.toChunks (BE.encode a)) addr 259 liftIO $ sendManyTo sock (BL.toChunks (BE.encode a)) addr
260#else
261sendMessage :: MonadIO m => Socket -> SockAddr -> BC.ByteString -> m ()
262sendMessage sock addr a = do
263 liftIO $ sendManyTo sock [a] addr
264#endif
249 265
250genTransactionId :: TransactionCounter -> IO TransactionId 266genTransactionId :: TransactionCounter -> IO TransactionId
251genTransactionId ref = do 267genTransactionId ref = do
252 cur <- atomicModifyIORef' ref $ \ cur -> (succ cur, cur) 268 cur <- atomicModifyIORef' ref $ \ cur -> (succ cur, cur)
269#ifdef VERSION_bencoding
253 return $ BC.pack (show cur) 270 return $ BC.pack (show cur)
271#else
272 return $ either (error "failed to create TransactionId") id $ S.decode $ BC.pack (L.take 24 $ show cur ++ L.repeat ' ')
273#endif
254 274
255-- | How many times 'query' call have been performed. 275-- | How many times 'query' call have been performed.
256getQueryCount :: MonadKRPC h m => m Int 276getQueryCount :: MonadKRPC h m => m Int
@@ -274,8 +294,13 @@ unregisterQuery cid ref = do
274 294
275 295
276-- (sendmsg EINVAL) 296-- (sendmsg EINVAL)
297#ifdef VERSION_bencoding
277sendQuery :: BEncode a => Socket -> SockAddr -> a -> IO () 298sendQuery :: BEncode a => Socket -> SockAddr -> a -> IO ()
278sendQuery sock addr q = handle sockError $ sendMessage sock addr q 299sendQuery sock addr q = handle sockError $ sendMessage sock addr q
300#else
301sendQuery :: Serialize a => Socket -> SockAddr -> a -> IO ()
302sendQuery sock addr q = handle sockError $ sendMessage sock addr (S.encode q)
303#endif
279 where 304 where
280 sockError :: IOError -> IO () 305 sockError :: IOError -> IO ()
281 sockError _ = throwIO SendFailed 306 sockError _ = throwIO SendFailed
@@ -295,11 +320,11 @@ query' addr params = queryK addr params (const (,))
295-- | Enqueue a query, but give us the complete BEncoded content sent by the 320-- | Enqueue a query, but give us the complete BEncoded content sent by the
296-- remote Node. This is useful for handling extensions that this library does 321-- remote Node. This is useful for handling extensions that this library does
297-- not otherwise support. 322-- not otherwise support.
298queryRaw :: forall h m a b. (MonadKRPC h m, KRPC a b) => SockAddr -> a -> m (b, BValue) 323queryRaw :: forall h m a b. (MonadKRPC h m, KRPC a b) => SockAddr -> a -> m (b, KQueryArgs)
299queryRaw addr params = queryK addr params (\raw x _ -> (x,raw)) 324queryRaw addr params = queryK addr params (\raw x _ -> (x,raw))
300 325
301queryK :: forall h m a b x. (MonadKRPC h m, KRPC a b) => 326queryK :: forall h m a b x. (MonadKRPC h m, KRPC a b) =>
302 SockAddr -> a -> (BValue -> b -> Maybe ReflectedIP -> x) -> m x 327 SockAddr -> a -> (KQueryArgs -> b -> Maybe ReflectedIP -> x) -> m x
303queryK addr params kont = do 328queryK addr params kont = do
304 Manager {..} <- getManager 329 Manager {..} <- getManager
305 tid <- liftIO $ genTransactionId transactionCounter 330 tid <- liftIO $ genTransactionId transactionCounter
@@ -310,17 +335,29 @@ queryK addr params kont = do
310 mres <- liftIO $ do 335 mres <- liftIO $ do
311 ares <- registerQuery (tid, addr) pendingCalls 336 ares <- registerQuery (tid, addr) pendingCalls
312 337
338#ifdef VERSION_bencoding
313 let q = KQuery (toBEncode params) (methodName queryMethod) tid 339 let q = KQuery (toBEncode params) (methodName queryMethod) tid
340#else
341 let q = Tox.Message (methodName queryMethod) cli tid params
342 cli = error "TODO TOX client node id"
343#endif
314 sendQuery sock addr q 344 sendQuery sock addr q
315 `onException` unregisterQuery (tid, addr) pendingCalls 345 `onException` unregisterQuery (tid, addr) pendingCalls
316 346
317 timeout (optQueryTimeout options * 10 ^ (6 :: Int)) $ do 347 timeout (optQueryTimeout options * 10 ^ (6 :: Int)) $ do
318 (raw,res) <- readMVar ares 348 (raw,res) <- readMVar ares -- MVar (KQueryArgs, KResult)
319 case res of 349 case res of
350#ifdef VERSION_bencoding
320 Left (KError c m _) -> throwIO $ QueryFailed c (T.decodeUtf8 m) 351 Left (KError c m _) -> throwIO $ QueryFailed c (T.decodeUtf8 m)
321 Right (KResponse {..}) -> 352 Right (KResponse {..}) ->
322 case fromBEncode respVals of 353 case fromBEncode respVals of
323 Right r -> pure $ kont raw r respIP 354 Right r -> pure $ kont raw r respIP
355#else
356 Left _ -> throwIO $ QueryFailed GenericError "TODO: TOX ERROR"
357 Right (Tox.Message {..}) ->
358 case S.decode msgPayload of
359 Right r -> pure $ kont raw r Nothing
360#endif
324 Left e -> throwIO $ QueryFailed ProtocolError (T.pack e) 361 Left e -> throwIO $ QueryFailed ProtocolError (T.pack e)
325 362
326 case mres of 363 case mres of
@@ -377,51 +414,87 @@ handler body = (name, wrapper)
377 where 414 where
378 Method name = method :: Method a b 415 Method name = method :: Method a b
379 wrapper addr args = 416 wrapper addr args =
417#ifdef VERSION_bencoding
380 case fromBEncode args of 418 case fromBEncode args of
419#else
420 case S.decode args of
421#endif
381 Left e -> return $ Left e 422 Left e -> return $ Left e
382 Right a -> do 423 Right a -> do
383 r <- body addr a 424 r <- body addr a
425#ifdef VERSION_bencoding
384 return $ Right $ toBEncode r 426 return $ Right $ toBEncode r
427#else
428 return $ Right $ S.encode r
429#endif
385 430
386runHandler :: MonadKRPC h m 431runHandler :: MonadKRPC h m
387 => HandlerBody h -> SockAddr -> KQuery -> m KResult 432 => HandlerBody h -> SockAddr -> KQuery -> m KResult
388runHandler h addr KQuery {..} = Lifted.catches wrapper failbacks 433runHandler h addr m = Lifted.catches wrapper failbacks
389 where 434 where
390 signature = querySignature queryMethod queryId addr 435 signature = querySignature (queryMethod m) (queryId m) addr
391 436
392 wrapper = do 437 wrapper = do
393 $(logDebugS) "handler.quered" signature 438 $(logDebugS) "handler.quered" signature
394 result <- liftHandler (h addr queryArgs) 439 result <- liftHandler (h addr (queryArgs m))
395 440
396 case result of 441 case result of
397 Left msg -> do 442 Left msg -> do
398 $(logDebugS) "handler.bad_query" $ signature <> " !" <> T.pack msg 443 $(logDebugS) "handler.bad_query" $ signature <> " !" <> T.pack msg
399 return $ Left $ KError ProtocolError (BC.pack msg) queryId 444#ifdef VERSION_bencoding
445 return $ Left $ KError ProtocolError (BC.pack msg) (queryId m)
446#else
447 return $ Left $ decodeError "TODO TOX ProtocolError" (queryId m)
448#endif
400 449
401 Right a -> do 450 Right a -> do -- KQueryArgs
402 $(logDebugS) "handler.success" signature 451 $(logDebugS) "handler.success" signature
403 return $ Right $ KResponse a queryId (Just $ ReflectedIP addr) 452#ifdef VERSION_bencoding
453 return $ Right $ KResponse a (queryId m) (Just $ ReflectedIP addr)
454#else
455 let cli = error "TODO TOX client node id"
456 messageid = error "TODO TOX message response id"
457 -- TODO: ReflectedIP addr ??
458 return $ Right $ Tox.Message messageid cli (queryId m) a
459#endif
404 460
405 failbacks = 461 failbacks =
406 [ E.Handler $ \ (e :: HandlerFailure) -> do 462 [ E.Handler $ \ (e :: HandlerFailure) -> do
407 $(logDebugS) "handler.failed" signature 463 $(logDebugS) "handler.failed" signature
408 return $ Left $ KError ProtocolError (prettyHF e) queryId 464#ifdef VERSION_bencoding
465 return $ Left $ KError ProtocolError (prettyHF e) (queryId m)
466#else
467 return $ Left $ decodeError "TODO TOX ProtocolError 2" (queryId m)
468#endif
469
409 470
410 -- may happen if handler makes query and fail 471 -- may happen if handler makes query and fail
411 , E.Handler $ \ (e :: QueryFailure) -> do 472 , E.Handler $ \ (e :: QueryFailure) -> do
412 return $ Left $ KError ServerError (prettyQF e) queryId 473#ifdef VERSION_bencoding
474 return $ Left $ KError ServerError (prettyQF e) (queryId m)
475#else
476 return $ Left $ decodeError "TODO TOX ServerError" (queryId m)
477#endif
413 478
414 -- since handler thread exit after sendMessage we can safely 479 -- since handler thread exit after sendMessage we can safely
415 -- suppress async exception here 480 -- suppress async exception here
416 , E.Handler $ \ (e :: SomeException) -> do 481 , E.Handler $ \ (e :: SomeException) -> do
417 return $ Left $ KError GenericError (BC.pack (show e)) queryId 482#ifdef VERSION_bencoding
483 return $ Left $ KError GenericError (BC.pack (show e)) (queryId m)
484#else
485 return $ Left $ decodeError "TODO TOX GenericError" (queryId m)
486#endif
418 ] 487 ]
419 488
420dispatchHandler :: MonadKRPC h m => KQuery -> SockAddr -> m KResult 489dispatchHandler :: MonadKRPC h m => KQuery -> SockAddr -> m KResult
421dispatchHandler q @ KQuery {..} addr = do 490dispatchHandler q addr = do
422 Manager {..} <- getManager 491 Manager {..} <- getManager
423 case L.lookup queryMethod handlers of 492 case L.lookup (queryMethod q) handlers of
424 Nothing -> return $ Left $ KError MethodUnknown queryMethod queryId 493#ifdef VERSION_bencoding
494 Nothing -> return $ Left $ KError MethodUnknown (queryMethod q) (queryId q)
495#else
496 Nothing -> return $ Left $ decodeError "TODO TOX Error MethodUnknown" (queryId q)
497#endif
425 Just h -> runHandler h addr q 498 Just h -> runHandler h addr q
426 499
427{----------------------------------------------------------------------- 500{-----------------------------------------------------------------------
@@ -435,11 +508,12 @@ dispatchHandler q @ KQuery {..} addr = do
435-- peer B fork too many threads 508-- peer B fork too many threads
436-- ... space leak 509-- ... space leak
437-- 510--
438handleQuery :: MonadKRPC h m => BValue -> KQuery -> SockAddr -> m () 511handleQuery :: MonadKRPC h m => KQueryArgs -> KQuery -> SockAddr -> m ()
439handleQuery raw q addr = void $ fork $ do 512handleQuery raw q addr = void $ fork $ do
440 myThreadId >>= liftIO . flip labelThread "KRPC.handleQuery" 513 myThreadId >>= liftIO . flip labelThread "KRPC.handleQuery"
441 Manager {..} <- getManager 514 Manager {..} <- getManager
442 res <- dispatchHandler q addr 515 res <- dispatchHandler q addr
516#ifdef VERSION_bencoding
443 let resbe = either toBEncode toBEncode res 517 let resbe = either toBEncode toBEncode res
444 $(logOther "q") $ T.unlines 518 $(logOther "q") $ T.unlines
445 [ either (const "<unicode-fail>") id $ T.decodeUtf8' (BL.toStrict $ showBEncode raw) 519 [ either (const "<unicode-fail>") id $ T.decodeUtf8' (BL.toStrict $ showBEncode raw)
@@ -447,21 +521,36 @@ handleQuery raw q addr = void $ fork $ do
447 , either (const "<unicode-fail>") id $ T.decodeUtf8' (BL.toStrict $ showBEncode resbe) 521 , either (const "<unicode-fail>") id $ T.decodeUtf8' (BL.toStrict $ showBEncode resbe)
448 ] 522 ]
449 sendMessage sock addr resbe 523 sendMessage sock addr resbe
524#else
525 -- Errors not sent for Tox.
526 either (const $ return ()) (sendMessage sock addr . S.encode) res
527#endif
450 528
451handleResponse :: MonadKRPC h m => BValue -> KResult -> SockAddr -> m () 529handleResponse :: MonadKRPC h m => KQueryArgs -> KResult -> SockAddr -> m ()
452handleResponse raw result addr = do 530handleResponse raw result addr = do
453 Manager {..} <- getManager 531 Manager {..} <- getManager
454 liftIO $ do 532 liftIO $ do
533#ifdef VERSION_bencoding
455 let resultId = either errorId respId result 534 let resultId = either errorId respId result
535#else
536 let resultId = either Tox.msgNonce Tox.msgNonce result
537#endif
456 mcall <- unregisterQuery (resultId, addr) pendingCalls 538 mcall <- unregisterQuery (resultId, addr) pendingCalls
457 case mcall of 539 case mcall of
458 Nothing -> return () 540 Nothing -> return ()
459 Just ares -> putMVar ares (raw,result) 541 Just ares -> putMVar ares (raw,result)
460 542
461handleMessage :: MonadKRPC h m => BValue -> KMessage -> SockAddr -> m () 543#ifdef VERSION_bencoding
544handleMessage :: MonadKRPC h m => KQueryArgs -> KMessage -> SockAddr -> m ()
462handleMessage raw (Q q) = handleQuery raw q 545handleMessage raw (Q q) = handleQuery raw q
463handleMessage raw (R r) = handleResponse raw (Right r) 546handleMessage raw (R r) = handleResponse raw (Right r)
464handleMessage raw (E e) = handleResponse raw (Left e) 547handleMessage raw (E e) = handleResponse raw (Left e)
548#else
549handleMessage :: MonadKRPC h m => KQueryArgs -> Tox.Message BC.ByteString -> SockAddr -> m ()
550handleMessage raw q | Tox.isQuery q = handleQuery raw q
551handleMessage raw r | Tox.isResponse r = handleResponse raw (Right r)
552handleMessage raw e | Tox.isError e = handleResponse raw (Left e)
553#endif
465 554
466listener :: MonadKRPC h m => m () 555listener :: MonadKRPC h m => m ()
467listener = do 556listener = do
@@ -469,9 +558,17 @@ listener = do
469 fix $ \again -> do 558 fix $ \again -> do
470 (bs, addr) <- liftIO $ do 559 (bs, addr) <- liftIO $ do
471 handle exceptions $ BS.recvFrom sock (optMaxMsgSize options) 560 handle exceptions $ BS.recvFrom sock (optMaxMsgSize options)
561#ifdef VERSION_bencoding
472 case BE.parse bs >>= \r -> (,) r <$> BE.decode bs of 562 case BE.parse bs >>= \r -> (,) r <$> BE.decode bs of
563#else
564 case return bs >>= \r -> (,) r <$> decode bs of
565#endif
473 -- TODO ignore unknown messages at all? 566 -- TODO ignore unknown messages at all?
567#ifdef VERSION_bencoding
474 Left e -> liftIO $ sendMessage sock addr $ unknownMessage e 568 Left e -> liftIO $ sendMessage sock addr $ unknownMessage e
569#else
570 Left _ -> return () -- TODO TOX send unknownMessage error
571#endif
475 Right (raw,m) -> handleMessage raw m addr 572 Right (raw,m) -> handleMessage raw m addr
476 again 573 again
477 where 574 where
diff --git a/src/Network/KRPC/Message.hs b/src/Network/KRPC/Message.hs
index 6f4ae620..d48fa8ac 100644
--- a/src/Network/KRPC/Message.hs
+++ b/src/Network/KRPC/Message.hs
@@ -12,8 +12,10 @@
12-- 12--
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 OverloadedStrings #-} 16{-# LANGUAGE OverloadedStrings #-}
16{-# LANGUAGE FlexibleContexts #-} 17{-# LANGUAGE FlexibleContexts #-}
18{-# LANGUAGE FlexibleInstances #-}
17{-# LANGUAGE TypeSynonymInstances #-} 19{-# LANGUAGE TypeSynonymInstances #-}
18{-# LANGUAGE MultiParamTypeClasses #-} 20{-# LANGUAGE MultiParamTypeClasses #-}
19{-# LANGUAGE FunctionalDependencies #-} 21{-# LANGUAGE FunctionalDependencies #-}
@@ -31,6 +33,11 @@ module Network.KRPC.Message
31 33
32 -- * Query 34 -- * Query
33 , KQuery(..) 35 , KQuery(..)
36#ifndef VERSION_bencoding
37 , queryArgs
38 , queryMethod
39 , queryId
40#endif
34 , MethodName 41 , MethodName
35 42
36 -- * Response 43 -- * Response
@@ -39,12 +46,18 @@ module Network.KRPC.Message
39 46
40 -- * Message 47 -- * Message
41 , KMessage (..) 48 , KMessage (..)
49 , KQueryArgs
50
42 ) where 51 ) where
43 52
44import Control.Applicative 53import Control.Applicative
45import Control.Arrow 54import Control.Arrow
46import Control.Exception.Lifted as Lifted 55import Control.Exception.Lifted as Lifted
56#ifdef VERSION_bencoding
47import Data.BEncode as BE 57import Data.BEncode as BE
58#else
59import qualified Data.Tox as Tox
60#endif
48import Data.ByteString as B 61import Data.ByteString as B
49import Data.ByteString.Char8 as BC 62import Data.ByteString.Char8 as BC
50import qualified Data.Serialize as S 63import qualified Data.Serialize as S
@@ -53,15 +66,23 @@ import Data.Typeable
53import Network.Socket (SockAddr (..),PortNumber,HostAddress) 66import Network.Socket (SockAddr (..),PortNumber,HostAddress)
54 67
55 68
69#ifdef VERSION_bencoding
56-- | This transaction ID is generated by the querying node and is 70-- | This transaction ID is generated by the querying node and is
57-- echoed in the response, so responses may be correlated with 71-- echoed in the response, so responses may be correlated with
58-- multiple queries to the same node. The transaction ID should be 72-- multiple queries to the same node. The transaction ID should be
59-- encoded as a short string of binary numbers, typically 2 characters 73-- encoded as a short string of binary numbers, typically 2 characters
60-- are enough as they cover 2^16 outstanding queries. 74-- are enough as they cover 2^16 outstanding queries.
61type TransactionId = ByteString 75type TransactionId = ByteString
76#else
77type TransactionId = Tox.Nonce24 -- msgNonce
78#endif
62 79
63unknownTransaction :: TransactionId 80unknownTransaction :: TransactionId
81#ifdef VERSION_bencoding
64unknownTransaction = "" 82unknownTransaction = ""
83#else
84unknownTransaction = 0
85#endif
65 86
66{----------------------------------------------------------------------- 87{-----------------------------------------------------------------------
67-- Error messages 88-- Error messages
@@ -98,13 +119,16 @@ instance Enum ErrorCode where
98 toEnum _ = GenericError 119 toEnum _ = GenericError
99 {-# INLINE toEnum #-} 120 {-# INLINE toEnum #-}
100 121
122#ifdef VERSION_bencoding
101instance BEncode ErrorCode where 123instance BEncode ErrorCode where
102 toBEncode = toBEncode . fromEnum 124 toBEncode = toBEncode . fromEnum
103 {-# INLINE toBEncode #-} 125 {-# INLINE toBEncode #-}
104 126
105 fromBEncode b = toEnum <$> fromBEncode b 127 fromBEncode b = toEnum <$> fromBEncode b
106 {-# INLINE fromBEncode #-} 128 {-# INLINE fromBEncode #-}
129#endif
107 130
131#ifdef VERSION_bencoding
108-- | Errors are sent when a query cannot be fulfilled. Error message 132-- | Errors are sent when a query cannot be fulfilled. Error message
109-- can be send only from server to client but not in the opposite 133-- can be send only from server to client but not in the opposite
110-- direction. 134-- direction.
@@ -113,7 +137,10 @@ data KError = KError
113 { errorCode :: !ErrorCode -- ^ the type of error; 137 { errorCode :: !ErrorCode -- ^ the type of error;
114 , errorMessage :: !ByteString -- ^ human-readable text message; 138 , errorMessage :: !ByteString -- ^ human-readable text message;
115 , errorId :: !TransactionId -- ^ match to the corresponding 'queryId'. 139 , errorId :: !TransactionId -- ^ match to the corresponding 'queryId'.
116 } deriving (Show, Read, Eq, Ord, Typeable) 140 } deriving ( Show, Eq, Ord, Typeable, Read )
141#else
142type KError = Tox.Message ByteString -- TODO TOX unused
143#endif
117 144
118-- | Errors, or KRPC message dictionaries with a \"y\" value of \"e\", 145-- | Errors, or KRPC message dictionaries with a \"y\" value of \"e\",
119-- contain one additional key \"e\". The value of \"e\" is a 146-- contain one additional key \"e\". The value of \"e\" is a
@@ -129,6 +156,7 @@ data KError = KError
129-- 156--
130-- > d1:eli201e23:A Generic Error Ocurrede1:t2:aa1:y1:ee 157-- > d1:eli201e23:A Generic Error Ocurrede1:t2:aa1:y1:ee
131-- 158--
159#ifdef VERSION_bencoding
132instance BEncode KError where 160instance BEncode KError where
133 toBEncode KError {..} = toDict $ 161 toBEncode KError {..} = toDict $
134 "e" .=! (errorCode, errorMessage) 162 "e" .=! (errorCode, errorMessage)
@@ -142,33 +170,49 @@ instance BEncode KError where
142 (code, msg) <- field (req "e") 170 (code, msg) <- field (req "e")
143 KError code msg <$>! "t" 171 KError code msg <$>! "t"
144 {-# INLINE fromBEncode #-} 172 {-# INLINE fromBEncode #-}
173#endif
145 174
146instance Exception KError 175instance Exception KError
147 176
148-- | Received 'queryArgs' or 'respVals' can not be decoded. 177-- | Received 'queryArgs' or 'respVals' can not be decoded.
149decodeError :: String -> TransactionId -> KError 178decodeError :: String -> TransactionId -> KError
179#ifdef VERSION_bencoding
150decodeError msg = KError ProtocolError (BC.pack msg) 180decodeError msg = KError ProtocolError (BC.pack msg)
181#else
182decodeError msg = error "TODO TOX Error packet"
183#endif
151 184
152-- | A remote node has send some 'KMessage' this node is unable to 185-- | A remote node has send some 'KMessage' this node is unable to
153-- decode. 186-- decode.
154unknownMessage :: String -> KError 187unknownMessage :: String -> KError
188#ifdef VERSION_bencoding
155unknownMessage msg = KError ProtocolError (BC.pack msg) unknownTransaction 189unknownMessage msg = KError ProtocolError (BC.pack msg) unknownTransaction
190#else
191unknownMessage msg = error "TODO TOX Protocol error"
192#endif
156 193
157{----------------------------------------------------------------------- 194{-----------------------------------------------------------------------
158-- Query messages 195-- Query messages
159-----------------------------------------------------------------------} 196-----------------------------------------------------------------------}
160 197
198#ifdef VERSION_bencoding
161type MethodName = ByteString 199type MethodName = ByteString
200type KQueryArgs = BValue
201#else
202type MethodName = Tox.MessageType -- msgType
203type KQueryArgs = ByteString -- msgPayload
204#endif
162 205
206#ifdef VERSION_bencoding
163-- | Query used to signal that caller want to make procedure call to 207-- | Query used to signal that caller want to make procedure call to
164-- callee and pass arguments in. Therefore query may be only sent from 208-- callee and pass arguments in. Therefore query may be only sent from
165-- client to server but not in the opposite direction. 209-- client to server but not in the opposite direction.
166-- 210--
167data KQuery = KQuery 211data KQuery = KQuery
168 { queryArgs :: !BValue -- ^ values to be passed to method; 212 { queryArgs :: !KQueryArgs -- ^ values to be passed to method;
169 , queryMethod :: !MethodName -- ^ method to call; 213 , queryMethod :: !MethodName -- ^ method to call;
170 , queryId :: !TransactionId -- ^ one-time query token. 214 , queryId :: !TransactionId -- ^ one-time query token.
171 } deriving (Show, Read, Eq, Ord, Typeable) 215 } deriving ( Show, Eq, Ord, Typeable, Read )
172 216
173-- | Queries, or KRPC message dictionaries with a \"y\" value of 217-- | Queries, or KRPC message dictionaries with a \"y\" value of
174-- \"q\", contain two additional keys; \"q\" and \"a\". Key \"q\" has 218-- \"q\", contain two additional keys; \"q\" and \"a\". Key \"q\" has
@@ -193,13 +237,19 @@ instance BEncode KQuery where
193 KQuery <$>! "a" <*>! "q" <*>! "t" 237 KQuery <$>! "a" <*>! "q" <*>! "t"
194 {-# INLINE fromBEncode #-} 238 {-# INLINE fromBEncode #-}
195 239
196newtype ReflectedIP = ReflectedIP SockAddr
197 deriving (Eq, Ord, Show)
198
199instance BEncode ReflectedIP where 240instance BEncode ReflectedIP where
200 toBEncode (ReflectedIP addr) = BString (encodeAddr addr) 241 toBEncode (ReflectedIP addr) = BString (encodeAddr addr)
201 fromBEncode (BString bs) = ReflectedIP <$> decodeAddr bs 242 fromBEncode (BString bs) = ReflectedIP <$> decodeAddr bs
202 fromBEncode _ = Left "ReflectedIP should be a bencoded string" 243 fromBEncode _ = Left "ReflectedIP should be a bencoded string"
244#else
245type KQuery = Tox.Message KQueryArgs
246queryArgs = Tox.msgPayload
247queryMethod = Tox.msgType
248queryId = Tox.msgNonce
249#endif
250
251newtype ReflectedIP = ReflectedIP SockAddr
252 deriving (Eq, Ord, Show)
203 253
204port16 :: Word16 -> PortNumber 254port16 :: Word16 -> PortNumber
205port16 = fromIntegral 255port16 = fromIntegral
@@ -237,8 +287,9 @@ encodeAddr _ = B.empty
237-- 287--
238-- * KResponse can be only sent from server to client. 288-- * KResponse can be only sent from server to client.
239-- 289--
290#ifdef VERSION_bencoding
240data KResponse = KResponse 291data KResponse = KResponse
241 { respVals :: BValue -- ^ 'BDict' containing return values; 292 { respVals :: KQueryArgs -- ^ 'BDict' containing return values;
242 , respId :: TransactionId -- ^ match to the corresponding 'queryId'. 293 , respId :: TransactionId -- ^ match to the corresponding 'queryId'.
243 , respIP :: Maybe ReflectedIP 294 , respIP :: Maybe ReflectedIP
244 } deriving (Show, Eq, Ord, Typeable) 295 } deriving (Show, Eq, Ord, Typeable)
@@ -265,11 +316,18 @@ instance BEncode KResponse where
265 addr <- optional (field (req "ip")) 316 addr <- optional (field (req "ip"))
266 (\r t -> KResponse r t addr) <$>! "r" <*>! "t" 317 (\r t -> KResponse r t addr) <$>! "r" <*>! "t"
267 {-# INLINE fromBEncode #-} 318 {-# INLINE fromBEncode #-}
319#else
320type KResponse = Tox.Message KQueryArgs
321respVals = Tox.msgPayload
322respId = Tox.msgNonce
323respIP = Nothing :: Maybe ReflectedIP
324#endif
268 325
269{----------------------------------------------------------------------- 326{-----------------------------------------------------------------------
270-- Summed messages 327-- Summed messages
271-----------------------------------------------------------------------} 328-----------------------------------------------------------------------}
272 329
330#ifdef VERSION_bencoding
273-- | Generic KRPC message. 331-- | Generic KRPC message.
274data KMessage 332data KMessage
275 = Q KQuery 333 = Q KQuery
@@ -287,3 +345,6 @@ instance BEncode KMessage where
287 <|> R <$> fromBEncode b 345 <|> R <$> fromBEncode b
288 <|> E <$> fromBEncode b 346 <|> E <$> fromBEncode b
289 <|> decodingError "KMessage: unknown message or message tag" 347 <|> decodingError "KMessage: unknown message or message tag"
348#else
349type KMessage = Tox.Message
350#endif
diff --git a/src/Network/KRPC/Method.hs b/src/Network/KRPC/Method.hs
index 916b38a8..2a791924 100644
--- a/src/Network/KRPC/Method.hs
+++ b/src/Network/KRPC/Method.hs
@@ -7,6 +7,7 @@
7-- 7--
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 RankNTypes #-} 11{-# LANGUAGE RankNTypes #-}
11{-# LANGUAGE MultiParamTypeClasses #-} 12{-# LANGUAGE MultiParamTypeClasses #-}
12{-# LANGUAGE GeneralizedNewtypeDeriving #-} 13{-# LANGUAGE GeneralizedNewtypeDeriving #-}
@@ -17,7 +18,11 @@ module Network.KRPC.Method
17 , KRPC (..) 18 , KRPC (..)
18 ) where 19 ) where
19 20
21#ifdef VERSION_bencoding
20import Data.BEncode (BEncode) 22import Data.BEncode (BEncode)
23#else
24import Data.Serialize
25#endif
21import Data.ByteString.Char8 as BC 26import Data.ByteString.Char8 as BC
22import Data.Char 27import Data.Char
23import Data.Monoid 28import Data.Monoid
@@ -38,7 +43,12 @@ import Network.KRPC.Message
38-- * result: Type of return value of the method. 43-- * result: Type of return value of the method.
39-- 44--
40newtype Method param result = Method { methodName :: MethodName } 45newtype Method param result = Method { methodName :: MethodName }
41 deriving (Eq, Ord, IsString, BEncode) 46 deriving ( Eq, Ord
47#ifdef VERSION_bencoding
48 , IsString
49 , BEncode
50#endif
51 )
42 52
43-- | Example: 53-- | Example:
44-- 54--
@@ -49,7 +59,11 @@ instance (Typeable a, Typeable b) => Show (Method a b) where
49 59
50showsMethod :: forall a b. ( Typeable a , Typeable b ) => Method a b -> ShowS 60showsMethod :: forall a b. ( Typeable a , Typeable b ) => Method a b -> ShowS
51showsMethod (Method name) = 61showsMethod (Method name) =
62#ifdef VERSION_bencoding
52 showString (BC.unpack name) <> 63 showString (BC.unpack name) <>
64#else
65 shows (show name) <>
66#endif
53 showString " :: " <> 67 showString " :: " <>
54 shows paramsTy <> 68 shows paramsTy <>
55 showString " -> " <> 69 showString " -> " <>
@@ -72,7 +86,13 @@ showsMethod (Method name) =
72-- method = \"ping\" 86-- method = \"ping\"
73-- @ 87-- @
74-- 88--
75class (Typeable req, BEncode req, Typeable resp, BEncode resp) 89class ( Typeable req, Typeable resp
90#ifdef VERSION_bencoding
91 , BEncode req, BEncode resp
92#else
93 , Serialize req, Serialize resp
94#endif
95 )
76 => KRPC req resp where 96 => KRPC req resp where
77 97
78 -- | Method name. Default implementation uses lowercased @req@ 98 -- | Method name. Default implementation uses lowercased @req@
@@ -80,8 +100,10 @@ class (Typeable req, BEncode req, Typeable resp, BEncode resp)
80 -- 100 --
81 method :: Method req resp 101 method :: Method req resp
82 102
103#ifdef VERSION_bencoding
83 -- TODO add underscores 104 -- TODO add underscores
84 default method :: Typeable req => Method req resp 105 default method :: Typeable req => Method req resp
85 method = Method $ fromString $ L.map toLower $ show $ typeOf hole 106 method = Method $ fromString $ L.map toLower $ show $ typeOf hole
86 where 107 where
87 hole = error "krpc.method: impossible" :: req 108 hole = error "krpc.method: impossible" :: req
109#endif