diff options
Diffstat (limited to 'src/Network/BitTorrent/DHT/ContactInfo.hs')
-rw-r--r-- | src/Network/BitTorrent/DHT/ContactInfo.hs | 58 |
1 files changed, 44 insertions, 14 deletions
diff --git a/src/Network/BitTorrent/DHT/ContactInfo.hs b/src/Network/BitTorrent/DHT/ContactInfo.hs index d7c92e35..979dbb62 100644 --- a/src/Network/BitTorrent/DHT/ContactInfo.hs +++ b/src/Network/BitTorrent/DHT/ContactInfo.hs | |||
@@ -1,14 +1,19 @@ | |||
1 | module Network.BitTorrent.DHT.ContactInfo | 1 | module Network.BitTorrent.DHT.ContactInfo |
2 | ( PeerStore | 2 | ( PeerStore |
3 | , Network.BitTorrent.DHT.ContactInfo.lookup | 3 | , Network.BitTorrent.DHT.ContactInfo.lookup |
4 | , Network.BitTorrent.DHT.ContactInfo.insert | 4 | , Network.BitTorrent.DHT.ContactInfo.insertPeer |
5 | , knownSwarms | ||
5 | ) where | 6 | ) where |
6 | 7 | ||
8 | import Control.Applicative | ||
7 | import Data.Default | 9 | import Data.Default |
8 | import Data.List as L | 10 | import Data.List as L |
9 | import Data.Maybe | 11 | import Data.Maybe |
10 | import Data.HashMap.Strict as HM | 12 | import Data.HashMap.Strict as HM |
11 | import Data.Serialize | 13 | import Data.Serialize |
14 | import Data.PSQueue as PSQ | ||
15 | import Data.Time.Clock.POSIX | ||
16 | import Data.ByteString (ByteString) | ||
12 | 17 | ||
13 | import Data.Torrent | 18 | import Data.Torrent |
14 | import Network.BitTorrent.Address | 19 | import Network.BitTorrent.Address |
@@ -107,21 +112,43 @@ import Network.BitTorrent.Address | |||
107 | 112 | ||
108 | -- | Storage used to keep track a set of known peers in client, | 113 | -- | Storage used to keep track a set of known peers in client, |
109 | -- tracker or DHT sessions. | 114 | -- tracker or DHT sessions. |
110 | newtype PeerStore ip = PeerStore (HashMap InfoHash [PeerAddr ip]) | 115 | newtype PeerStore ip = PeerStore (HashMap InfoHash (SwarmData ip)) |
116 | |||
117 | type Timestamp = POSIXTime | ||
118 | |||
119 | data SwarmData ip = SwarmData | ||
120 | { peers :: PSQ (PeerAddr ip) Timestamp | ||
121 | , name :: Maybe ByteString | ||
122 | } | ||
123 | |||
124 | knownSwarms :: PeerStore ip -> [ (InfoHash, Int, Maybe ByteString) ] | ||
125 | knownSwarms (PeerStore m) = L.map (\(ih,SwarmData q n) -> (ih,PSQ.size q,n)) $ HM.toList m | ||
126 | |||
127 | swarmSinglton :: Ord ip => PeerAddr ip -> SwarmData ip | ||
128 | swarmSinglton a = SwarmData | ||
129 | { peers = PSQ.singleton a 0 | ||
130 | , name = Nothing } | ||
131 | |||
132 | swarmInsert :: Ord ip => SwarmData ip -> SwarmData ip -> SwarmData ip | ||
133 | swarmInsert old new = SwarmData | ||
134 | { peers = L.foldl' (\q (a :-> t) -> PSQ.insertWith (\p _ -> p) a t q) (peers old) (PSQ.toList $ peers new) | ||
135 | , name = name new <|> name old -- TODO: decodeUtf8' check | ||
136 | } | ||
137 | |||
111 | 138 | ||
112 | -- | Empty store. | 139 | -- | Empty store. |
113 | instance Default (PeerStore a) where | 140 | instance Default (PeerStore a) where |
114 | def = PeerStore HM.empty | 141 | def = PeerStore HM.empty |
115 | {-# INLINE def #-} | 142 | {-# INLINE def #-} |
116 | 143 | ||
117 | -- | Monoid under union operation. | 144 | -- -- | Monoid under union operation. |
118 | instance Eq a => Monoid (PeerStore a) where | 145 | -- instance Eq a => Monoid (PeerStore a) where |
119 | mempty = def | 146 | -- mempty = def |
120 | {-# INLINE mempty #-} | 147 | -- {-# INLINE mempty #-} |
121 | 148 | -- | |
122 | mappend (PeerStore a) (PeerStore b) = | 149 | -- mappend (PeerStore a) (PeerStore b) = |
123 | PeerStore (HM.unionWith L.union a b) | 150 | -- PeerStore (HM.unionWith L.union a b) |
124 | {-# INLINE mappend #-} | 151 | -- {-# INLINE mappend #-} |
125 | 152 | ||
126 | -- | Can be used to store peers between invocations of the client | 153 | -- | Can be used to store peers between invocations of the client |
127 | -- software. | 154 | -- software. |
@@ -130,9 +157,12 @@ instance Serialize (PeerStore a) where | |||
130 | put = undefined | 157 | put = undefined |
131 | 158 | ||
132 | -- | Used in 'get_peers' DHT queries. | 159 | -- | Used in 'get_peers' DHT queries. |
133 | lookup :: InfoHash -> PeerStore a -> [PeerAddr a] | 160 | lookup :: Ord a => InfoHash -> PeerStore a -> [PeerAddr a] |
134 | lookup ih (PeerStore m) = fromMaybe [] $ HM.lookup ih m | 161 | lookup ih (PeerStore m) = maybe [] (PSQ.keys . peers) $ HM.lookup ih m |
135 | 162 | ||
136 | -- | Used in 'announce_peer' DHT queries. | 163 | -- | Used in 'announce_peer' DHT queries. |
137 | insert :: Eq a => InfoHash -> PeerAddr a -> PeerStore a -> PeerStore a | 164 | insertPeer :: Ord a => InfoHash -> Maybe ByteString -> PeerAddr a -> PeerStore a -> PeerStore a |
138 | insert ih a (PeerStore m) = PeerStore (HM.insertWith L.union ih [a] m) | 165 | insertPeer ih name a (PeerStore m) = PeerStore (HM.insertWith swarmInsert ih a' m) |
166 | where | ||
167 | a' = SwarmData { peers = PSQ.singleton a 0 | ||
168 | , name = name } | ||