diff options
author | Sam Truzjan <pxqr.sta@gmail.com> | 2014-03-24 04:56:25 +0400 |
---|---|---|
committer | Sam Truzjan <pxqr.sta@gmail.com> | 2014-03-24 04:56:25 +0400 |
commit | c09681431dfff9522eec70dc20042183e6dde119 (patch) | |
tree | afdb021a38905750e6a454e2212cc309f2e99613 /src/Network/BitTorrent/Tracker/List.hs | |
parent | b153806a0b9945e9ba3b82296ce0c39b627eb6b9 (diff) |
Move trackerURI field to TrackerList
Diffstat (limited to 'src/Network/BitTorrent/Tracker/List.hs')
-rw-r--r-- | src/Network/BitTorrent/Tracker/List.hs | 76 |
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 #-} |
13 | module Network.BitTorrent.Tracker.List | 13 | module 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 | ||
26 | import Prelude hiding (mapM, foldr) | 28 | import Prelude hiding (mapM, foldr) |
29 | import Control.Arrow | ||
27 | import Control.Applicative | 30 | import Control.Applicative |
28 | import Control.Exception | 31 | import Control.Exception |
29 | import Data.Default | 32 | import Data.Default |
30 | import Data.List as L (elem, any, filter, null) | 33 | import Data.List as L (map, elem, any, filter, null) |
31 | import Data.Maybe | 34 | import Data.Maybe |
32 | import Data.Foldable | 35 | import Data.Foldable |
33 | import Data.Traversable | 36 | import 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 | ||
44 | type Tier a = [a] | 47 | type TierEntry a = (URI, a) |
48 | type 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. |
49 | data TrackerList a | 53 | data 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. |
55 | instance Default (TrackerList URI) where | 59 | instance Default (TrackerList a) where |
56 | def = TierList [] | 60 | def = TierList [] |
57 | 61 | ||
58 | instance Functor TrackerList where | 62 | instance 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 | ||
62 | instance Foldable TrackerList where | 66 | instance 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 | ||
66 | instance Traversable TrackerList where | 72 | instance 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 | |||
77 | traverseWithURI :: Applicative f | ||
78 | => (TierEntry a -> f b) -> TrackerList a -> f (TrackerList b) | ||
79 | traverseWithURI f (Announce (uri, a)) = (Announce . (,) uri) <$> f (uri, a) | ||
80 | traverseWithURI 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. |
105 | trackerList :: Torrent -> TrackerList URI | 120 | trackerList :: Torrent -> TrackerList () |
106 | trackerList Torrent {..} = fromMaybe (TierList []) $ do | 121 | trackerList 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) | |||
114 | shuffleTiers (Announce a ) = return (Announce a) | 132 | shuffleTiers (Announce a ) = return (Announce a) |
115 | shuffleTiers (TierList xs) = TierList <$> mapM shuffleM xs | 133 | shuffleTiers (TierList xs) = TierList <$> mapM shuffleM xs |
116 | 134 | ||
135 | mapWithURI :: (URI -> a -> b) -> TrackerList a -> TrackerList b | ||
136 | mapWithURI f (Announce (uri, a)) = Announce (uri, f uri a) | ||
137 | mapWithURI 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) | |||
127 | throwRPC :: String -> IO a | 151 | throwRPC :: String -> IO a |
128 | throwRPC = throwIO . GenericException | 152 | throwRPC = throwIO . GenericException |
129 | 153 | ||
130 | -- | Like 'traverse' but ignore 'RpcExceptions'. | 154 | -- | Like 'traverse' but ignores 'RpcExceptions'. |
131 | traverseAll :: (a -> IO a) -> TrackerList a -> IO (TrackerList a) | 155 | traverseAll :: (TierEntry a -> IO a) -> TrackerList a -> IO (TrackerList a) |
132 | traverseAll action = traverse (action $?) | 156 | traverseAll 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. |
140 | traverseTiers :: (a -> IO a) -> TrackerList a -> IO (TrackerList a) | 164 | traverseTiers :: (TierEntry a -> IO a) -> TrackerList a -> IO (TrackerList a) |
141 | traverseTiers action ts = catchRPC (goList ts) (return ts) | 165 | traverseTiers 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 |