summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent/Internal.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/BitTorrent/Internal.hs')
-rw-r--r--src/Network/BitTorrent/Internal.hs125
1 files changed, 106 insertions, 19 deletions
diff --git a/src/Network/BitTorrent/Internal.hs b/src/Network/BitTorrent/Internal.hs
index 38087f0d..2f538652 100644
--- a/src/Network/BitTorrent/Internal.hs
+++ b/src/Network/BitTorrent/Internal.hs
@@ -10,12 +10,33 @@
10-- Network.BitTorrent.Exchange and modules. To hide some internals 10-- Network.BitTorrent.Exchange and modules. To hide some internals
11-- of this module we detach it from Exchange. 11-- of this module we detach it from Exchange.
12-- 12--
13{-# LANGUAGE RecordWildCards #-} 13-- Note: expose only static data in data field lists, all dynamic
14-- data should be modified through standalone functions.
15--
16{-# LANGUAGE OverloadedStrings #-}
17{-# LANGUAGE RecordWildCards #-}
18{-# LANGUAGE TemplateHaskell #-}
19{-# LANGUAGE FlexibleInstances #-}
20{-# LANGUAGE FlexibleContexts #-}
21{-# LANGUAGE MultiParamTypeClasses #-}
22{-# LANGUAGE UndecidableInstances #-}
14module Network.BitTorrent.Internal 23module Network.BitTorrent.Internal
15 ( Progress(..), startProgress 24 ( Progress(..), startProgress
16 , ClientSession(..), newClient 25
17 , SwarmSession(..), newLeacher, newSeeder 26 , ClientSession (clientPeerID, allowedExtensions)
18 , PeerSession(..), withPeerSession 27 , newClient, getCurrentProgress
28
29 , SwarmSession(SwarmSession, torrentMeta, clientSession)
30 , newLeacher, newSeeder
31
32 , PeerSession(PeerSession, connectedPeerAddr
33 , swarmSession, enabledExtensions
34 )
35 , SessionState
36 , bitfield, status
37 , emptyBF, fullBF, singletonBF
38 , getPieceCount, getPeerBF
39 , sessionError, withPeerSession
19 40
20 -- * Timeouts 41 -- * Timeouts
21 , updateIncoming, updateOutcoming 42 , updateIncoming, updateOutcoming
@@ -24,6 +45,9 @@ module Network.BitTorrent.Internal
24import Control.Applicative 45import Control.Applicative
25import Control.Concurrent 46import Control.Concurrent
26import Control.Concurrent.STM 47import Control.Concurrent.STM
48import Control.Lens
49import Control.Monad.State
50import Control.Monad.Reader
27import Control.Exception 51import Control.Exception
28 52
29import Data.IORef 53import Data.IORef
@@ -32,10 +56,8 @@ import Data.Function
32import Data.Ord 56import Data.Ord
33import Data.Set as S 57import Data.Set as S
34 58
35import Data.Conduit 59import Data.Serialize hiding (get)
36import Data.Conduit.Cereal 60import Text.PrettyPrint
37import Data.Conduit.Network
38import Data.Serialize
39 61
40import Network 62import Network
41import Network.Socket 63import Network.Socket
@@ -70,13 +92,20 @@ startProgress = Progress 0 0
70 Client session 92 Client session
71-----------------------------------------------------------------------} 93-----------------------------------------------------------------------}
72 94
73-- | In one application you could have many clients. 95-- | In one application we could have many clients with difference
96-- ID's and enabled extensions.
74data ClientSession = ClientSession { 97data ClientSession = ClientSession {
75 clientPeerID :: PeerID -- ^ 98 -- | Our peer ID used in handshaked and discovery mechanism.
76 , allowedExtensions :: [Extension] -- ^ 99 clientPeerID :: PeerID
100
101 -- | Extensions we should try to use. Hovewer some particular peer
102 -- might not support some extension, so we keep enableExtension in
103 -- 'PeerSession'.
104 , allowedExtensions :: [Extension]
105
77 , swarmSessions :: TVar (Set SwarmSession) 106 , swarmSessions :: TVar (Set SwarmSession)
78 , eventManager :: EventManager 107 , eventManager :: EventManager
79 , currentProgress :: IORef Progress 108 , currentProgress :: TVar Progress
80 } 109 }
81 110
82instance Eq ClientSession where 111instance Eq ClientSession where
@@ -85,6 +114,9 @@ instance Eq ClientSession where
85instance Ord ClientSession where 114instance Ord ClientSession where
86 compare = comparing clientPeerID 115 compare = comparing clientPeerID
87 116
117getCurrentProgress :: MonadIO m => ClientSession -> m Progress
118getCurrentProgress = liftIO . readTVarIO . currentProgress
119
88newClient :: [Extension] -> IO ClientSession 120newClient :: [Extension] -> IO ClientSession
89newClient exts = do 121newClient exts = do
90 mgr <- Ev.new 122 mgr <- Ev.new
@@ -95,7 +127,7 @@ newClient exts = do
95 <*> pure exts 127 <*> pure exts
96 <*> newTVarIO S.empty 128 <*> newTVarIO S.empty
97 <*> pure mgr 129 <*> pure mgr
98 <*> newIORef (startProgress 0) 130 <*> newTVarIO (startProgress 0)
99 131
100{----------------------------------------------------------------------- 132{-----------------------------------------------------------------------
101 Swarm session 133 Swarm session
@@ -106,7 +138,9 @@ newClient exts = do
106data SwarmSession = SwarmSession { 138data SwarmSession = SwarmSession {
107 torrentMeta :: Torrent 139 torrentMeta :: Torrent
108 , clientSession :: ClientSession 140 , clientSession :: ClientSession
109 , clientBitfield :: IORef Bitfield 141
142 -- | Modify this carefully updating global progress.
143 , clientBitfield :: TVar Bitfield
110 , connectedPeers :: TVar (Set PeerSession) 144 , connectedPeers :: TVar (Set PeerSession)
111 } 145 }
112 146
@@ -120,7 +154,7 @@ newSwarmSession :: Bitfield -> ClientSession -> Torrent -> IO SwarmSession
120newSwarmSession bf cs @ ClientSession {..} t @ Torrent {..} 154newSwarmSession bf cs @ ClientSession {..} t @ Torrent {..}
121 = SwarmSession <$> pure t 155 = SwarmSession <$> pure t
122 <*> pure cs 156 <*> pure cs
123 <*> newIORef bf 157 <*> newTVarIO bf
124 <*> newTVarIO S.empty 158 <*> newTVarIO S.empty
125 159
126newSeeder :: ClientSession -> Torrent -> IO SwarmSession 160newSeeder :: ClientSession -> Torrent -> IO SwarmSession
@@ -134,13 +168,29 @@ newLeacher cs t @ Torrent {..}
134isLeacher :: SwarmSession -> IO Bool 168isLeacher :: SwarmSession -> IO Bool
135isLeacher = undefined 169isLeacher = undefined
136 170
171getClientBitfield :: MonadIO m => SwarmSession -> m Bitfield
172getClientBitfield = liftIO . readTVarIO . clientBitfield
173
174{-
175haveDone :: MonadIO m => PieceIx -> SwarmSession -> m ()
176haveDone ix =
177 liftIO $ atomically $ do
178 bf <- readTVar clientBitfield
179 writeTVar (have ix bf)
180 currentProgress
181-}
137{----------------------------------------------------------------------- 182{-----------------------------------------------------------------------
138 Peer session 183 Peer session
139-----------------------------------------------------------------------} 184-----------------------------------------------------------------------}
140 185
141data PeerSession = PeerSession { 186data PeerSession = PeerSession {
187 -- | Used as unique 'PeerSession' identifier within one
188 -- 'SwarmSession'.
142 connectedPeerAddr :: PeerAddr 189 connectedPeerAddr :: PeerAddr
190
143 , swarmSession :: SwarmSession 191 , swarmSession :: SwarmSession
192
193 -- | Extensions such that both peer and client support.
144 , enabledExtensions :: [Extension] 194 , enabledExtensions :: [Extension]
145 195
146 -- | To dissconnect from died peers appropriately we should check 196 -- | To dissconnect from died peers appropriately we should check
@@ -163,16 +213,31 @@ data PeerSession = PeerSession {
163 , outcomingTimeout :: TimeoutKey 213 , outcomingTimeout :: TimeoutKey
164 214
165 , broadcastMessages :: Chan [Message] 215 , broadcastMessages :: Chan [Message]
166 , peerBitfield :: IORef Bitfield 216 , sessionState :: IORef SessionState
167 , peerSessionStatus :: IORef SessionStatus 217 }
218
219data SessionState = SessionState {
220 _bitfield :: Bitfield
221 , _status :: SessionStatus
168 } 222 }
169 223
224$(makeLenses ''SessionState)
225
170instance Eq PeerSession where 226instance Eq PeerSession where
171 (==) = (==) `on` connectedPeerAddr 227 (==) = (==) `on` connectedPeerAddr
172 228
173instance Ord PeerSession where 229instance Ord PeerSession where
174 compare = comparing connectedPeerAddr 230 compare = comparing connectedPeerAddr
175 231
232instance (MonadIO m, MonadReader PeerSession m)
233 => MonadState SessionState m where
234 get = asks sessionState >>= liftIO . readIORef
235 put s = asks sessionState >>= \ref -> liftIO $ writeIORef ref s
236
237sessionError :: MonadIO m => Doc -> m ()
238sessionError msg
239 = liftIO $ throwIO $ userError $ render $ msg <+> "in session"
240
176-- TODO check if it connected yet peer 241-- TODO check if it connected yet peer
177withPeerSession :: SwarmSession -> PeerAddr 242withPeerSession :: SwarmSession -> PeerAddr
178 -> ((Socket, PeerSession) -> IO a) 243 -> ((Socket, PeerSession) -> IO a)
@@ -196,12 +261,34 @@ withPeerSession ss @ SwarmSession {..} addr
196 <*> registerTimeout (eventManager clientSession) 261 <*> registerTimeout (eventManager clientSession)
197 maxOutcomingTime (sendKA sock) 262 maxOutcomingTime (sendKA sock)
198 <*> newChan 263 <*> newChan
199 <*> pure clientBitfield 264 <*> do {
200 <*> newIORef def 265 ; tc <- totalCount <$> readTVarIO clientBitfield
266 ; newIORef (SessionState (haveNone tc) def)
267 }
201 return (sock, ps) 268 return (sock, ps)
202 269
203 closeSession = close . fst 270 closeSession = close . fst
204 271
272getPieceCount :: (MonadReader PeerSession m) => m PieceCount
273getPieceCount = asks (pieceCount . tInfo . torrentMeta . swarmSession)
274
275emptyBF :: (MonadReader PeerSession m) => m Bitfield
276emptyBF = liftM haveNone getPieceCount
277
278fullBF :: (MonadReader PeerSession m) => m Bitfield
279fullBF = liftM haveAll getPieceCount
280
281singletonBF :: (MonadReader PeerSession m) => PieceIx -> m Bitfield
282singletonBF ix = liftM (BF.singleton ix) getPieceCount
283
284getPeerBF :: (MonadIO m, MonadReader PeerSession m) => m Bitfield
285getPeerBF = asks swarmSession >>= liftIO . readTVarIO . clientBitfield
286
287--data Signal =
288--nextBroadcast :: P2P (Maybe Signal)
289--nextBroadcast =
290
291
205{----------------------------------------------------------------------- 292{-----------------------------------------------------------------------
206 Timeouts 293 Timeouts
207-----------------------------------------------------------------------} 294-----------------------------------------------------------------------}