summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Network/BitTorrent/Peer.hs88
-rw-r--r--src/Network/BitTorrent/Sessions/Types.lhs58
-rw-r--r--src/Network/BitTorrent/Tracker.hs5
-rw-r--r--src/Network/BitTorrent/Tracker/Protocol.hs32
m---------sub/bencoding0
5 files changed, 96 insertions, 87 deletions
diff --git a/src/Network/BitTorrent/Peer.hs b/src/Network/BitTorrent/Peer.hs
index a4d026dc..d951a1cd 100644
--- a/src/Network/BitTorrent/Peer.hs
+++ b/src/Network/BitTorrent/Peer.hs
@@ -28,6 +28,7 @@
28-- capabilities (such as supported enchancements), this should be 28-- capabilities (such as supported enchancements), this should be
29-- done using 'Network.BitTorrent.Extension'! 29-- done using 'Network.BitTorrent.Extension'!
30-- 30--
31{-# LANGUAGE ViewPatterns #-}
31{-# LANGUAGE GeneralizedNewtypeDeriving #-} 32{-# LANGUAGE GeneralizedNewtypeDeriving #-}
32{-# LANGUAGE StandaloneDeriving #-} 33{-# LANGUAGE StandaloneDeriving #-}
33{-# LANGUAGE TemplateHaskell #-} 34{-# LANGUAGE TemplateHaskell #-}
@@ -56,6 +57,19 @@ module Network.BitTorrent.Peer
56 , connectToPeer 57 , connectToPeer
57 , ppPeer 58 , ppPeer
58 59
60 -- * Peer progress
61 , Progress (..)
62 , left
63 , uploaded
64 , downloaded
65
66 , startProgress
67
68 , downloadedProgress
69 , enqueuedProgress
70 , uploadedProgress
71 , dequeuedProgress
72
59 -- * Client version detection 73 -- * Client version detection
60 -- ** Info 74 -- ** Info
61 , ClientInfo(..), clientInfo, ppClientInfo, unknownClient 75 , ClientInfo(..), clientInfo, ppClientInfo, unknownClient
@@ -70,18 +84,19 @@ module Network.BitTorrent.Peer
70 84
71 85
72import Control.Applicative 86import Control.Applicative
87import Control.Lens
73import Data.Aeson 88import Data.Aeson
74import Data.Aeson.TH 89import Data.Aeson.TH
75import Data.BEncode 90import Data.BEncode
76import Data.Bits 91import Data.Bits
77import Data.Char
78import Data.List as L
79import Data.Word
80import Data.ByteString (ByteString) 92import Data.ByteString (ByteString)
81import qualified Data.ByteString as B 93import qualified Data.ByteString as B
82import qualified Data.ByteString.Char8 as BC 94import qualified Data.ByteString.Char8 as BC
83import qualified Data.ByteString.Lazy as BL 95import qualified Data.ByteString.Lazy as BL
84import qualified Data.ByteString.Lazy.Builder as B 96import qualified Data.ByteString.Lazy.Builder as B
97import Data.Char
98import Data.List as L
99import Data.Word
85import Data.Foldable (foldMap) 100import Data.Foldable (foldMap)
86import Data.Monoid ((<>)) 101import Data.Monoid ((<>))
87import Data.Serialize 102import Data.Serialize
@@ -577,3 +592,70 @@ ppPeer p @ PeerAddr {..} = case peerID of
577 Nothing -> paddr 592 Nothing -> paddr
578 where 593 where
579 paddr = text (show (peerSockAddr p)) 594 paddr = text (show (peerSockAddr p))
595
596{-----------------------------------------------------------------------
597 Progress
598-----------------------------------------------------------------------}
599
600-- TODO: Use Word64?
601-- TODO: Use atomic bits?
602
603-- | 'Progress' contains upload/download/left stats about
604-- current client state and used to notify the tracker.
605--
606-- Progress data is considered as dynamic within one client
607-- session. This data also should be shared across client application
608-- sessions (e.g. files), otherwise use 'startProgress' to get initial
609-- 'Progress'.
610--
611data Progress = Progress
612 { _downloaded :: !Integer -- ^ Total amount of bytes downloaded;
613 , _left :: !Integer -- ^ Total amount of bytes left;
614 , _uploaded :: !Integer -- ^ Total amount of bytes uploaded.
615 } deriving (Show, Read, Eq)
616
617$(makeLenses ''Progress)
618$(deriveJSON (L.tail) ''Progress)
619
620instance Serialize Progress where
621 put Progress {..} = do
622 putWord64be $ fromIntegral _downloaded
623 putWord64be $ fromIntegral _left
624 putWord64be $ fromIntegral _uploaded
625
626 get = Progress
627 <$> (fromIntegral <$> getWord64be)
628 <*> (fromIntegral <$> getWord64be)
629 <*> (fromIntegral <$> getWord64be)
630
631-- | Initial progress is used when there are no session before.
632--
633-- Please note that tracker might penalize client some way if the do
634-- not accumulate progress. If possible and save 'Progress' between
635-- client sessions to avoid that.
636--
637startProgress :: Integer -> Progress
638startProgress = Progress 0 0
639
640-- | Used when the client download some data from /any/ peer.
641downloadedProgress :: Int -> Progress -> Progress
642downloadedProgress (fromIntegral -> amount)
643 = (left -~ amount)
644 . (downloaded +~ amount)
645{-# INLINE downloadedProgress #-}
646
647-- | Used when the client upload some data to /any/ peer.
648uploadedProgress :: Int -> Progress -> Progress
649uploadedProgress (fromIntegral -> amount) = uploaded +~ amount
650{-# INLINE uploadedProgress #-}
651
652-- | Used when leecher join client session.
653enqueuedProgress :: Integer -> Progress -> Progress
654enqueuedProgress amount = left +~ amount
655{-# INLINE enqueuedProgress #-}
656
657-- | Used when leecher leave client session.
658-- (e.g. user deletes not completed torrent)
659dequeuedProgress :: Integer -> Progress -> Progress
660dequeuedProgress amount = left -~ amount
661{-# INLINE dequeuedProgress #-}
diff --git a/src/Network/BitTorrent/Sessions/Types.lhs b/src/Network/BitTorrent/Sessions/Types.lhs
index 3dde1853..7ee7cbec 100644
--- a/src/Network/BitTorrent/Sessions/Types.lhs
+++ b/src/Network/BitTorrent/Sessions/Types.lhs
@@ -17,11 +17,6 @@
17> , TorrentLoc (..) 17> , TorrentLoc (..)
18> , TorrentMap 18> , TorrentMap
19> 19>
20> , Progress (..)
21> , left, uploaded, downloaded
22> , startProgress
23> , enqueuedProgress, uploadedProgress, dequeuedProgress
24>
25> , ClientSession (..) 20> , ClientSession (..)
26> 21>
27> , SwarmSession (..) 22> , SwarmSession (..)
@@ -65,7 +60,6 @@
65> import Network.BitTorrent.Extension 60> import Network.BitTorrent.Extension
66> import Network.BitTorrent.Peer 61> import Network.BitTorrent.Peer
67> import Network.BitTorrent.Exchange.Protocol as BT 62> import Network.BitTorrent.Exchange.Protocol as BT
68> import Network.BitTorrent.Tracker.Protocol as BT
69> import System.Torrent.Storage 63> import System.Torrent.Storage
70 64
71Thread layout 65Thread layout
@@ -173,58 +167,6 @@ so we need to do this on demand: if a peer asks for a block, we
173validate corresponding piece and only after read and send the block 167validate corresponding piece and only after read and send the block
174back. 168back.
175 169
176Progress
177------------------------------------------------------------------------
178
179Progress data is considered as dynamic within one client session. This
180data also should be shared across client application sessions
181(e.g. files), otherwise use 'startProgress' to get initial 'Progress'.
182
183> -- | 'Progress' contains upload/download/left stats about
184> -- current client state and used to notify the tracker.
185> data Progress = Progress {
186> _uploaded :: !Integer -- ^ Total amount of bytes uploaded.
187> , _downloaded :: !Integer -- ^ Total amount of bytes downloaded.
188> , _left :: !Integer -- ^ Total amount of bytes left.
189> } deriving (Show, Read, Eq)
190>
191> $(makeLenses ''Progress)
192
193**TODO:** Use Word64?
194
195**TODO:** Use atomic bits?
196
197Please note that tracker might penalize client some way if the do
198not accumulate progress. If possible and save 'Progress' between
199client sessions to avoid that.
200
201> -- | Initial progress is used when there are no session before.
202> startProgress :: Integer -> Progress
203> startProgress = Progress 0 0
204
205> -- | Used when the client download some data from /any/ peer.
206> downloadedProgress :: Int -> Progress -> Progress
207> downloadedProgress (fromIntegral -> amount)
208> = (left -~ amount)
209> . (downloaded +~ amount)
210> {-# INLINE downloadedProgress #-}
211
212> -- | Used when the client upload some data to /any/ peer.
213> uploadedProgress :: Int -> Progress -> Progress
214> uploadedProgress (fromIntegral -> amount) = uploaded +~ amount
215> {-# INLINE uploadedProgress #-}
216
217> -- | Used when leecher join client session.
218> enqueuedProgress :: Integer -> Progress -> Progress
219> enqueuedProgress amount = left +~ amount
220> {-# INLINE enqueuedProgress #-}
221
222> -- | Used when leecher leave client session.
223> -- (e.g. user deletes not completed torrent)
224> dequeuedProgress :: Integer -> Progress -> Progress
225> dequeuedProgress amount = left -~ amount
226> {-# INLINE dequeuedProgress #-}
227
228Client Sessions 170Client Sessions
229------------------------------------------------------------------------ 171------------------------------------------------------------------------
230 172
diff --git a/src/Network/BitTorrent/Tracker.hs b/src/Network/BitTorrent/Tracker.hs
index e98f1e94..c707cedd 100644
--- a/src/Network/BitTorrent/Tracker.hs
+++ b/src/Network/BitTorrent/Tracker.hs
@@ -41,7 +41,6 @@ import Network.URI
41 41
42import Data.Torrent.Metainfo 42import Data.Torrent.Metainfo
43import Network.BitTorrent.Peer 43import Network.BitTorrent.Peer
44import Network.BitTorrent.Sessions.Types
45import Network.BitTorrent.Tracker.Protocol 44import Network.BitTorrent.Tracker.Protocol
46import Network.BitTorrent.Tracker.HTTP 45import Network.BitTorrent.Tracker.HTTP
47 46
@@ -73,9 +72,7 @@ genericReq ses pr = AnnounceQuery {
73 , reqPeerId = tconnPeerId ses 72 , reqPeerId = tconnPeerId ses
74 , reqPort = tconnPort ses 73 , reqPort = tconnPort ses
75 74
76 , reqUploaded = _uploaded pr 75 , reqProgress = pr
77 , reqDownloaded = _downloaded pr
78 , reqLeft = _left pr
79 76
80 , reqIP = Nothing 77 , reqIP = Nothing
81 , reqNumWant = Nothing 78 , reqNumWant = Nothing
diff --git a/src/Network/BitTorrent/Tracker/Protocol.hs b/src/Network/BitTorrent/Tracker/Protocol.hs
index e7755a10..3f264aed 100644
--- a/src/Network/BitTorrent/Tracker/Protocol.hs
+++ b/src/Network/BitTorrent/Tracker/Protocol.hs
@@ -63,6 +63,7 @@ import Network
63import Network.Socket 63import Network.Socket
64 64
65import Network.BitTorrent.Peer 65import Network.BitTorrent.Peer
66import Network.BitTorrent.Sessions.Types
66 67
67{----------------------------------------------------------------------- 68{-----------------------------------------------------------------------
68 Announce messages 69 Announce messages
@@ -97,14 +98,8 @@ data AnnounceQuery = AnnounceQuery {
97 -- peers. Normally, tracker should respond with this port when 98 -- peers. Normally, tracker should respond with this port when
98 -- some peer request the tracker with the same info hash. 99 -- some peer request the tracker with the same info hash.
99 100
100 , reqUploaded :: !Integer 101 , reqProgress :: !Progress
101 -- ^ Number of bytes that the peer has uploaded in the swarm. 102 -- ^ Current progress of peer doing request.
102
103 , reqDownloaded :: !Integer
104 -- ^ Number of bytes downloaded in the swarm by the peer.
105
106 , reqLeft :: !Integer
107 -- ^ Number of bytes needed in order to complete download.
108 103
109 , reqIP :: Maybe HostAddress 104 , reqIP :: Maybe HostAddress
110 -- ^ The peer IP. Needed only when client communicated with 105 -- ^ The peer IP. Needed only when client communicated with
@@ -213,9 +208,9 @@ instance URLEncode AnnounceQuery where
213 urlEncode AnnounceQuery {..} = mconcat 208 urlEncode AnnounceQuery {..} = mconcat
214 [ s "peer_id" %= reqPeerId 209 [ s "peer_id" %= reqPeerId
215 , s "port" %= reqPort 210 , s "port" %= reqPort
216 , s "uploaded" %= reqUploaded 211 , s "uploaded" %= _uploaded reqProgress
217 , s "downloaded" %= reqDownloaded 212 , s "left" %= _left reqProgress
218 , s "left" %= reqLeft 213 , s "downloaded" %= _downloaded reqProgress
219 , s "ip" %=? reqIP 214 , s "ip" %=? reqIP
220 , s "numwant" %=? reqNumWant 215 , s "numwant" %=? reqNumWant
221 , s "event" %=? reqEvent 216 , s "event" %=? reqEvent
@@ -248,15 +243,12 @@ getEvent = do
248 3 -> return $ Just Stopped 243 3 -> return $ Just Stopped
249 _ -> fail "unknown event id" 244 _ -> fail "unknown event id"
250 245
246
251instance Serialize AnnounceQuery where 247instance Serialize AnnounceQuery where
252 put AnnounceQuery {..} = do 248 put AnnounceQuery {..} = do
253 put reqInfoHash 249 put reqInfoHash
254 put reqPeerId 250 put reqPeerId
255 251 put reqProgress
256 putWord64be $ fromIntegral reqDownloaded
257 putWord64be $ fromIntegral reqLeft
258 putWord64be $ fromIntegral reqUploaded
259
260 putEvent reqEvent 252 putEvent reqEvent
261 putWord32be $ fromMaybe 0 reqIP 253 putWord32be $ fromMaybe 0 reqIP
262 putWord32be $ 0 -- TODO what the fuck is "key"? 254 putWord32be $ 0 -- TODO what the fuck is "key"?
@@ -268,9 +260,7 @@ instance Serialize AnnounceQuery where
268 ih <- get 260 ih <- get
269 pid <- get 261 pid <- get
270 262
271 down <- getWord64be 263 progress <- get
272 left <- getWord64be
273 up <- getWord64be
274 264
275 ev <- getEvent 265 ev <- getEvent
276 ip <- getWord32be 266 ip <- getWord32be
@@ -283,9 +273,7 @@ instance Serialize AnnounceQuery where
283 reqInfoHash = ih 273 reqInfoHash = ih
284 , reqPeerId = pid 274 , reqPeerId = pid
285 , reqPort = port 275 , reqPort = port
286 , reqUploaded = fromIntegral up 276 , reqProgress = progress
287 , reqDownloaded = fromIntegral down
288 , reqLeft = fromIntegral left
289 , reqIP = if ip == 0 then Nothing else Just ip 277 , reqIP = if ip == 0 then Nothing else Just ip
290 , reqNumWant = if want == -1 then Nothing else Just (fromIntegral want) 278 , reqNumWant = if want == -1 then Nothing else Just (fromIntegral want)
291 , reqEvent = ev 279 , reqEvent = ev
diff --git a/sub/bencoding b/sub/bencoding
Subproject 027333ccd04d3627c1fbebdf5d3b736c5d84865 Subproject 35913c887d8ef8f4e42398755bafb1439cd7c1a