summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent/Tracker/List.hs
diff options
context:
space:
mode:
authorSam Truzjan <pxqr.sta@gmail.com>2014-03-24 04:56:25 +0400
committerSam Truzjan <pxqr.sta@gmail.com>2014-03-24 04:56:25 +0400
commitc09681431dfff9522eec70dc20042183e6dde119 (patch)
treeafdb021a38905750e6a454e2212cc309f2e99613 /src/Network/BitTorrent/Tracker/List.hs
parentb153806a0b9945e9ba3b82296ce0c39b627eb6b9 (diff)
Move trackerURI field to TrackerList
Diffstat (limited to 'src/Network/BitTorrent/Tracker/List.hs')
-rw-r--r--src/Network/BitTorrent/Tracker/List.hs76
1 files changed, 50 insertions, 26 deletions
diff --git a/src/Network/BitTorrent/Tracker/List.hs b/src/Network/BitTorrent/Tracker/List.hs
index 1e22f7ec..d92dd4ba 100644
--- a/src/Network/BitTorrent/Tracker/List.hs
+++ b/src/Network/BitTorrent/Tracker/List.hs
@@ -12,11 +12,13 @@
12{-# LANGUAGE FlexibleInstances #-} 12{-# LANGUAGE FlexibleInstances #-}
13module Network.BitTorrent.Tracker.List 13module Network.BitTorrent.Tracker.List
14 ( -- * Tracker list 14 ( -- * Tracker list
15 TrackerList 15 TierEntry
16 , TrackerList
16 17
17 -- * Construction 18 -- * Construction
18 , trackerList 19 , trackerList
19 , shuffleTiers 20 , shuffleTiers
21 , mapWithURI
20 22
21 -- * Traversals 23 -- * Traversals
22 , traverseAll 24 , traverseAll
@@ -24,10 +26,11 @@ module Network.BitTorrent.Tracker.List
24 ) where 26 ) where
25 27
26import Prelude hiding (mapM, foldr) 28import Prelude hiding (mapM, foldr)
29import Control.Arrow
27import Control.Applicative 30import Control.Applicative
28import Control.Exception 31import Control.Exception
29import Data.Default 32import Data.Default
30import Data.List as L (elem, any, filter, null) 33import Data.List as L (map, elem, any, filter, null)
31import Data.Maybe 34import Data.Maybe
32import Data.Foldable 35import Data.Foldable
33import Data.Traversable 36import Data.Traversable
@@ -41,31 +44,43 @@ import Network.BitTorrent.Tracker.RPC as RPC
41-- Tracker list datatype 44-- Tracker list datatype
42-----------------------------------------------------------------------} 45-----------------------------------------------------------------------}
43 46
44type Tier a = [a] 47type TierEntry a = (URI, a)
48type Tier a = [TierEntry a]
45 49
46-- | Tracker list is either a single tracker or list of tiers. All 50-- | Tracker list is either a single tracker or list of tiers. All
47-- trackers in each tier must be checked before the client goes on to 51-- trackers in each tier must be checked before the client goes on to
48-- the next tier. 52-- the next tier.
49data TrackerList a 53data TrackerList a
50 = Announce a -- ^ torrent file 'announce' field only 54 = Announce (TierEntry a) -- ^ torrent file 'announce' field only
51 | TierList [Tier a] -- ^ torrent file 'announce-list' field only 55 | TierList [Tier a] -- ^ torrent file 'announce-list' field only
52 deriving (Show, Eq) 56 deriving (Show, Eq)
53 57
54-- | Empty tracker list. Can be used for trackerless torrents. 58-- | Empty tracker list. Can be used for trackerless torrents.
55instance Default (TrackerList URI) where 59instance Default (TrackerList a) where
56 def = TierList [] 60 def = TierList []
57 61
58instance Functor TrackerList where 62instance Functor TrackerList where
59 fmap f (Announce a) = Announce (f a) 63 fmap f (Announce (uri, a)) = Announce (uri, f a)
60 fmap f (TierList a) = TierList (fmap (fmap f) a) 64 fmap f (TierList a) = TierList (fmap (fmap (second f)) a)
61 65
62instance Foldable TrackerList where 66instance Foldable TrackerList where
63 foldr f z (Announce a ) = f a z 67 foldr f z (Announce e ) = f (snd e) z
64 foldr f z (TierList xs) = foldr (flip (foldr f)) z xs 68 foldr f z (TierList xs) = foldr (flip (foldr (f . snd))) z xs
69
70_traverseEntry f (uri, a) = (,) uri <$> f a
65 71
66instance Traversable TrackerList where 72instance Traversable TrackerList where
67 traverse f (Announce a ) = Announce <$> f a 73 traverse f (Announce e ) = Announce <$> _traverseEntry f e
68 traverse f (TierList xs) = TierList <$> traverse (traverse f) xs 74 traverse f (TierList xs) =
75 TierList <$> traverse (traverse (_traverseEntry f)) xs
76
77traverseWithURI :: Applicative f
78 => (TierEntry a -> f b) -> TrackerList a -> f (TrackerList b)
79traverseWithURI f (Announce (uri, a)) = (Announce . (,) uri) <$> f (uri, a)
80traverseWithURI f (TierList xxs ) =
81 TierList <$> traverse (traverse (traverseEntry f)) xxs
82 where
83 traverseEntry f (uri, a) = (,) uri <$> f (uri, a)
69 84
70{----------------------------------------------------------------------- 85{-----------------------------------------------------------------------
71-- List extraction 86-- List extraction
@@ -102,10 +117,13 @@ fixList mxss mx = do
102 117
103-- | Extract set of trackers from torrent file. The 'tAnnounce' key is 118-- | Extract set of trackers from torrent file. The 'tAnnounce' key is
104-- only ignored if the 'tAnnounceList' key is present. 119-- only ignored if the 'tAnnounceList' key is present.
105trackerList :: Torrent -> TrackerList URI 120trackerList :: Torrent -> TrackerList ()
106trackerList Torrent {..} = fromMaybe (TierList []) $ do 121trackerList Torrent {..} = fromMaybe (TierList []) $ do
107 TierList <$> (tAnnounceList `fixList` tAnnounce) 122 (TierList . tierList) <$> (tAnnounceList `fixList` tAnnounce)
108 <|> Announce <$> tAnnounce 123 <|> (Announce . nullEntry) <$> tAnnounce
124 where
125 nullEntry uri = (uri, ())
126 tierList = L.map (L.map nullEntry)
109 127
110-- | Shuffle /order of trackers/ in each tier, preserving original 128-- | Shuffle /order of trackers/ in each tier, preserving original
111-- /order of tiers/. This can help to balance the load between the 129-- /order of tiers/. This can help to balance the load between the
@@ -114,6 +132,12 @@ shuffleTiers :: TrackerList a -> IO (TrackerList a)
114shuffleTiers (Announce a ) = return (Announce a) 132shuffleTiers (Announce a ) = return (Announce a)
115shuffleTiers (TierList xs) = TierList <$> mapM shuffleM xs 133shuffleTiers (TierList xs) = TierList <$> mapM shuffleM xs
116 134
135mapWithURI :: (URI -> a -> b) -> TrackerList a -> TrackerList b
136mapWithURI f (Announce (uri, a)) = Announce (uri, f uri a)
137mapWithURI f (TierList xs ) = TierList (L.map (L.map mapEntry) xs)
138 where
139 mapEntry (uri, a) = (uri, f uri a)
140
117{----------------------------------------------------------------------- 141{-----------------------------------------------------------------------
118-- Special traversals (suppressed RPC exceptions) 142-- Special traversals (suppressed RPC exceptions)
119-----------------------------------------------------------------------} 143-----------------------------------------------------------------------}
@@ -127,21 +151,21 @@ catchRPC a b = catch a (f b)
127throwRPC :: String -> IO a 151throwRPC :: String -> IO a
128throwRPC = throwIO . GenericException 152throwRPC = throwIO . GenericException
129 153
130-- | Like 'traverse' but ignore 'RpcExceptions'. 154-- | Like 'traverse' but ignores 'RpcExceptions'.
131traverseAll :: (a -> IO a) -> TrackerList a -> IO (TrackerList a) 155traverseAll :: (TierEntry a -> IO a) -> TrackerList a -> IO (TrackerList a)
132traverseAll action = traverse (action $?) 156traverseAll action = traverseWithURI (action $?)
133 where 157 where
134 f $? x = catchRPC (f x) (return x) 158 f $? x = catchRPC (f x) (return (snd x))
135 159
136-- | Like 'traverse' but put working trackers to the head of tiers. 160-- | Like 'traverse' but put working trackers to the head of tiers.
137-- This can help to avoid exceessive requests to not available 161-- This can help to avoid exceessive requests to not available
138-- trackers at each reannounce. If no one action succeed then original 162-- trackers at each reannounce. If no one action succeed then original
139-- list is returned. 163-- list is returned.
140traverseTiers :: (a -> IO a) -> TrackerList a -> IO (TrackerList a) 164traverseTiers :: (TierEntry a -> IO a) -> TrackerList a -> IO (TrackerList a)
141traverseTiers action ts = catchRPC (goList ts) (return ts) 165traverseTiers action ts = catchRPC (goList ts) (return ts)
142 where 166 where
143 goList (Announce a) = Announce <$> action a 167 goList tl @ (Announce _ ) = traverseWithURI action tl
144 goList (TierList tiers) = TierList <$> goTiers (goTier []) tiers 168 goList (TierList tiers) = TierList <$> goTiers (goTier []) tiers
145 169
146 goTiers _ [] = throwRPC "traverseTiers: no tiers" 170 goTiers _ [] = throwRPC "traverseTiers: no tiers"
147 goTiers f (x : xs) = catchRPC shortcut failback 171 goTiers f (x : xs) = catchRPC shortcut failback
@@ -155,10 +179,10 @@ traverseTiers action ts = catchRPC (goList ts) (return ts)
155 return (x : xs') 179 return (x : xs')
156 180
157 goTier _ [] = throwRPC "traverseTiers: no trackers in tier" 181 goTier _ [] = throwRPC "traverseTiers: no trackers in tier"
158 goTier failed (a : as) = catchRPC shortcut failback 182 goTier failed ((uri, a) : as) = catchRPC shortcut failback
159 where 183 where
160 shortcut = do 184 shortcut = do
161 a' <- action a 185 a' <- action (uri, a)
162 return (a' : as ++ failed) -- failed trackers at the end 186 return ((uri, a') : as ++ failed) -- failed trackers at the end
163 187
164 failback = goTier (a : failed) as 188 failback = goTier ((uri, a) : failed) as