diff options
author | joe <joe@jerkface.net> | 2017-01-23 07:04:42 -0500 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-01-23 07:04:42 -0500 |
commit | e6c068447a1ba88eb1805f9397657ef45a9eda2f (patch) | |
tree | fa52cb81ee58fae82cccaff4c8299fe770ae7377 /src/Network/BitTorrent/DHT/ContactInfo.hs | |
parent | d2adf592c46afa0f8c0640dec4715ee74f4776ca (diff) |
PeerStore is now persistent.
Diffstat (limited to 'src/Network/BitTorrent/DHT/ContactInfo.hs')
-rw-r--r-- | src/Network/BitTorrent/DHT/ContactInfo.hs | 59 |
1 files changed, 48 insertions, 11 deletions
diff --git a/src/Network/BitTorrent/DHT/ContactInfo.hs b/src/Network/BitTorrent/DHT/ContactInfo.hs index 4302288c..117325fc 100644 --- a/src/Network/BitTorrent/DHT/ContactInfo.hs +++ b/src/Network/BitTorrent/DHT/ContactInfo.hs | |||
@@ -15,6 +15,8 @@ import Data.Serialize | |||
15 | import Data.PSQueue as PSQ | 15 | import Data.PSQueue as PSQ |
16 | import Data.Time.Clock.POSIX | 16 | import Data.Time.Clock.POSIX |
17 | import Data.ByteString (ByteString) | 17 | import Data.ByteString (ByteString) |
18 | import Data.Word | ||
19 | import Network.Socket (SockAddr(..)) | ||
18 | 20 | ||
19 | import Data.Torrent | 21 | import Data.Torrent |
20 | import Network.BitTorrent.Address | 22 | import Network.BitTorrent.Address |
@@ -122,6 +124,40 @@ data SwarmData ip = SwarmData | |||
122 | , name :: Maybe ByteString | 124 | , name :: Maybe ByteString |
123 | } | 125 | } |
124 | 126 | ||
127 | |||
128 | newtype SerializeAddress a = SerializeAddress { unserializeAddress :: a } | ||
129 | |||
130 | instance Address a => Serialize (SerializeAddress a) where | ||
131 | get = SerializeAddress <$> do | ||
132 | c <- get | ||
133 | case (c::Word8) of | ||
134 | 0x34 -> do ip4 <- get | ||
135 | return $ fromJust $ fromAddr (ip4::IPv4) | ||
136 | 0x36 -> do ip6 <- get | ||
137 | return $ fromJust $ fromAddr (ip6::IPv6) | ||
138 | _ -> return $ error "cannot deserialize non-IP SerializeAddress" | ||
139 | put (SerializeAddress a) | ||
140 | | Just ip4 <- fromAddr a | ||
141 | = put (0x34::Word8) >> put (ip4::IPv4) | ||
142 | | Just ip6 <- fromAddr a | ||
143 | = put (0x36::Word8) >> put (ip6::IPv6) | ||
144 | | otherwise = return $ error "cannot serialize non-IP SerializeAddress" | ||
145 | |||
146 | |||
147 | instance (Ord ip, Address ip) => Serialize (SwarmData ip) where | ||
148 | get = flip SwarmData <$> get | ||
149 | <*> ( PSQ.fromList . L.map parseAddr <$> get ) | ||
150 | where | ||
151 | parseAddr addr = (unserializeAddress <$> addr) | ||
152 | :-> 0 | ||
153 | |||
154 | put SwarmData{..} = do | ||
155 | put name | ||
156 | put $ L.map (\(addr :-> _) -> (SerializeAddress <$> addr)) | ||
157 | -- XXX: should we serialize the timestamp? | ||
158 | $ PSQ.toList peers | ||
159 | |||
160 | |||
125 | knownSwarms :: PeerStore ip -> [ (InfoHash, Int, Maybe ByteString) ] | 161 | knownSwarms :: PeerStore ip -> [ (InfoHash, Int, Maybe ByteString) ] |
126 | knownSwarms (PeerStore m) = L.map (\(ih,SwarmData q n) -> (ih,PSQ.size q,n)) $ HM.toList m | 162 | knownSwarms (PeerStore m) = L.map (\(ih,SwarmData q n) -> (ih,PSQ.size q,n)) $ HM.toList m |
127 | 163 | ||
@@ -136,26 +172,27 @@ swarmInsert old new = SwarmData | |||
136 | , name = name new <|> name old -- TODO: decodeUtf8' check | 172 | , name = name new <|> name old -- TODO: decodeUtf8' check |
137 | } | 173 | } |
138 | 174 | ||
175 | isSwarmOccupied SwarmData{..} = not $ PSQ.null peers | ||
139 | 176 | ||
140 | -- | Empty store. | 177 | -- | Empty store. |
141 | instance Default (PeerStore a) where | 178 | instance Default (PeerStore a) where |
142 | def = PeerStore HM.empty | 179 | def = PeerStore HM.empty |
143 | {-# INLINE def #-} | 180 | {-# INLINE def #-} |
144 | 181 | ||
145 | -- -- | Monoid under union operation. | 182 | -- | Monoid under union operation. |
146 | -- instance Eq a => Monoid (PeerStore a) where | 183 | instance Ord a => Monoid (PeerStore a) where |
147 | -- mempty = def | 184 | mempty = def |
148 | -- {-# INLINE mempty #-} | 185 | {-# INLINE mempty #-} |
149 | -- | 186 | |
150 | -- mappend (PeerStore a) (PeerStore b) = | 187 | mappend (PeerStore a) (PeerStore b) = |
151 | -- PeerStore (HM.unionWith L.union a b) | 188 | PeerStore (HM.unionWith swarmInsert a b) |
152 | -- {-# INLINE mappend #-} | 189 | {-# INLINE mappend #-} |
153 | 190 | ||
154 | -- | Can be used to store peers between invocations of the client | 191 | -- | Can be used to store peers between invocations of the client |
155 | -- software. | 192 | -- software. |
156 | instance Serialize (PeerStore a) where | 193 | instance (Ord a, Address a) => Serialize (PeerStore a) where |
157 | get = undefined | 194 | get = PeerStore . HM.fromList <$> get |
158 | put = undefined | 195 | put (PeerStore m) = put (L.filter (isSwarmOccupied . snd) $ HM.toList m) |
159 | 196 | ||
160 | -- | Returns all peers associated with a given info hash. | 197 | -- | Returns all peers associated with a given info hash. |
161 | lookup :: Ord a => InfoHash -> PeerStore a -> [PeerAddr a] | 198 | lookup :: Ord a => InfoHash -> PeerStore a -> [PeerAddr a] |