diff options
Diffstat (limited to 'src/Network/BitTorrent/DHT/Routing.hs')
-rw-r--r-- | src/Network/BitTorrent/DHT/Routing.hs | 33 |
1 files changed, 22 insertions, 11 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 | ||