summaryrefslogtreecommitdiff
path: root/src/Data/Torrent/Progress.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Data/Torrent/Progress.hs')
-rw-r--r--src/Data/Torrent/Progress.hs95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/Data/Torrent/Progress.hs b/src/Data/Torrent/Progress.hs
new file mode 100644
index 00000000..c1515cf0
--- /dev/null
+++ b/src/Data/Torrent/Progress.hs
@@ -0,0 +1,95 @@
1{-# LANGUAGE TemplateHaskell #-}
2{-# LANGUAGE ViewPatterns #-}
3module Data.Torrent.Progress
4 ( -- * Peer progress
5 Progress (..)
6 , left
7 , uploaded
8 , downloaded
9
10 , startProgress
11
12 , downloadedProgress
13 , enqueuedProgress
14 , uploadedProgress
15 , dequeuedProgress
16
17 ) where
18
19import Control.Applicative
20import Control.Lens
21import Data.Aeson.TH
22import Data.List as L
23import Data.Default
24import Data.Serialize as S
25
26
27-- TODO: Use Word64?
28-- TODO: Use atomic bits?
29
30-- | 'Progress' contains upload/download/left stats about
31-- current client state and used to notify the tracker.
32--
33-- Progress data is considered as dynamic within one client
34-- session. This data also should be shared across client application
35-- sessions (e.g. files), otherwise use 'startProgress' to get initial
36-- 'Progress'.
37--
38data Progress = Progress
39 { _downloaded :: !Integer -- ^ Total amount of bytes downloaded;
40 , _left :: !Integer -- ^ Total amount of bytes left;
41 , _uploaded :: !Integer -- ^ Total amount of bytes uploaded.
42 } deriving (Show, Read, Eq)
43
44$(makeLenses ''Progress)
45$(deriveJSON L.tail ''Progress)
46
47instance Serialize Progress where
48 put Progress {..} = do
49 putWord64be $ fromIntegral _downloaded
50 putWord64be $ fromIntegral _left
51 putWord64be $ fromIntegral _uploaded
52
53 get = Progress
54 <$> (fromIntegral <$> getWord64be)
55 <*> (fromIntegral <$> getWord64be)
56 <*> (fromIntegral <$> getWord64be)
57
58instance Default Progress where
59 def = Progress 0 0 0
60 {-# INLINE def #-}
61
62-- TODO Monoid instance
63
64-- | Initial progress is used when there are no session before.
65--
66-- Please note that tracker might penalize client some way if the do
67-- not accumulate progress. If possible and save 'Progress' between
68-- client sessions to avoid that.
69--
70startProgress :: Integer -> Progress
71startProgress = Progress 0 0
72{-# INLINE startProgress #-}
73
74-- | Used when the client download some data from /any/ peer.
75downloadedProgress :: Int -> Progress -> Progress
76downloadedProgress (fromIntegral -> amount)
77 = (left -~ amount)
78 . (downloaded +~ amount)
79{-# INLINE downloadedProgress #-}
80
81-- | Used when the client upload some data to /any/ peer.
82uploadedProgress :: Int -> Progress -> Progress
83uploadedProgress (fromIntegral -> amount) = uploaded +~ amount
84{-# INLINE uploadedProgress #-}
85
86-- | Used when leecher join client session.
87enqueuedProgress :: Integer -> Progress -> Progress
88enqueuedProgress amount = left +~ amount
89{-# INLINE enqueuedProgress #-}
90
91-- | Used when leecher leave client session.
92-- (e.g. user deletes not completed torrent)
93dequeuedProgress :: Integer -> Progress -> Progress
94dequeuedProgress amount = left -~ amount
95{-# INLINE dequeuedProgress #-}