summaryrefslogtreecommitdiff
path: root/src/Network
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2017-06-07 05:57:20 -0400
committerjoe <joe@jerkface.net>2017-06-07 05:57:20 -0400
commit05345c643d0bcebe17f9474d9561da6e90fff34e (patch)
treec3ad0c1dd86a376b8c177fda57d5ef835e4efdf5 /src/Network
parenta4fe28f0cf95da88f5c2db4e3397c227625aa6ac (diff)
WIP: Adapting DHT to Tox network (part 4).
Diffstat (limited to 'src/Network')
-rw-r--r--src/Network/BitTorrent/DHT/Query.hs2
-rw-r--r--src/Network/DHT/Mainline.hs48
-rw-r--r--src/Network/KRPC/Manager.hs27
-rw-r--r--src/Network/RPC.hs52
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
115nodeHandler action = handler mainline $ \ sockAddr qry -> do 115nodeHandler 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 #-}
2module Network.DHT.Mainline where 4module Network.DHT.Mainline where
3 5
6import Network.Socket
4import Network.RPC 7import Network.RPC
5import Network.KRPC.Message 8import Network.KRPC.Message as KRPC
6import Data.BEncode as BE 9import Data.BEncode as BE
7import qualified Data.ByteString.Lazy as L 10import qualified Data.ByteString.Lazy as L
11import Network.BitTorrent.Address as BT (NodeId)
8 12
9mainline :: Messaging KMessageOf TransactionId BValue 13instance Envelope KMessageOf where
10mainline = 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
32instance 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
78import Data.Typeable 78import Data.Typeable
79import Network.RPC 79import Network.RPC
80import Network.KRPC.Message 80import Network.KRPC.Message
81import Network.KRPC.Method 81import Network.KRPC.Method hiding (Envelope)
82import qualified Network.KRPC.Method as KRPC (Envelope)
82import Network.Socket hiding (listen) 83import Network.Socket hiding (listen)
83import Network.Socket.ByteString as BS 84import Network.Socket.ByteString as BS
84import System.IO.Error 85import System.IO.Error
85import System.Timeout 86import System.Timeout
87import Network.DHT.Mainline
86 88
87 89
88{----------------------------------------------------------------------- 90{-----------------------------------------------------------------------
@@ -130,14 +132,14 @@ validateOptions Options {..}
130-- Options 132-- Options
131-----------------------------------------------------------------------} 133-----------------------------------------------------------------------}
132 134
133type KResult = Either KError KResponse 135type KResult = Either KError KMessage -- Response
134 136
135type TransactionCounter = IORef Int 137type TransactionCounter = IORef Int
136type CallId = (TransactionId, SockAddr) 138type CallId = (TransactionId, SockAddr)
137type CallRes = MVar (KQueryArgs, KResult) -- (raw response, decoded response) 139type CallRes = MVar (KQueryArgs, KResult) -- (raw response, decoded response)
138type PendingCalls = IORef (Map CallId CallRes) 140type PendingCalls = IORef (Map CallId CallRes)
139 141
140type HandlerBody h msg v = SockAddr -> msg v -> h (Either String v) 142type 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--
424handler :: forall h a b msg. (KRPC a b, Applicative h, Functor msg) 426handler :: 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
426handler msging body = (name, wrapper) 428handler 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
434runHandler :: MonadKRPC h m 437runHandler :: 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
555handleMessage :: MonadKRPC h m => KQueryArgs -> KMessage -> SockAddr -> m () 558handleMessage :: MonadKRPC h m => KQueryArgs -> KMessage -> SockAddr -> m ()
556handleMessage raw (Q q) = handleQuery raw q 559handleMessage raw (Q q) = handleQuery raw q
557handleMessage raw (R r) = handleResponse raw (Right r) 560handleMessage raw (R r) = handleResponse raw (Right (R r))
558handleMessage raw (E e) = handleResponse raw (Left e) 561handleMessage raw (E e) = handleResponse raw (Left e)
559#else 562#else
560handleMessage :: MonadKRPC h m => KQueryArgs -> Tox.Message BC.ByteString -> SockAddr -> m () 563handleMessage :: 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 #-}
2module Network.RPC where 8module Network.RPC where
3 9
4import Data.ByteString (ByteString) 10import Data.ByteString (ByteString)
11import Data.Kind (Constraint)
12import Data.Data
13import Network.Socket
5 14
6data MessageClass = Error | Query | Response 15data MessageClass = Error | Query | Response
7 deriving (Eq,Ord,Enum,Bounded,Show,Read) 16 deriving (Eq,Ord,Enum,Bounded,Data,Show,Read)
8 17
9data Messaging msg tid payload = Messaging 18class 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
39class 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