summaryrefslogtreecommitdiff
path: root/src/Network
diff options
context:
space:
mode:
authorSam Truzjan <pxqr.sta@gmail.com>2014-03-17 22:38:23 +0400
committerSam Truzjan <pxqr.sta@gmail.com>2014-03-17 22:38:23 +0400
commitba0c765b9e47335e2833f1ec72b3843792e0718d (patch)
tree643260d4c4f9a3c8ecfe287f96430e025eb41587 /src/Network
parentb7761dde5a330257d4cdacf3d8098caf552f6cce (diff)
Refactor single tracker session
Diffstat (limited to 'src/Network')
-rw-r--r--src/Network/BitTorrent/Tracker/Session.hs121
1 files changed, 63 insertions, 58 deletions
diff --git a/src/Network/BitTorrent/Tracker/Session.hs b/src/Network/BitTorrent/Tracker/Session.hs
index 33a46898..e13bc6f0 100644
--- a/src/Network/BitTorrent/Tracker/Session.hs
+++ b/src/Network/BitTorrent/Tracker/Session.hs
@@ -51,18 +51,9 @@ import Network.BitTorrent.Tracker.Message
51import Network.BitTorrent.Tracker.RPC as RPC 51import Network.BitTorrent.Tracker.RPC as RPC
52 52
53{----------------------------------------------------------------------- 53{-----------------------------------------------------------------------
54-- Tracker entry 54-- Single tracker session
55-----------------------------------------------------------------------} 55-----------------------------------------------------------------------}
56 56
57data LastScrape = LastScrape
58 { leechersCount :: Maybe Int
59 , seedersCount :: Maybe Int
60 } deriving (Show, Eq)
61
62-- | Tracker session starts with scrape unknown.
63instance Default LastScrape where
64 def = LastScrape Nothing Nothing
65
66-- | Status of this client. 57-- | Status of this client.
67data Status 58data Status
68 = Running -- ^ This client is announced and listenning for incoming 59 = Running -- ^ This client is announced and listenning for incoming
@@ -74,29 +65,14 @@ data Status
74instance Default Status where 65instance Default Status where
75 def = Paused 66 def = Paused
76 67
77-- | Client status after event announce succeed. 68-- | Tracker session starts with scrape unknown.
78nextStatus :: Maybe Event -> Status 69instance Default LastScrape where
79nextStatus Nothing = Running 70 def = LastScrape Nothing Nothing
80nextStatus (Just Started ) = Running
81nextStatus (Just Stopped ) = Paused
82nextStatus (Just Completed) = Running
83
84-- | Do we need to notify this /specific/ tracker?
85needNotify :: Maybe Event -> Maybe Status -> Bool
86needNotify Nothing _ = True
87needNotify (Just Started) Nothing = True
88needNotify (Just Stopped) Nothing = False
89needNotify (Just Completed) Nothing = False
90needNotify Nothing (Just Running) = True
91needNotify Nothing (Just Paused ) = True
92 71
93-- | Do we need to sent this event to a first working tracker or to 72data LastScrape = LastScrape
94-- the all known good trackers? 73 { leechersCount :: Maybe Int
95allNotify :: Maybe Event -> Bool 74 , seedersCount :: Maybe Int
96allNotify Nothing = False 75 } deriving (Show, Eq)
97allNotify (Just Started) = False
98allNotify (Just Stopped) = True
99allNotify (Just Completed) = True
100 76
101-- | Single tracker session. 77-- | Single tracker session.
102data TrackerEntry = TrackerEntry 78data TrackerEntry = TrackerEntry
@@ -113,9 +89,55 @@ data TrackerEntry = TrackerEntry
113 , scrapeCache :: Cached LastScrape 89 , scrapeCache :: Cached LastScrape
114 } 90 }
115 91
92-- | Single tracker session with empty state.
116nullEntry :: URI -> TrackerEntry 93nullEntry :: URI -> TrackerEntry
117nullEntry uri = TrackerEntry uri Nothing def def 94nullEntry uri = TrackerEntry uri Nothing def def
118 95
96-- | Do we need to notify this /specific/ tracker?
97needNotify :: Maybe Event -> Maybe Status -> Bool
98needNotify Nothing _ = True
99needNotify (Just Started) Nothing = True
100needNotify (Just Stopped) Nothing = False
101needNotify (Just Completed) Nothing = False
102needNotify Nothing (Just Running) = True
103needNotify Nothing (Just Paused ) = True
104
105-- | Client status after event announce succeed.
106nextStatus :: Maybe Event -> Status
107nextStatus Nothing = Running
108nextStatus (Just Started ) = Running
109nextStatus (Just Stopped ) = Paused
110nextStatus (Just Completed) = Running
111
112seconds :: Int -> NominalDiffTime
113seconds n = realToFrac (toEnum n :: Uni)
114
115cachePeers :: AnnounceInfo -> IO (Cached [PeerAddr IP])
116cachePeers AnnounceInfo {..} =
117 newCached (seconds respInterval)
118 (seconds (fromMaybe respInterval respMinInterval))
119 (getPeerList respPeers)
120
121cacheScrape :: AnnounceInfo -> IO (Cached LastScrape)
122cacheScrape AnnounceInfo {..} =
123 newCached (seconds respInterval)
124 (seconds (fromMaybe respInterval respMinInterval))
125 LastScrape
126 { seedersCount = respComplete
127 , leechersCount = respIncomplete
128 }
129
130-- | Make announce request to specific tracker returning new state.
131announceTo :: Manager -> InfoHash -> Maybe Event
132 -> TrackerEntry -> IO TrackerEntry
133announceTo mgr ih mevent entry @ TrackerEntry {..}
134 | mevent `needNotify` statusSent = do
135 let q = SAnnounceQuery ih def Nothing mevent
136 res <- RPC.announce mgr trackerURI q
137 TrackerEntry trackerURI (Just (nextStatus mevent))
138 <$> cachePeers res <*> cacheScrape res
139 | otherwise = return entry
140
119{----------------------------------------------------------------------- 141{-----------------------------------------------------------------------
120-- Multitracker Session 142-- Multitracker Session
121-----------------------------------------------------------------------} 143-----------------------------------------------------------------------}
@@ -157,41 +179,24 @@ withSession ih uris = bracket (newSession ih uris) closeSession
157getStatus :: Session -> IO Status 179getStatus :: Session -> IO Status
158getStatus Session {..} = takeMVar currentStatus 180getStatus Session {..} = takeMVar currentStatus
159 181
160seconds :: Int -> NominalDiffTime 182-- | Do we need to sent this event to a first working tracker or to
161seconds n = realToFrac (toEnum n :: Uni) 183-- the all known good trackers?
162 184allNotify :: Maybe Event -> Bool
163cachePeers :: AnnounceInfo -> IO (Cached [PeerAddr IP]) 185allNotify Nothing = False
164cachePeers AnnounceInfo {..} = 186allNotify (Just Started) = False
165 newCached (seconds respInterval) 187allNotify (Just Stopped) = True
166 (seconds (fromMaybe respInterval respMinInterval)) 188allNotify (Just Completed) = True
167 (getPeerList respPeers)
168
169cacheScrape :: AnnounceInfo -> IO (Cached LastScrape)
170cacheScrape AnnounceInfo {..} =
171 newCached (seconds respInterval)
172 (seconds (fromMaybe respInterval respMinInterval))
173 LastScrape
174 { seedersCount = respComplete
175 , leechersCount = respIncomplete
176 }
177 189
178announceAll :: Manager -> Session -> Maybe Event -> IO () 190announceAll :: Manager -> Session -> Maybe Event -> IO ()
179announceAll mgr Session {..} mevent = do 191announceAll mgr Session {..} mevent = do
180 modifyMVar_ trackers (traversal announceTo) 192 modifyMVar_ trackers (traversal (announceTo mgr infohash mevent))
181 where 193 where
182 traversal 194 traversal
183 | allNotify mevent = traverseAll 195 | allNotify mevent = traverseAll
184 | otherwise = traverseTiers 196 | otherwise = traverseTiers
185 197
186 announceTo entry @ TrackerEntry {..}
187 | mevent `needNotify` statusSent = do
188 let q = SAnnounceQuery infohash def Nothing mevent
189 res <- RPC.announce mgr trackerURI q
190 TrackerEntry trackerURI (Just (nextStatus mevent))
191 <$> cachePeers res <*> cacheScrape res
192 | otherwise = return entry
193
194-- TODO send notifications to tracker periodically. 198-- TODO send notifications to tracker periodically.
199-- TODO change 'currentStatus'
195-- | 200-- |
196-- 201--
197-- This function /may/ block until tracker query proceed. 202-- This function /may/ block until tracker query proceed.