diff options
Diffstat (limited to 'src/Network/BitTorrent/Exchange.hs')
-rw-r--r-- | src/Network/BitTorrent/Exchange.hs | 54 |
1 files changed, 34 insertions, 20 deletions
diff --git a/src/Network/BitTorrent/Exchange.hs b/src/Network/BitTorrent/Exchange.hs index 9b5a8535..0fd1d15a 100644 --- a/src/Network/BitTorrent/Exchange.hs +++ b/src/Network/BitTorrent/Exchange.hs | |||
@@ -11,6 +11,7 @@ | |||
11 | {-# LANGUAGE MultiParamTypeClasses #-} | 11 | {-# LANGUAGE MultiParamTypeClasses #-} |
12 | {-# LANGUAGE RecordWildCards #-} | 12 | {-# LANGUAGE RecordWildCards #-} |
13 | {-# LANGUAGE FlexibleContexts #-} | 13 | {-# LANGUAGE FlexibleContexts #-} |
14 | {-# LANGUAGE BangPatterns #-} | ||
14 | module Network.BitTorrent.Exchange | 15 | module Network.BitTorrent.Exchange |
15 | ( -- * Block | 16 | ( -- * Block |
16 | Block(..), BlockIx(..) | 17 | Block(..), BlockIx(..) |
@@ -35,14 +36,17 @@ import Control.Concurrent | |||
35 | import Control.Lens | 36 | import Control.Lens |
36 | import Control.Monad.Fork.Class | 37 | import Control.Monad.Fork.Class |
37 | import Control.Monad.Reader | 38 | import Control.Monad.Reader |
39 | import Control.Monad.State | ||
38 | import Control.Monad.Trans.Resource | 40 | import Control.Monad.Trans.Resource |
39 | 41 | ||
42 | import Data.IORef | ||
40 | import Data.Conduit as C | 43 | import Data.Conduit as C |
41 | import Data.Conduit.Cereal | 44 | import Data.Conduit.Cereal |
42 | import Data.Conduit.Network | 45 | import Data.Conduit.Network |
43 | import Data.Serialize as S | 46 | import Data.Serialize as S |
44 | import Text.PrettyPrint as PP hiding (($$)) | 47 | import Text.PrettyPrint as PP hiding (($$)) |
45 | 48 | ||
49 | |||
46 | import Network | 50 | import Network |
47 | 51 | ||
48 | 52 | ||
@@ -75,10 +79,12 @@ runPeerWire sock p2p = | |||
75 | awaitMessage :: P2P Message | 79 | awaitMessage :: P2P Message |
76 | awaitMessage = P2P (ReaderT (const go)) | 80 | awaitMessage = P2P (ReaderT (const go)) |
77 | where | 81 | where |
78 | go = await >>= maybe disconnect return | 82 | go = await >>= maybe (monadThrow PeerDisconnected) return |
83 | {-# INLINE awaitMessage #-} | ||
79 | 84 | ||
80 | yieldMessage :: Message -> P2P () | 85 | yieldMessage :: Message -> P2P () |
81 | yieldMessage msg = P2P $ ReaderT $ \se -> C.yield msg | 86 | yieldMessage msg = P2P $ ReaderT $ \se -> C.yield msg |
87 | {-# INLINE yieldMessage #-} | ||
82 | 88 | ||
83 | {----------------------------------------------------------------------- | 89 | {----------------------------------------------------------------------- |
84 | P2P monad | 90 | P2P monad |
@@ -97,6 +103,14 @@ newtype P2P a = P2P { | |||
97 | , MonadIO, MonadThrow, MonadActive | 103 | , MonadIO, MonadThrow, MonadActive |
98 | , MonadReader PeerSession | 104 | , MonadReader PeerSession |
99 | ) | 105 | ) |
106 | |||
107 | instance MonadState SessionState P2P where | ||
108 | {-# SPECIALIZE instance MonadState SessionState P2P #-} | ||
109 | get = asks sessionState >>= liftIO . readIORef | ||
110 | {-# INLINE get #-} | ||
111 | put !s = asks sessionState >>= \ref -> liftIO $ writeIORef ref s | ||
112 | {-# INLINE put #-} | ||
113 | |||
100 | -- TODO instance for MonadFork | 114 | -- TODO instance for MonadFork |
101 | 115 | ||
102 | runSession :: SwarmSession -> PeerAddr -> P2P () -> IO () | 116 | runSession :: SwarmSession -> PeerAddr -> P2P () -> IO () |
@@ -134,50 +148,50 @@ chainP2P :: SwarmSession -> PeerConnection -> P2P () -> IO () | |||
134 | -----------------------------------------------------------------------} | 148 | -----------------------------------------------------------------------} |
135 | 149 | ||
136 | -- | Terminate the current 'P2P' session. | 150 | -- | Terminate the current 'P2P' session. |
137 | disconnect :: MonadThrow m => m a | 151 | disconnect :: P2P a |
138 | disconnect = monadThrow PeerDisconnected | 152 | disconnect = monadThrow PeerDisconnected |
139 | 153 | ||
140 | -- TODO handle all protocol details here so we can hide this from | 154 | -- TODO handle all protocol details here so we can hide this from |
141 | -- public interface | | 155 | -- public interface | |
142 | protocolError :: MonadThrow m => Doc -> m a | 156 | protocolError :: Doc -> P2P a |
143 | protocolError = monadThrow . ProtocolError | 157 | protocolError = monadThrow . ProtocolError |
144 | 158 | ||
145 | {----------------------------------------------------------------------- | 159 | {----------------------------------------------------------------------- |
146 | Helpers | 160 | Helpers |
147 | -----------------------------------------------------------------------} | 161 | -----------------------------------------------------------------------} |
148 | 162 | ||
149 | -- | Count of client have pieces. | 163 | getClientBF :: P2P Bitfield |
150 | getHaveCount :: (MonadReader PeerSession m) => m PieceCount | 164 | getClientBF = asks swarmSession >>= liftIO . getClientBitfield |
151 | getHaveCount = undefined | 165 | {-# INLINE getClientBF #-} |
166 | |||
167 | -- | Count of client /have/ pieces. | ||
168 | getHaveCount :: P2P PieceCount | ||
169 | getHaveCount = haveCount <$> getClientBF | ||
152 | {-# INLINE getHaveCount #-} | 170 | {-# INLINE getHaveCount #-} |
153 | 171 | ||
154 | -- | Count of client do not have pieces. | 172 | -- | Count of client do not /have/ pieces. |
155 | getWantCount :: (MonadReader PeerSession m) => m PieceCount | 173 | getWantCount :: P2P PieceCount |
156 | getWantCount = undefined | 174 | getWantCount = totalCount <$> getClientBF |
157 | {-# INLINE getWantCount #-} | 175 | {-# INLINE getWantCount #-} |
158 | 176 | ||
159 | -- | Count of both have and want pieces. | 177 | -- | Count of both /have/ and /want/ pieces. |
160 | getPieceCount :: (MonadReader PeerSession m) => m PieceCount | 178 | getPieceCount :: P2P PieceCount |
161 | getPieceCount = asks findPieceCount | 179 | getPieceCount = asks findPieceCount |
162 | {-# INLINE getPieceCount #-} | 180 | {-# INLINE getPieceCount #-} |
163 | 181 | ||
164 | -- for internal use only | 182 | -- for internal use only |
165 | emptyBF :: (MonadReader PeerSession m) => m Bitfield | 183 | emptyBF :: P2P Bitfield |
166 | emptyBF = liftM haveNone getPieceCount | 184 | emptyBF = liftM haveNone getPieceCount |
167 | 185 | ||
168 | fullBF :: (MonadReader PeerSession m) => m Bitfield | 186 | fullBF :: P2P Bitfield |
169 | fullBF = liftM haveAll getPieceCount | 187 | fullBF = liftM haveAll getPieceCount |
170 | 188 | ||
171 | singletonBF :: (MonadReader PeerSession m) => PieceIx -> m Bitfield | 189 | singletonBF :: PieceIx -> P2P Bitfield |
172 | singletonBF i = liftM (BF.singleton i) getPieceCount | 190 | singletonBF i = liftM (BF.singleton i) getPieceCount |
173 | 191 | ||
174 | adjustBF :: (MonadReader PeerSession m) => Bitfield -> m Bitfield | 192 | adjustBF :: Bitfield -> P2P Bitfield |
175 | adjustBF bf = (`adjustSize` bf) `liftM` getPieceCount | 193 | adjustBF bf = (`adjustSize` bf) `liftM` getPieceCount |
176 | 194 | ||
177 | getClientBF :: (MonadIO m, MonadReader PeerSession m) => m Bitfield | ||
178 | getClientBF = asks swarmSession >>= liftIO . getClientBitfield | ||
179 | |||
180 | |||
181 | 195 | ||
182 | peerWant :: P2P Bitfield | 196 | peerWant :: P2P Bitfield |
183 | peerWant = BF.difference <$> getClientBF <*> use bitfield | 197 | peerWant = BF.difference <$> getClientBF <*> use bitfield |
@@ -332,7 +346,7 @@ awaitEvent = awaitMessage >>= go | |||
332 | requireExtension ExtFast | 346 | requireExtension ExtFast |
333 | awaitEvent | 347 | awaitEvent |
334 | 348 | ||
335 | 349 | -- TODO minimized number of peerOffer calls | |
336 | 350 | ||
337 | -- | | 351 | -- | |
338 | -- @ | 352 | -- @ |