diff options
author | Sam Truzjan <pxqr.sta@gmail.com> | 2013-12-28 18:30:44 +0400 |
---|---|---|
committer | Sam Truzjan <pxqr.sta@gmail.com> | 2013-12-28 18:30:44 +0400 |
commit | 4a46766d5fb0882151e80f9137983a8c2dfb7869 (patch) | |
tree | 62d49c7c00858377275f321a590e2c36b7577062 /src/Network | |
parent | 0e3ed097d12e5fb82b594265a1adb6096fe556b4 (diff) |
Add instance Alternative Routing
Diffstat (limited to 'src/Network')
-rw-r--r-- | src/Network/BitTorrent/DHT/Routing.hs | 33 | ||||
-rw-r--r-- | src/Network/BitTorrent/DHT/Session.hs | 27 |
2 files changed, 37 insertions, 23 deletions
diff --git a/src/Network/BitTorrent/DHT/Routing.hs b/src/Network/BitTorrent/DHT/Routing.hs index 984a61cc..af10513d 100644 --- a/src/Network/BitTorrent/DHT/Routing.hs +++ b/src/Network/BitTorrent/DHT/Routing.hs | |||
@@ -37,13 +37,12 @@ module Network.BitTorrent.DHT.Routing | |||
37 | , Network.BitTorrent.DHT.Routing.insert | 37 | , Network.BitTorrent.DHT.Routing.insert |
38 | ) where | 38 | ) where |
39 | 39 | ||
40 | import Control.Applicative hiding (empty) | 40 | import Control.Applicative as A |
41 | import Control.Arrow | 41 | import Control.Arrow |
42 | import Control.Monad | 42 | import Control.Monad |
43 | import Data.Function | 43 | import Data.Function |
44 | import Data.List as L hiding (insert) | 44 | import Data.List as L hiding (insert) |
45 | import Data.Maybe | 45 | import Data.Maybe |
46 | import Data.Monoid | ||
47 | import Data.PSQueue as PSQ | 46 | import Data.PSQueue as PSQ |
48 | import Data.Serialize as S hiding (Result, Done) | 47 | import Data.Serialize as S hiding (Result, Done) |
49 | import Data.Time | 48 | import Data.Time |
@@ -101,12 +100,14 @@ insert ping (k, v) = go 0 | |||
101 | type Timestamp = POSIXTime | 100 | type Timestamp = POSIXTime |
102 | 101 | ||
103 | data Routing ip result | 102 | data Routing ip result |
104 | = Done result | 103 | = Full |
104 | | Done result | ||
105 | | GetTime ( Timestamp -> Routing ip result) | 105 | | GetTime ( Timestamp -> Routing ip result) |
106 | | NeedPing (NodeAddr ip) ( Bool -> Routing ip result) | 106 | | NeedPing (NodeAddr ip) ( Bool -> Routing ip result) |
107 | | Refresh NodeId ([NodeInfo ip] -> Routing ip result) | 107 | | Refresh NodeId ([NodeInfo ip] -> Routing ip result) |
108 | 108 | ||
109 | instance Functor (Routing ip) where | 109 | instance Functor (Routing ip) where |
110 | fmap _ Full = Full | ||
110 | fmap f (Done r) = Done ( f r) | 111 | fmap f (Done r) = Done ( f r) |
111 | fmap f (GetTime g) = GetTime (fmap f . g) | 112 | fmap f (GetTime g) = GetTime (fmap f . g) |
112 | fmap f (NeedPing addr g) = NeedPing addr (fmap f . g) | 113 | fmap f (NeedPing addr g) = NeedPing addr (fmap f . g) |
@@ -115,20 +116,31 @@ instance Functor (Routing ip) where | |||
115 | instance Monad (Routing ip) where | 116 | instance Monad (Routing ip) where |
116 | return = Done | 117 | return = Done |
117 | 118 | ||
119 | Full >>= _ = Full | ||
118 | Done r >>= m = m r | 120 | Done r >>= m = m r |
119 | GetTime f >>= m = GetTime $ \ t -> f t >>= m | 121 | GetTime f >>= m = GetTime $ \ t -> f t >>= m |
120 | NeedPing a f >>= m = NeedPing a $ \ p -> f p >>= m | 122 | NeedPing a f >>= m = NeedPing a $ \ p -> f p >>= m |
121 | Refresh n f >>= m = Refresh n $ \ i -> f i >>= m | 123 | Refresh n f >>= m = Refresh n $ \ i -> f i >>= m |
122 | 124 | ||
125 | instance Applicative (Routing ip) where | ||
126 | pure = return | ||
127 | (<*>) = ap | ||
128 | |||
129 | instance Alternative (Routing ip) where | ||
130 | empty = Full | ||
131 | Full <|> m = m | ||
132 | m <|> _ = m | ||
133 | |||
123 | runRouting :: (Monad m, Eq ip) | 134 | runRouting :: (Monad m, Eq ip) |
124 | => (NodeAddr ip -> m Bool) -- ^ ping_node | 135 | => (NodeAddr ip -> m Bool) -- ^ ping_node |
125 | -> (NodeId -> m [NodeInfo ip]) -- ^ find_nodes | 136 | -> (NodeId -> m [NodeInfo ip]) -- ^ find_nodes |
126 | -> m Timestamp -- ^ timestamper | 137 | -> m Timestamp -- ^ timestamper |
127 | -> Routing ip f -- ^ action | 138 | -> Routing ip f -- ^ action |
128 | -> m f -- ^ result | 139 | -> m (Maybe f) -- ^ result |
129 | runRouting ping_node find_nodes timestamper = go | 140 | runRouting ping_node find_nodes timestamper = go |
130 | where | 141 | where |
131 | go (Done r) = return r | 142 | go Full = return (Nothing) |
143 | go (Done r) = return (Just r) | ||
132 | go (GetTime f) = do | 144 | go (GetTime f) = do |
133 | t <- timestamper | 145 | t <- timestamper |
134 | go (f t) | 146 | go (f t) |
@@ -231,7 +243,7 @@ insertBucket curTime info bucket | |||
231 | return $ PSQ.insert info curTime bucket | 243 | return $ PSQ.insert info curTime bucket |
232 | 244 | ||
233 | -- bucket is full of good nodes => ignore new node | 245 | -- bucket is full of good nodes => ignore new node |
234 | | otherwise = return bucket | 246 | | otherwise = A.empty |
235 | 247 | ||
236 | insertNode :: Eq ip => NodeInfo ip -> Bucket ip -> ip `Routing` Bucket ip | 248 | insertNode :: Eq ip => NodeInfo ip -> Bucket ip -> ip `Routing` Bucket ip |
237 | insertNode info bucket = do | 249 | insertNode info bucket = do |
@@ -348,8 +360,7 @@ insert info @ NodeInfo {..} = go (0 :: BitIx) | |||
348 | go i (One bucket table ) | 360 | go i (One bucket table ) |
349 | | testIdBit nodeId i = One bucket <$> go (succ i) table | 361 | | testIdBit nodeId i = One bucket <$> go (succ i) table |
350 | | otherwise = (`One` table) <$> insertNode info bucket | 362 | | otherwise = (`One` table) <$> insertNode info bucket |
351 | go i (Tip nid n bucket) = case insertNode info bucket of | 363 | go i (Tip nid n bucket) |
352 | Done kbucket | 364 | | n == 0 = Tip nid n <$> insertNode info bucket |
353 | | n == 0 -> Tip nid n <$> Done kbucket | 365 | | otherwise = Tip nid n <$> insertNode info bucket |
354 | | otherwise -> go (succ i) (splitTip nid n i kbucket) | 366 | <|> go (succ i) (splitTip nid n i bucket) |
355 | result -> Tip nid n <$> result | ||
diff --git a/src/Network/BitTorrent/DHT/Session.hs b/src/Network/BitTorrent/DHT/Session.hs index 9243ef49..9db5947a 100644 --- a/src/Network/BitTorrent/DHT/Session.hs +++ b/src/Network/BitTorrent/DHT/Session.hs | |||
@@ -33,7 +33,7 @@ module Network.BitTorrent.DHT.Session | |||
33 | 33 | ||
34 | import Control.Applicative | 34 | import Control.Applicative |
35 | import Control.Concurrent.STM | 35 | import Control.Concurrent.STM |
36 | import Control.Exception hiding (Handler) | 36 | import Control.Exception.Lifted hiding (Handler) |
37 | import Control.Monad.Base | 37 | import Control.Monad.Base |
38 | import Control.Monad.Logger | 38 | import Control.Monad.Logger |
39 | import Control.Monad.Reader | 39 | import Control.Monad.Reader |
@@ -145,15 +145,16 @@ runDHT naddr handlers action = runResourceT $ do | |||
145 | -----------------------------------------------------------------------} | 145 | -----------------------------------------------------------------------} |
146 | 146 | ||
147 | -- TODO fork? | 147 | -- TODO fork? |
148 | routing :: Address ip => Routing ip a -> DHT ip a | 148 | routing :: Address ip => Routing ip a -> DHT ip (Maybe a) |
149 | routing = runRouting ping refreshNodes getTimestamp | 149 | routing = runRouting ping refreshNodes getTimestamp |
150 | 150 | ||
151 | -- TODO add timeout | 151 | -- TODO add timeout |
152 | ping :: Address ip => NodeAddr ip -> DHT ip Bool | 152 | ping :: Address ip => NodeAddr ip -> DHT ip Bool |
153 | ping addr = do | 153 | ping addr = do |
154 | $(logDebugS) "routing.questionable_node" (T.pack (render (pretty addr))) | 154 | $(logDebugS) "routing.questionable_node" (T.pack (render (pretty addr))) |
155 | Ping <- Ping <@> addr | 155 | result <- try $ Ping <@> addr |
156 | return True | 156 | let _ = result :: Either SomeException Ping |
157 | return $ either (const False) (const True) result | ||
157 | 158 | ||
158 | -- FIXME do not use getClosest sinse we should /refresh/ them | 159 | -- FIXME do not use getClosest sinse we should /refresh/ them |
159 | refreshNodes :: Address ip => NodeId -> DHT ip [NodeInfo ip] | 160 | refreshNodes :: Address ip => NodeId -> DHT ip [NodeInfo ip] |
@@ -167,9 +168,9 @@ refreshNodes nid = do | |||
167 | 168 | ||
168 | getTimestamp :: DHT ip Timestamp | 169 | getTimestamp :: DHT ip Timestamp |
169 | getTimestamp = do | 170 | getTimestamp = do |
170 | timestamp <- liftIO $ getCurrentTime | 171 | utcTime <- liftIO $ getCurrentTime |
171 | $(logDebugS) "routing.make_timestamp" (T.pack (render (pretty timestamp))) | 172 | $(logDebugS) "routing.make_timestamp" (T.pack (render (pretty utcTime))) |
172 | return $ utcTimeToPOSIXSeconds timestamp | 173 | return $ utcTimeToPOSIXSeconds utcTime |
173 | 174 | ||
174 | {----------------------------------------------------------------------- | 175 | {----------------------------------------------------------------------- |
175 | -- Tokens | 176 | -- Tokens |
@@ -222,11 +223,13 @@ getClosestHash ih = kclosestHash 8 ih <$> getTable | |||
222 | insertNode :: Address ip => NodeInfo ip -> DHT ip () | 223 | insertNode :: Address ip => NodeInfo ip -> DHT ip () |
223 | insertNode info = do | 224 | insertNode info = do |
224 | t <- getTable | 225 | t <- getTable |
225 | t' <- routing (R.insert info t) | 226 | mt <- routing (R.insert info t) |
226 | putTable t' | 227 | case mt of |
227 | 228 | Nothing -> $(logDebugS) "insertNode" "Routing table is full" | |
228 | let logMsg = "Routing table updated: " <> pretty t <> " -> " <> pretty t' | 229 | Just t' -> do |
229 | $(logDebugS) "insertNode" (T.pack (render logMsg)) | 230 | putTable t' |
231 | let logMsg = "Routing table updated: " <> pretty t <> " -> " <> pretty t' | ||
232 | $(logDebugS) "insertNode" (T.pack (render logMsg)) | ||
230 | 233 | ||
231 | {----------------------------------------------------------------------- | 234 | {----------------------------------------------------------------------- |
232 | -- Peer storage | 235 | -- Peer storage |