summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent/DHT/ContactInfo.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/BitTorrent/DHT/ContactInfo.hs')
-rw-r--r--src/Network/BitTorrent/DHT/ContactInfo.hs58
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 @@
1module Network.BitTorrent.DHT.ContactInfo 1module 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
8import Control.Applicative
7import Data.Default 9import Data.Default
8import Data.List as L 10import Data.List as L
9import Data.Maybe 11import Data.Maybe
10import Data.HashMap.Strict as HM 12import Data.HashMap.Strict as HM
11import Data.Serialize 13import Data.Serialize
14import Data.PSQueue as PSQ
15import Data.Time.Clock.POSIX
16import Data.ByteString (ByteString)
12 17
13import Data.Torrent 18import Data.Torrent
14import Network.BitTorrent.Address 19import 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.
110newtype PeerStore ip = PeerStore (HashMap InfoHash [PeerAddr ip]) 115newtype PeerStore ip = PeerStore (HashMap InfoHash (SwarmData ip))
116
117type Timestamp = POSIXTime
118
119data SwarmData ip = SwarmData
120 { peers :: PSQ (PeerAddr ip) Timestamp
121 , name :: Maybe ByteString
122 }
123
124knownSwarms :: PeerStore ip -> [ (InfoHash, Int, Maybe ByteString) ]
125knownSwarms (PeerStore m) = L.map (\(ih,SwarmData q n) -> (ih,PSQ.size q,n)) $ HM.toList m
126
127swarmSinglton :: Ord ip => PeerAddr ip -> SwarmData ip
128swarmSinglton a = SwarmData
129 { peers = PSQ.singleton a 0
130 , name = Nothing }
131
132swarmInsert :: Ord ip => SwarmData ip -> SwarmData ip -> SwarmData ip
133swarmInsert 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.
113instance Default (PeerStore a) where 140instance 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.
118instance 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.
133lookup :: InfoHash -> PeerStore a -> [PeerAddr a] 160lookup :: Ord a => InfoHash -> PeerStore a -> [PeerAddr a]
134lookup ih (PeerStore m) = fromMaybe [] $ HM.lookup ih m 161lookup 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.
137insert :: Eq a => InfoHash -> PeerAddr a -> PeerStore a -> PeerStore a 164insertPeer :: Ord a => InfoHash -> Maybe ByteString -> PeerAddr a -> PeerStore a -> PeerStore a
138insert ih a (PeerStore m) = PeerStore (HM.insertWith L.union ih [a] m) 165insertPeer 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 }