diff options
author | joe <joe@jerkface.net> | 2017-06-07 05:57:20 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-06-07 05:57:20 -0400 |
commit | 05345c643d0bcebe17f9474d9561da6e90fff34e (patch) | |
tree | c3ad0c1dd86a376b8c177fda57d5ef835e4efdf5 /src/Network | |
parent | a4fe28f0cf95da88f5c2db4e3397c227625aa6ac (diff) |
WIP: Adapting DHT to Tox network (part 4).
Diffstat (limited to 'src/Network')
-rw-r--r-- | src/Network/BitTorrent/DHT/Query.hs | 2 | ||||
-rw-r--r-- | src/Network/DHT/Mainline.hs | 48 | ||||
-rw-r--r-- | src/Network/KRPC/Manager.hs | 27 | ||||
-rw-r--r-- | src/Network/RPC.hs | 52 |
4 files changed, 91 insertions, 38 deletions
diff --git a/src/Network/BitTorrent/DHT/Query.hs b/src/Network/BitTorrent/DHT/Query.hs index e1104cb9..820db8ba 100644 --- a/src/Network/BitTorrent/DHT/Query.hs +++ b/src/Network/BitTorrent/DHT/Query.hs | |||
@@ -112,7 +112,7 @@ nodeHandler :: ( Address ip | |||
112 | #endif | 112 | #endif |
113 | => (NodeAddr ip -> a -> DHT ip b) -> NodeHandler ip | 113 | => (NodeAddr ip -> a -> DHT ip b) -> NodeHandler ip |
114 | #ifdef VERSION_bencoding | 114 | #ifdef VERSION_bencoding |
115 | nodeHandler action = handler mainline $ \ sockAddr qry -> do | 115 | nodeHandler action = handler $ \ sockAddr qry -> do |
116 | let remoteId = queringNodeId qry | 116 | let remoteId = queringNodeId qry |
117 | read_only = queryIsReadOnly qry | 117 | read_only = queryIsReadOnly qry |
118 | q = queryParams qry | 118 | q = queryParams qry |
diff --git a/src/Network/DHT/Mainline.hs b/src/Network/DHT/Mainline.hs index 7cd33c0d..540b74f9 100644 --- a/src/Network/DHT/Mainline.hs +++ b/src/Network/DHT/Mainline.hs | |||
@@ -1,22 +1,40 @@ | |||
1 | {-# LANGUAGE LambdaCase #-} | 1 | {-# LANGUAGE LambdaCase #-} |
2 | {-# LANGUAGE MultiParamTypeClasses #-} | ||
3 | {-# LANGUAGE TypeFamilies #-} | ||
2 | module Network.DHT.Mainline where | 4 | module Network.DHT.Mainline where |
3 | 5 | ||
6 | import Network.Socket | ||
4 | import Network.RPC | 7 | import Network.RPC |
5 | import Network.KRPC.Message | 8 | import Network.KRPC.Message as KRPC |
6 | import Data.BEncode as BE | 9 | import Data.BEncode as BE |
7 | import qualified Data.ByteString.Lazy as L | 10 | import qualified Data.ByteString.Lazy as L |
11 | import Network.BitTorrent.Address as BT (NodeId) | ||
8 | 12 | ||
9 | mainline :: Messaging KMessageOf TransactionId BValue | 13 | instance Envelope KMessageOf where |
10 | mainline = Messaging | 14 | type TransactionID KMessageOf = KRPC.TransactionId |
11 | { messageClass = \case Q _ -> Query | 15 | type NodeId KMessageOf = BT.NodeId |
12 | R _ -> Response | 16 | |
13 | E _ -> Error | 17 | envelopePayload (Q q) = queryArgs q |
14 | , messageTransaction = \case Q q -> queryId q | 18 | envelopePayload (R r) = respVals r |
15 | R r -> respId r | 19 | envelopePayload (E _) = error "TODO: messagePayload for KError" |
16 | E e -> errorId e | 20 | |
17 | , messagePayload = \case Q q -> queryArgs q | 21 | envelopeTransaction (Q q) = queryId q |
18 | R r -> respVals r | 22 | envelopeTransaction (R r) = respId r |
19 | E e -> error "TODO: messagePayload for KError" | 23 | envelopeTransaction (E e) = errorId e |
20 | , encodePayload = fmap (L.toStrict . BE.encode) | 24 | |
21 | , decodePayload = sequence . fmap BE.decode | 25 | envelopeClass (Q _) = Query |
22 | } | 26 | envelopeClass (R _) = Response |
27 | envelopeClass (E _) = Error | ||
28 | |||
29 | buildReply self addr qry response = | ||
30 | (R (KResponse response (envelopeTransaction qry) (Just $ ReflectedIP addr))) | ||
31 | |||
32 | instance WireFormat BValue KMessageOf where | ||
33 | type SerializableTo BValue = BEncode | ||
34 | type CipherContext BValue KMessageOf = () | ||
35 | |||
36 | decodeHeaders _ bs = BE.decode bs >>= BE.fromBEncode | ||
37 | decodePayload kmsg = mapM BE.fromBEncode kmsg | ||
38 | |||
39 | encodeHeaders _ kmsg = L.toStrict $ BE.encode kmsg | ||
40 | encodePayload msg = fmap BE.toBEncode msg | ||
diff --git a/src/Network/KRPC/Manager.hs b/src/Network/KRPC/Manager.hs index 58ac7674..f31a3cd6 100644 --- a/src/Network/KRPC/Manager.hs +++ b/src/Network/KRPC/Manager.hs | |||
@@ -78,11 +78,13 @@ import Data.Tuple | |||
78 | import Data.Typeable | 78 | import Data.Typeable |
79 | import Network.RPC | 79 | import Network.RPC |
80 | import Network.KRPC.Message | 80 | import Network.KRPC.Message |
81 | import Network.KRPC.Method | 81 | import Network.KRPC.Method hiding (Envelope) |
82 | import qualified Network.KRPC.Method as KRPC (Envelope) | ||
82 | import Network.Socket hiding (listen) | 83 | import Network.Socket hiding (listen) |
83 | import Network.Socket.ByteString as BS | 84 | import Network.Socket.ByteString as BS |
84 | import System.IO.Error | 85 | import System.IO.Error |
85 | import System.Timeout | 86 | import System.Timeout |
87 | import Network.DHT.Mainline | ||
86 | 88 | ||
87 | 89 | ||
88 | {----------------------------------------------------------------------- | 90 | {----------------------------------------------------------------------- |
@@ -130,14 +132,14 @@ validateOptions Options {..} | |||
130 | -- Options | 132 | -- Options |
131 | -----------------------------------------------------------------------} | 133 | -----------------------------------------------------------------------} |
132 | 134 | ||
133 | type KResult = Either KError KResponse | 135 | type KResult = Either KError KMessage -- Response |
134 | 136 | ||
135 | type TransactionCounter = IORef Int | 137 | type TransactionCounter = IORef Int |
136 | type CallId = (TransactionId, SockAddr) | 138 | type CallId = (TransactionId, SockAddr) |
137 | type CallRes = MVar (KQueryArgs, KResult) -- (raw response, decoded response) | 139 | type CallRes = MVar (KQueryArgs, KResult) -- (raw response, decoded response) |
138 | type PendingCalls = IORef (Map CallId CallRes) | 140 | type PendingCalls = IORef (Map CallId CallRes) |
139 | 141 | ||
140 | type HandlerBody h msg v = SockAddr -> msg v -> h (Either String v) | 142 | type HandlerBody h msg v = SockAddr -> msg v -> h (Either String (msg v)) |
141 | 143 | ||
142 | -- | Handler is a function which will be invoked then some /remote/ | 144 | -- | Handler is a function which will be invoked then some /remote/ |
143 | -- node querying /this/ node. | 145 | -- node querying /this/ node. |
@@ -362,7 +364,7 @@ queryK addr params kont = do | |||
362 | case res of | 364 | case res of |
363 | #ifdef VERSION_bencoding | 365 | #ifdef VERSION_bencoding |
364 | Left (KError c m _) -> throwIO $ QueryFailed c (T.decodeUtf8 m) | 366 | Left (KError c m _) -> throwIO $ QueryFailed c (T.decodeUtf8 m) |
365 | Right (KResponse {..}) -> | 367 | Right (R (KResponse {..})) -> |
366 | case fromBEncode respVals of | 368 | case fromBEncode respVals of |
367 | Right r -> pure $ kont raw r respIP | 369 | Right r -> pure $ kont raw r respIP |
368 | #else | 370 | #else |
@@ -421,15 +423,16 @@ prettyQF e = T.encodeUtf8 $ "handler fail while performing query: " | |||
421 | -- If the handler make some 'query' normally it /should/ handle | 423 | -- If the handler make some 'query' normally it /should/ handle |
422 | -- corresponding 'QueryFailure's. | 424 | -- corresponding 'QueryFailure's. |
423 | -- | 425 | -- |
424 | handler :: forall h a b msg. (KRPC a b, Applicative h, Functor msg) | 426 | handler :: forall h a b msg raw. (KRPC a b, Applicative h, Functor msg, WireFormat raw msg, SerializableTo raw a, SerializableTo raw b) |
425 | => Messaging msg TransactionId (Envelope a b) -> (SockAddr -> a -> h b) -> Handler h msg (Envelope a b) | 427 | => (SockAddr -> a -> h b) -> Handler h msg raw |
426 | handler msging body = (name, wrapper) | 428 | handler body = (name, wrapper) |
427 | where | 429 | where |
428 | Method name = method :: Method a b | 430 | Method name = method :: Method a b |
431 | wrapper :: SockAddr -> msg raw -> h (Either String (msg raw)) | ||
429 | wrapper addr args = | 432 | wrapper addr args = |
430 | case unseal $ messagePayload msging args of | 433 | case decodePayload args of |
431 | Left e -> pure $ Left e | 434 | Left e -> pure $ Left e |
432 | Right a -> Right . seal <$> body addr a | 435 | Right a -> Right . encodePayload . buildReply (error "self node-id") addr args <$> body addr (envelopePayload a) |
433 | 436 | ||
434 | runHandler :: MonadKRPC h m | 437 | runHandler :: MonadKRPC h m |
435 | #ifdef VERSION_bencoding | 438 | #ifdef VERSION_bencoding |
@@ -461,7 +464,7 @@ runHandler h addr m = Lifted.catches wrapper failbacks | |||
461 | Right a -> do -- KQueryArgs | 464 | Right a -> do -- KQueryArgs |
462 | $(logDebugS) "handler.success" signature | 465 | $(logDebugS) "handler.success" signature |
463 | #ifdef VERSION_bencoding | 466 | #ifdef VERSION_bencoding |
464 | return $ Right $ KResponse a (queryId m) (Just $ ReflectedIP addr) | 467 | return $ Right a |
465 | #else | 468 | #else |
466 | let cli = error "TODO TOX client node id" | 469 | let cli = error "TODO TOX client node id" |
467 | messageid = error "TODO TOX message response id" | 470 | messageid = error "TODO TOX message response id" |
@@ -542,7 +545,7 @@ handleResponse raw result addr = do | |||
542 | Manager {..} <- getManager | 545 | Manager {..} <- getManager |
543 | liftIO $ do | 546 | liftIO $ do |
544 | #ifdef VERSION_bencoding | 547 | #ifdef VERSION_bencoding |
545 | let resultId = either errorId respId result | 548 | let resultId = either errorId envelopeTransaction result |
546 | #else | 549 | #else |
547 | let resultId = either Tox.msgNonce Tox.msgNonce result | 550 | let resultId = either Tox.msgNonce Tox.msgNonce result |
548 | #endif | 551 | #endif |
@@ -554,7 +557,7 @@ handleResponse raw result addr = do | |||
554 | #ifdef VERSION_bencoding | 557 | #ifdef VERSION_bencoding |
555 | handleMessage :: MonadKRPC h m => KQueryArgs -> KMessage -> SockAddr -> m () | 558 | handleMessage :: MonadKRPC h m => KQueryArgs -> KMessage -> SockAddr -> m () |
556 | handleMessage raw (Q q) = handleQuery raw q | 559 | handleMessage raw (Q q) = handleQuery raw q |
557 | handleMessage raw (R r) = handleResponse raw (Right r) | 560 | handleMessage raw (R r) = handleResponse raw (Right (R r)) |
558 | handleMessage raw (E e) = handleResponse raw (Left e) | 561 | handleMessage raw (E e) = handleResponse raw (Left e) |
559 | #else | 562 | #else |
560 | handleMessage :: MonadKRPC h m => KQueryArgs -> Tox.Message BC.ByteString -> SockAddr -> m () | 563 | handleMessage :: MonadKRPC h m => KQueryArgs -> Tox.Message BC.ByteString -> SockAddr -> m () |
diff --git a/src/Network/RPC.hs b/src/Network/RPC.hs index 2e9356e8..727422fd 100644 --- a/src/Network/RPC.hs +++ b/src/Network/RPC.hs | |||
@@ -1,15 +1,47 @@ | |||
1 | {-# LANGUAGE RankNTypes #-} | 1 | {-# LANGUAGE ConstraintKinds #-} |
2 | {-# LANGUAGE FunctionalDependencies #-} | ||
3 | {-# LANGUAGE MultiParamTypeClasses #-} | ||
4 | {-# LANGUAGE RankNTypes #-} | ||
5 | {-# LANGUAGE ScopedTypeVariables #-} | ||
6 | {-# LANGUAGE TypeFamilies #-} | ||
7 | {-# LANGUAGE DeriveDataTypeable #-} | ||
2 | module Network.RPC where | 8 | module Network.RPC where |
3 | 9 | ||
4 | import Data.ByteString (ByteString) | 10 | import Data.ByteString (ByteString) |
11 | import Data.Kind (Constraint) | ||
12 | import Data.Data | ||
13 | import Network.Socket | ||
5 | 14 | ||
6 | data MessageClass = Error | Query | Response | 15 | data MessageClass = Error | Query | Response |
7 | deriving (Eq,Ord,Enum,Bounded,Show,Read) | 16 | deriving (Eq,Ord,Enum,Bounded,Data,Show,Read) |
8 | 17 | ||
9 | data Messaging msg tid payload = Messaging | 18 | class Envelope envelope where |
10 | { messageClass :: forall a. msg a -> MessageClass | 19 | type TransactionID envelope |
11 | , messageTransaction :: forall a. msg a -> tid | 20 | type NodeId envelope |
12 | , messagePayload :: forall a. msg a -> a | 21 | |
13 | , encodePayload :: msg payload -> msg ByteString | 22 | envelopePayload :: envelope a -> a |
14 | , decodePayload :: msg ByteString -> Either String (msg payload) | 23 | envelopeTransaction :: envelope a -> TransactionID envelope |
15 | } | 24 | envelopeClass :: envelope a -> MessageClass |
25 | |||
26 | -- | > buildReply self addr qry response | ||
27 | -- | ||
28 | -- [ self ] this node's id. | ||
29 | -- | ||
30 | -- [ addr ] SockAddr of query origin. | ||
31 | -- | ||
32 | -- [ qry ] received query message. | ||
33 | -- | ||
34 | -- [ response ] response payload. | ||
35 | -- | ||
36 | -- Returns: response message envelope | ||
37 | buildReply :: NodeId envelope -> SockAddr -> envelope a -> b -> envelope b | ||
38 | |||
39 | class Envelope envelope => WireFormat raw envelope where | ||
40 | type SerializableTo raw :: * -> Constraint | ||
41 | type CipherContext raw envelope | ||
42 | |||
43 | decodeHeaders :: CipherContext raw envelope -> ByteString -> Either String (envelope raw) | ||
44 | decodePayload :: SerializableTo raw a => envelope raw -> Either String (envelope a) | ||
45 | |||
46 | encodeHeaders :: CipherContext raw envelope -> envelope raw -> ByteString | ||
47 | encodePayload :: SerializableTo raw a => envelope a -> envelope raw | ||