summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent/Exchange/Wire/Status.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/BitTorrent/Exchange/Wire/Status.hs')
-rw-r--r--src/Network/BitTorrent/Exchange/Wire/Status.hs135
1 files changed, 135 insertions, 0 deletions
diff --git a/src/Network/BitTorrent/Exchange/Wire/Status.hs b/src/Network/BitTorrent/Exchange/Wire/Status.hs
new file mode 100644
index 00000000..d1b60f11
--- /dev/null
+++ b/src/Network/BitTorrent/Exchange/Wire/Status.hs
@@ -0,0 +1,135 @@
1-- |
2-- Copyright : (c) Sam Truzjan 2013
3-- License : BSD3
4-- Maintainer : pxqr.sta@gmail.com
5-- Stability : experimental
6-- Portability : portable
7--
8-- Each P2P connection endpoint should keep track status of both
9-- sides.
10--
11{-# LANGUAGE TemplateHaskell #-}
12module Network.BitTorrent.Exchange.Wire.Status
13 ( -- * Peer status
14 PeerStatus(..)
15 , choking
16 , interested
17
18 -- ** Query
19 , updateStatus
20 , statusUpdates
21
22 -- * Connection status
23 , ConnectionStatus(..)
24 , clientStatus
25 , remoteStatus
26
27 -- ** Query
28 , canUpload
29 , canDownload
30
31 -- * Extra
32 , defaultUnchokeSlots
33 , defaultRechokeInterval
34 ) where
35
36import Control.Lens
37import Data.Aeson.TH
38import Data.Default
39import Data.Maybe
40import Data.Monoid
41import Text.PrettyPrint as PP hiding ((<>))
42import Text.PrettyPrint.Class
43
44import Data.Torrent.JSON
45import Network.BitTorrent.Exchange.Message
46
47
48{-----------------------------------------------------------------------
49-- Peer status
50-----------------------------------------------------------------------}
51
52-- | Connections contain two bits of state on either end: choked or
53-- not, and interested or not.
54data PeerStatus = PeerStatus
55 { -- | Choking is a notification that no data will be sent until
56 -- unchoking happens.
57 _choking :: !Bool
58
59 -- |
60 , _interested :: !Bool
61 } deriving (Show, Eq, Ord)
62
63$(makeLenses ''PeerStatus)
64$(deriveJSON omitLensPrefix ''PeerStatus)
65
66instance Pretty PeerStatus where
67 pretty PeerStatus {..} =
68 pretty (Choking _choking) <+> "and" <+> pretty (Interested _interested)
69
70-- | Connections start out choked and not interested.
71instance Default PeerStatus where
72 def = PeerStatus True False
73
74instance Monoid PeerStatus where
75 mempty = def
76 mappend a b = PeerStatus
77 { _choking = _choking a && _choking b
78 , _interested = _interested a || _interested b
79 }
80
81-- | Can be used to update remote peer status using incoming 'Status'
82-- message.
83updateStatus :: StatusUpdate -> PeerStatus -> PeerStatus
84updateStatus (Choking b) = choking .~ b
85updateStatus (Interested b) = interested .~ b
86
87-- | Can be used to generate outcoming messages.
88statusUpdates :: PeerStatus -> PeerStatus -> [StatusUpdate]
89statusUpdates a b = catMaybes $
90 [ if _choking a == _choking b then Nothing
91 else Just $ Choking $ _choking b
92 , if _interested a == _interested b then Nothing
93 else Just $ Interested $ _interested b
94 ]
95
96{-----------------------------------------------------------------------
97-- Connection status
98-----------------------------------------------------------------------}
99
100-- | Status of the both endpoints.
101data ConnectionStatus = ConnectionStatus
102 { _clientStatus :: !PeerStatus
103 , _remoteStatus :: !PeerStatus
104 } deriving (Show, Eq)
105
106$(makeLenses ''ConnectionStatus)
107$(deriveJSON omitRecordPrefix ''ConnectionStatus)
108
109instance Pretty ConnectionStatus where
110 pretty ConnectionStatus {..} =
111 "this " <+> pretty _clientStatus $$
112 "remote" <+> pretty _remoteStatus
113
114-- | Connections start out choked and not interested.
115instance Default ConnectionStatus where
116 def = ConnectionStatus def def
117
118-- | Can the client transfer to the remote peer?
119canUpload :: ConnectionStatus -> Bool
120canUpload ConnectionStatus {..}
121 = _interested _remoteStatus && not (_choking _clientStatus)
122
123-- | Can the client transfer from the remote peer?
124canDownload :: ConnectionStatus -> Bool
125canDownload ConnectionStatus {..}
126 = _interested _clientStatus && not (_choking _remoteStatus)
127
128-- | Indicates how many peers are allowed to download from the client
129-- by default.
130defaultUnchokeSlots :: Int
131defaultUnchokeSlots = 4
132
133-- |
134defaultRechokeInterval :: Int
135defaultRechokeInterval = 10 * 1000 * 1000 \ No newline at end of file