diff options
author | joe <joe@jerkface.net> | 2017-06-04 22:39:14 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-06-04 22:39:14 -0400 |
commit | 219d72ebde4bab5a516a86608dcb3aede75c1611 (patch) | |
tree | df111d38c3532b9342f30c1bad98ef095569d54f /src/Network/KRPC | |
parent | 713cee07450697e40811e74059739da02dd604c7 (diff) |
WIP: Adapting DHT to Tox network.
Diffstat (limited to 'src/Network/KRPC')
-rw-r--r-- | src/Network/KRPC/Manager.hs | 137 | ||||
-rw-r--r-- | src/Network/KRPC/Message.hs | 75 | ||||
-rw-r--r-- | src/Network/KRPC/Method.hs | 26 |
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 | |||
55 | import Control.Monad.Logger | 55 | import Control.Monad.Logger |
56 | import Control.Monad.Reader | 56 | import Control.Monad.Reader |
57 | import Control.Monad.Trans.Control | 57 | import Control.Monad.Trans.Control |
58 | #ifdef VERSION_bencoding | ||
58 | import Data.BEncode as BE | 59 | import Data.BEncode as BE |
59 | import Data.BEncode.Internal as BE | 60 | import Data.BEncode.Internal as BE |
60 | import Data.BEncode.Pretty (showBEncode) | 61 | import Data.BEncode.Pretty (showBEncode) |
62 | #else | ||
63 | import qualified Data.Tox as Tox | ||
64 | #endif | ||
61 | import qualified Data.ByteString.Base16 as Base16 | 65 | import qualified Data.ByteString.Base16 as Base16 |
62 | import Data.ByteString as BS | 66 | import Data.ByteString as BS |
63 | import Data.ByteString.Char8 as BC | 67 | import Data.ByteString.Char8 as BC |
@@ -67,6 +71,7 @@ import Data.IORef | |||
67 | import Data.List as L | 71 | import Data.List as L |
68 | import Data.Map as M | 72 | import Data.Map as M |
69 | import Data.Monoid | 73 | import Data.Monoid |
74 | import Data.Serialize as S | ||
70 | import Data.Text as T | 75 | import Data.Text as T |
71 | import Data.Text.Encoding as T | 76 | import Data.Text.Encoding as T |
72 | import Data.Tuple | 77 | import Data.Tuple |
@@ -128,10 +133,10 @@ type KResult = Either KError KResponse | |||
128 | 133 | ||
129 | type TransactionCounter = IORef Int | 134 | type TransactionCounter = IORef Int |
130 | type CallId = (TransactionId, SockAddr) | 135 | type CallId = (TransactionId, SockAddr) |
131 | type CallRes = MVar (BValue, KResult) | 136 | type CallRes = MVar (KQueryArgs, KResult) -- (raw response, decoded response) |
132 | type PendingCalls = IORef (Map CallId CallRes) | 137 | type PendingCalls = IORef (Map CallId CallRes) |
133 | 138 | ||
134 | type HandlerBody h = SockAddr -> BValue -> h (BE.Result BValue) | 139 | type 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 |
224 | querySignature :: MethodName -> TransactionId -> SockAddr -> Text | 229 | querySignature :: MethodName -> TransactionId -> SockAddr -> Text |
225 | querySignature name transaction addr = T.concat | 230 | querySignature 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 | ||
244 | instance Exception QueryFailure | 254 | instance Exception QueryFailure |
245 | 255 | ||
256 | #ifdef VERSION_bencoding | ||
246 | sendMessage :: MonadIO m => BEncode a => Socket -> SockAddr -> a -> m () | 257 | sendMessage :: MonadIO m => BEncode a => Socket -> SockAddr -> a -> m () |
247 | sendMessage sock addr a = do | 258 | sendMessage 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 | ||
261 | sendMessage :: MonadIO m => Socket -> SockAddr -> BC.ByteString -> m () | ||
262 | sendMessage sock addr a = do | ||
263 | liftIO $ sendManyTo sock [a] addr | ||
264 | #endif | ||
249 | 265 | ||
250 | genTransactionId :: TransactionCounter -> IO TransactionId | 266 | genTransactionId :: TransactionCounter -> IO TransactionId |
251 | genTransactionId ref = do | 267 | genTransactionId 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. |
256 | getQueryCount :: MonadKRPC h m => m Int | 276 | getQueryCount :: 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 | ||
277 | sendQuery :: BEncode a => Socket -> SockAddr -> a -> IO () | 298 | sendQuery :: BEncode a => Socket -> SockAddr -> a -> IO () |
278 | sendQuery sock addr q = handle sockError $ sendMessage sock addr q | 299 | sendQuery sock addr q = handle sockError $ sendMessage sock addr q |
300 | #else | ||
301 | sendQuery :: Serialize a => Socket -> SockAddr -> a -> IO () | ||
302 | sendQuery 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. |
298 | queryRaw :: forall h m a b. (MonadKRPC h m, KRPC a b) => SockAddr -> a -> m (b, BValue) | 323 | queryRaw :: forall h m a b. (MonadKRPC h m, KRPC a b) => SockAddr -> a -> m (b, KQueryArgs) |
299 | queryRaw addr params = queryK addr params (\raw x _ -> (x,raw)) | 324 | queryRaw addr params = queryK addr params (\raw x _ -> (x,raw)) |
300 | 325 | ||
301 | queryK :: forall h m a b x. (MonadKRPC h m, KRPC a b) => | 326 | queryK :: 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 |
303 | queryK addr params kont = do | 328 | queryK 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 | ||
386 | runHandler :: MonadKRPC h m | 431 | runHandler :: MonadKRPC h m |
387 | => HandlerBody h -> SockAddr -> KQuery -> m KResult | 432 | => HandlerBody h -> SockAddr -> KQuery -> m KResult |
388 | runHandler h addr KQuery {..} = Lifted.catches wrapper failbacks | 433 | runHandler 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 | ||
420 | dispatchHandler :: MonadKRPC h m => KQuery -> SockAddr -> m KResult | 489 | dispatchHandler :: MonadKRPC h m => KQuery -> SockAddr -> m KResult |
421 | dispatchHandler q @ KQuery {..} addr = do | 490 | dispatchHandler 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 | -- |
438 | handleQuery :: MonadKRPC h m => BValue -> KQuery -> SockAddr -> m () | 511 | handleQuery :: MonadKRPC h m => KQueryArgs -> KQuery -> SockAddr -> m () |
439 | handleQuery raw q addr = void $ fork $ do | 512 | handleQuery 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 | ||
451 | handleResponse :: MonadKRPC h m => BValue -> KResult -> SockAddr -> m () | 529 | handleResponse :: MonadKRPC h m => KQueryArgs -> KResult -> SockAddr -> m () |
452 | handleResponse raw result addr = do | 530 | handleResponse 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 | ||
461 | handleMessage :: MonadKRPC h m => BValue -> KMessage -> SockAddr -> m () | 543 | #ifdef VERSION_bencoding |
544 | handleMessage :: MonadKRPC h m => KQueryArgs -> KMessage -> SockAddr -> m () | ||
462 | handleMessage raw (Q q) = handleQuery raw q | 545 | handleMessage raw (Q q) = handleQuery raw q |
463 | handleMessage raw (R r) = handleResponse raw (Right r) | 546 | handleMessage raw (R r) = handleResponse raw (Right r) |
464 | handleMessage raw (E e) = handleResponse raw (Left e) | 547 | handleMessage raw (E e) = handleResponse raw (Left e) |
548 | #else | ||
549 | handleMessage :: MonadKRPC h m => KQueryArgs -> Tox.Message BC.ByteString -> SockAddr -> m () | ||
550 | handleMessage raw q | Tox.isQuery q = handleQuery raw q | ||
551 | handleMessage raw r | Tox.isResponse r = handleResponse raw (Right r) | ||
552 | handleMessage raw e | Tox.isError e = handleResponse raw (Left e) | ||
553 | #endif | ||
465 | 554 | ||
466 | listener :: MonadKRPC h m => m () | 555 | listener :: MonadKRPC h m => m () |
467 | listener = do | 556 | listener = 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 | ||
44 | import Control.Applicative | 53 | import Control.Applicative |
45 | import Control.Arrow | 54 | import Control.Arrow |
46 | import Control.Exception.Lifted as Lifted | 55 | import Control.Exception.Lifted as Lifted |
56 | #ifdef VERSION_bencoding | ||
47 | import Data.BEncode as BE | 57 | import Data.BEncode as BE |
58 | #else | ||
59 | import qualified Data.Tox as Tox | ||
60 | #endif | ||
48 | import Data.ByteString as B | 61 | import Data.ByteString as B |
49 | import Data.ByteString.Char8 as BC | 62 | import Data.ByteString.Char8 as BC |
50 | import qualified Data.Serialize as S | 63 | import qualified Data.Serialize as S |
@@ -53,15 +66,23 @@ import Data.Typeable | |||
53 | import Network.Socket (SockAddr (..),PortNumber,HostAddress) | 66 | import 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. |
61 | type TransactionId = ByteString | 75 | type TransactionId = ByteString |
76 | #else | ||
77 | type TransactionId = Tox.Nonce24 -- msgNonce | ||
78 | #endif | ||
62 | 79 | ||
63 | unknownTransaction :: TransactionId | 80 | unknownTransaction :: TransactionId |
81 | #ifdef VERSION_bencoding | ||
64 | unknownTransaction = "" | 82 | unknownTransaction = "" |
83 | #else | ||
84 | unknownTransaction = 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 | ||
101 | instance BEncode ErrorCode where | 123 | instance 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 | ||
142 | type 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 | ||
132 | instance BEncode KError where | 160 | instance 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 | ||
146 | instance Exception KError | 175 | instance Exception KError |
147 | 176 | ||
148 | -- | Received 'queryArgs' or 'respVals' can not be decoded. | 177 | -- | Received 'queryArgs' or 'respVals' can not be decoded. |
149 | decodeError :: String -> TransactionId -> KError | 178 | decodeError :: String -> TransactionId -> KError |
179 | #ifdef VERSION_bencoding | ||
150 | decodeError msg = KError ProtocolError (BC.pack msg) | 180 | decodeError msg = KError ProtocolError (BC.pack msg) |
181 | #else | ||
182 | decodeError 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. |
154 | unknownMessage :: String -> KError | 187 | unknownMessage :: String -> KError |
188 | #ifdef VERSION_bencoding | ||
155 | unknownMessage msg = KError ProtocolError (BC.pack msg) unknownTransaction | 189 | unknownMessage msg = KError ProtocolError (BC.pack msg) unknownTransaction |
190 | #else | ||
191 | unknownMessage 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 | ||
161 | type MethodName = ByteString | 199 | type MethodName = ByteString |
200 | type KQueryArgs = BValue | ||
201 | #else | ||
202 | type MethodName = Tox.MessageType -- msgType | ||
203 | type 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 | -- |
167 | data KQuery = KQuery | 211 | data 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 | ||
196 | newtype ReflectedIP = ReflectedIP SockAddr | ||
197 | deriving (Eq, Ord, Show) | ||
198 | |||
199 | instance BEncode ReflectedIP where | 240 | instance 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 | ||
245 | type KQuery = Tox.Message KQueryArgs | ||
246 | queryArgs = Tox.msgPayload | ||
247 | queryMethod = Tox.msgType | ||
248 | queryId = Tox.msgNonce | ||
249 | #endif | ||
250 | |||
251 | newtype ReflectedIP = ReflectedIP SockAddr | ||
252 | deriving (Eq, Ord, Show) | ||
203 | 253 | ||
204 | port16 :: Word16 -> PortNumber | 254 | port16 :: Word16 -> PortNumber |
205 | port16 = fromIntegral | 255 | port16 = 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 | ||
240 | data KResponse = KResponse | 291 | data 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 | ||
320 | type KResponse = Tox.Message KQueryArgs | ||
321 | respVals = Tox.msgPayload | ||
322 | respId = Tox.msgNonce | ||
323 | respIP = 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. |
274 | data KMessage | 332 | data 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 | ||
349 | type 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 | ||
20 | import Data.BEncode (BEncode) | 22 | import Data.BEncode (BEncode) |
23 | #else | ||
24 | import Data.Serialize | ||
25 | #endif | ||
21 | import Data.ByteString.Char8 as BC | 26 | import Data.ByteString.Char8 as BC |
22 | import Data.Char | 27 | import Data.Char |
23 | import Data.Monoid | 28 | import 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 | -- |
40 | newtype Method param result = Method { methodName :: MethodName } | 45 | newtype 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 | ||
50 | showsMethod :: forall a b. ( Typeable a , Typeable b ) => Method a b -> ShowS | 60 | showsMethod :: forall a b. ( Typeable a , Typeable b ) => Method a b -> ShowS |
51 | showsMethod (Method name) = | 61 | showsMethod (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 | -- |
75 | class (Typeable req, BEncode req, Typeable resp, BEncode resp) | 89 | class ( 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 | ||