summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bittorrent.cabal1
-rw-r--r--src/Network/BitTorrent.hs16
-rw-r--r--src/Network/BitTorrent/Client.hs9
-rw-r--r--src/Network/BitTorrent/Client/Handle.hs7
-rw-r--r--src/Network/BitTorrent/Client/Types.hs27
-rw-r--r--src/Network/BitTorrent/Exchange.hs5
-rw-r--r--src/Network/BitTorrent/Exchange/Session.hs46
-rw-r--r--src/Network/BitTorrent/Internal/Types.hs10
-rw-r--r--src/Network/BitTorrent/Tracker.hs3
-rw-r--r--src/Network/BitTorrent/Tracker/Message.hs20
-rw-r--r--src/Network/BitTorrent/Tracker/RPC.hs2
-rw-r--r--src/Network/BitTorrent/Tracker/Session.hs49
12 files changed, 83 insertions, 112 deletions
diff --git a/bittorrent.cabal b/bittorrent.cabal
index 7058d704..5c53d3fc 100644
--- a/bittorrent.cabal
+++ b/bittorrent.cabal
@@ -80,6 +80,7 @@ library
80 Network.BitTorrent.Exchange.Session.Metadata 80 Network.BitTorrent.Exchange.Session.Metadata
81 Network.BitTorrent.Exchange.Session.Status 81 Network.BitTorrent.Exchange.Session.Status
82 Network.BitTorrent.Internal.Cache 82 Network.BitTorrent.Internal.Cache
83 Network.BitTorrent.Internal.Types
83 Network.BitTorrent.Tracker 84 Network.BitTorrent.Tracker
84 Network.BitTorrent.Tracker.List 85 Network.BitTorrent.Tracker.List
85 Network.BitTorrent.Tracker.Message 86 Network.BitTorrent.Tracker.Message
diff --git a/src/Network/BitTorrent.hs b/src/Network/BitTorrent.hs
index 8cb928d3..bcc7cfcf 100644
--- a/src/Network/BitTorrent.hs
+++ b/src/Network/BitTorrent.hs
@@ -29,10 +29,6 @@ module Network.BitTorrent
29 , getClient 29 , getClient
30 , simpleClient 30 , simpleClient
31 31
32 -- ** Events
33 , ClientEvent (..)
34 , subscription
35
36 -- * Torrent 32 -- * Torrent
37 -- ** Source 33 -- ** Source
38 , InfoHash 34 , InfoHash
@@ -55,9 +51,13 @@ module Network.BitTorrent
55 , start 51 , start
56 , pause 52 , pause
57 , stop 53 , stop
54
55 -- * Events
56 , EventSource (..)
58 ) where 57 ) where
59 58
60import Data.Torrent as BT 59import Data.Torrent
61import Data.Torrent.InfoHash as BT 60import Data.Torrent.InfoHash
62import Data.Torrent.Magnet as BT 61import Data.Torrent.Magnet
63import Network.BitTorrent.Client as BT \ No newline at end of file 62import Network.BitTorrent.Client
63import Network.BitTorrent.Internal.Types \ No newline at end of file
diff --git a/src/Network/BitTorrent/Client.hs b/src/Network/BitTorrent/Client.hs
index 93c5f47e..bf6740c3 100644
--- a/src/Network/BitTorrent/Client.hs
+++ b/src/Network/BitTorrent/Client.hs
@@ -21,10 +21,6 @@ module Network.BitTorrent.Client
21 , withClient 21 , withClient
22 , simpleClient 22 , simpleClient
23 23
24 -- ** Events
25 , ClientEvent (..)
26 , Network.BitTorrent.Client.subscription
27
28 -- * BitTorrent monad 24 -- * BitTorrent monad
29 , MonadBitTorrent (..) 25 , MonadBitTorrent (..)
30 , BitTorrent 26 , BitTorrent
@@ -166,11 +162,6 @@ simpleClient m = do
166 runStderrLoggingT $ LoggingT $ \ logger -> do 162 runStderrLoggingT $ LoggingT $ \ logger -> do
167 withClient def logger (`runBitTorrent` m) 163 withClient def logger (`runBitTorrent` m)
168 164
169subscription :: BitTorrent (ReceivePort ClientEvent)
170subscription = do
171 Client {..} <- getClient
172 liftIO $ listen clientEvents
173
174{----------------------------------------------------------------------- 165{-----------------------------------------------------------------------
175-- Torrent identifiers 166-- Torrent identifiers
176-----------------------------------------------------------------------} 167-----------------------------------------------------------------------}
diff --git a/src/Network/BitTorrent/Client/Handle.hs b/src/Network/BitTorrent/Client/Handle.hs
index 25316a0a..0d1b7f92 100644
--- a/src/Network/BitTorrent/Client/Handle.hs
+++ b/src/Network/BitTorrent/Client/Handle.hs
@@ -14,11 +14,7 @@ module Network.BitTorrent.Client.Handle
14 14
15 -- * Query 15 -- * Query
16 , getHandle 16 , getHandle
17 , HandleStatus (..)
18 , getStatus 17 , getStatus
19
20 -- * Events
21 , HandleEvent (..)
22 ) where 18 ) where
23 19
24import Control.Concurrent.Chan.Split 20import Control.Concurrent.Chan.Split
@@ -192,6 +188,3 @@ getHandle ih = do
192 188
193getStatus :: Handle -> IO HandleStatus 189getStatus :: Handle -> IO HandleStatus
194getStatus Handle {..} = readMVar handleStatus 190getStatus Handle {..} = readMVar handleStatus
195
196subscription :: Handle -> IO (ReceivePort HandleEvent)
197subscription Handle {..} = listen handleEvents
diff --git a/src/Network/BitTorrent/Client/Types.hs b/src/Network/BitTorrent/Client/Types.hs
index aa876ff1..c019bc5f 100644
--- a/src/Network/BitTorrent/Client/Types.hs
+++ b/src/Network/BitTorrent/Client/Types.hs
@@ -17,13 +17,12 @@ module Network.BitTorrent.Client.Types
17 , MonadBitTorrent (..) 17 , MonadBitTorrent (..)
18 18
19 -- * Events 19 -- * Events
20 , ClientEvent (..) 20 , Types.Event (..)
21 , HandleEvent (..)
22 ) where 21 ) where
23 22
24import Control.Applicative 23import Control.Applicative
25import Control.Concurrent 24import Control.Concurrent
26import Control.Concurrent.Chan.Split 25import Control.Concurrent.Chan.Split as CS
27import Control.Monad.Base 26import Control.Monad.Base
28import Control.Monad.Logger 27import Control.Monad.Logger
29import Control.Monad.Reader 28import Control.Monad.Reader
@@ -36,19 +35,17 @@ import Network
36import System.Log.FastLogger 35import System.Log.FastLogger
37 36
38import Data.Torrent.InfoHash 37import Data.Torrent.InfoHash
38import Network.BitTorrent.Internal.Types as Types
39import Network.BitTorrent.Core 39import Network.BitTorrent.Core
40import Network.BitTorrent.DHT as DHT 40import Network.BitTorrent.DHT as DHT
41import Network.BitTorrent.Exchange as Exchange 41import Network.BitTorrent.Exchange as Exchange
42import Network.BitTorrent.Tracker as Tracker 42import Network.BitTorrent.Tracker as Tracker hiding (Event)
43 43
44data HandleStatus 44data HandleStatus
45 = Running 45 = Running
46 | Stopped 46 | Stopped
47 deriving (Show, Eq) 47 deriving (Show, Eq)
48 48
49data HandleEvent
50 = StatusChanged HandleStatus
51
52data Handle = Handle 49data Handle = Handle
53 { handleTopic :: !InfoHash 50 { handleTopic :: !InfoHash
54 , handlePrivate :: !Bool 51 , handlePrivate :: !Bool
@@ -56,9 +53,13 @@ data Handle = Handle
56 , handleStatus :: !(MVar HandleStatus) 53 , handleStatus :: !(MVar HandleStatus)
57 , handleTrackers :: !Tracker.Session 54 , handleTrackers :: !Tracker.Session
58 , handleExchange :: !Exchange.Session 55 , handleExchange :: !Exchange.Session
59 , handleEvents :: !(SendPort HandleEvent) 56 , handleEvents :: !(SendPort (Event Handle))
60 } 57 }
61 58
59instance EventSource Handle where
60 data Event Handle = StatusChanged HandleStatus
61 listen Handle {..} = CS.listen undefined
62
62data Client = Client 63data Client = Client
63 { clientPeerId :: !PeerId 64 { clientPeerId :: !PeerId
64 , clientListenerPort :: !PortNumber 65 , clientListenerPort :: !PortNumber
@@ -69,7 +70,7 @@ data Client = Client
69 , clientNode :: !(Node IPv4) 70 , clientNode :: !(Node IPv4)
70 , clientTorrents :: !(MVar (HashMap InfoHash Handle)) 71 , clientTorrents :: !(MVar (HashMap InfoHash Handle))
71 , clientLogger :: !LogFun 72 , clientLogger :: !LogFun
72 , clientEvents :: !(SendPort ClientEvent) 73 , clientEvents :: !(SendPort (Event Client))
73 } 74 }
74 75
75instance Eq Client where 76instance Eq Client where
@@ -78,6 +79,10 @@ instance Eq Client where
78instance Ord Client where 79instance Ord Client where
79 compare = comparing clientPeerId 80 compare = comparing clientPeerId
80 81
82instance EventSource Client where
83 data Event Client = TorrentAdded InfoHash
84 listen Client {..} = CS.listen clientEvents
85
81-- | External IP address of a host running a bittorrent client 86-- | External IP address of a host running a bittorrent client
82-- software may be used to acknowledge remote peer the host connected 87-- software may be used to acknowledge remote peer the host connected
83-- to. See 'Network.BitTorrent.Exchange.Message.ExtendedHandshake'. 88-- to. See 'Network.BitTorrent.Exchange.Message.ExtendedHandshake'.
@@ -88,10 +93,6 @@ externalAddr Client {..} = PeerAddr
88 , peerPort = clientListenerPort 93 , peerPort = clientListenerPort
89 } 94 }
90 95
91data ClientEvent
92 = TorrentAdded InfoHash
93 deriving (Show, Eq)
94
95{----------------------------------------------------------------------- 96{-----------------------------------------------------------------------
96-- BitTorrent monad 97-- BitTorrent monad
97-----------------------------------------------------------------------} 98-----------------------------------------------------------------------}
diff --git a/src/Network/BitTorrent/Exchange.hs b/src/Network/BitTorrent/Exchange.hs
index a90c19f8..ce71e286 100644
--- a/src/Network/BitTorrent/Exchange.hs
+++ b/src/Network/BitTorrent/Exchange.hs
@@ -27,13 +27,8 @@ module Network.BitTorrent.Exchange
27 27
28 -- * Connections 28 -- * Connections
29 , connect 29 , connect
30
31 -- * Events
32 , SessionEvent (..)
33 , subscription
34 ) where 30 ) where
35 31
36import Network.BitTorrent.Exchange.Connection hiding (Options)
37import Network.BitTorrent.Exchange.Manager 32import Network.BitTorrent.Exchange.Manager
38import Network.BitTorrent.Exchange.Message 33import Network.BitTorrent.Exchange.Message
39import Network.BitTorrent.Exchange.Session 34import Network.BitTorrent.Exchange.Session
diff --git a/src/Network/BitTorrent/Exchange/Session.hs b/src/Network/BitTorrent/Exchange/Session.hs
index b6d7f810..91ea8da9 100644
--- a/src/Network/BitTorrent/Exchange/Session.hs
+++ b/src/Network/BitTorrent/Exchange/Session.hs
@@ -1,9 +1,11 @@
1{-# LANGUAGE FlexibleInstances #-} 1{-# LANGUAGE FlexibleInstances #-}
2{-# LANGUAGE TypeFamilies #-}
2{-# LANGUAGE TemplateHaskell #-} 3{-# LANGUAGE TemplateHaskell #-}
3{-# LANGUAGE DeriveDataTypeable #-} 4{-# LANGUAGE DeriveDataTypeable #-}
4module Network.BitTorrent.Exchange.Session 5module Network.BitTorrent.Exchange.Session
5 ( -- * Session 6 ( -- * Session
6 Session 7 Session
8 , Event (..)
7 , LogFun 9 , LogFun
8 , sessionLogger 10 , sessionLogger
9 11
@@ -19,10 +21,6 @@ module Network.BitTorrent.Exchange.Session
19 -- * Query 21 -- * Query
20 , waitMetadata 22 , waitMetadata
21 , takeMetadata 23 , takeMetadata
22
23 -- * Events
24 , SessionEvent (..)
25 , subscription
26 ) where 24 ) where
27 25
28import Control.Applicative 26import Control.Applicative
@@ -52,6 +50,7 @@ import Data.Torrent.Bitfield as BF
52import Data.Torrent.InfoHash 50import Data.Torrent.InfoHash
53import Data.Torrent.Piece 51import Data.Torrent.Piece
54import qualified Data.Torrent.Piece as Torrent (Piece ()) 52import qualified Data.Torrent.Piece as Torrent (Piece ())
53import Network.BitTorrent.Internal.Types
55import Network.BitTorrent.Core 54import Network.BitTorrent.Core
56import Network.BitTorrent.Exchange.Block as Block 55import Network.BitTorrent.Exchange.Block as Block
57import Network.BitTorrent.Exchange.Connection 56import Network.BitTorrent.Exchange.Connection
@@ -138,7 +137,7 @@ data Session = Session
138 { sessionPeerId :: !(PeerId) 137 { sessionPeerId :: !(PeerId)
139 , sessionTopic :: !(InfoHash) 138 , sessionTopic :: !(InfoHash)
140 , sessionLogger :: !(LogFun) 139 , sessionLogger :: !(LogFun)
141 , sessionEvents :: !(SendPort SessionEvent) 140 , sessionEvents :: !(SendPort (Event Session))
142 141
143 , sessionState :: !(MVar SessionState) 142 , sessionState :: !(MVar SessionState)
144 143
@@ -162,6 +161,17 @@ data Session = Session
162 , connectionsBroadcast :: !(Chan Message) 161 , connectionsBroadcast :: !(Chan Message)
163 } 162 }
164 163
164instance EventSource Session where
165 data Event Session
166 = ConnectingTo (PeerAddr IP)
167 | ConnectionEstablished (PeerAddr IP)
168 | ConnectionAborted
169 | ConnectionClosed (PeerAddr IP)
170 | SessionClosed
171 deriving Show
172
173 listen Session {..} = CS.listen sessionEvents
174
165newSession :: LogFun 175newSession :: LogFun
166 -> PeerAddr (Maybe IP) -- ^ /external/ address of this peer; 176 -> PeerAddr (Maybe IP) -- ^ /external/ address of this peer;
167 -> FilePath -- ^ root directory for content files; 177 -> FilePath -- ^ root directory for content files;
@@ -205,21 +215,6 @@ withSession :: ()
205withSession = error "withSession" 215withSession = error "withSession"
206 216
207{----------------------------------------------------------------------- 217{-----------------------------------------------------------------------
208-- Session events
209-----------------------------------------------------------------------}
210
211data SessionEvent
212 = ConnectingTo (PeerAddr IP)
213 | ConnectionEstablished (PeerAddr IP)
214 | ConnectionAborted
215 | ConnectionClosed (PeerAddr IP)
216 | SessionClosed
217 deriving Show
218
219subscription :: Session -> IO (ReceivePort SessionEvent)
220subscription Session {..} = listen sessionEvents
221
222{-----------------------------------------------------------------------
223-- Logging 218-- Logging
224-----------------------------------------------------------------------} 219-----------------------------------------------------------------------}
225 220
@@ -577,14 +572,3 @@ mainWire = do
577 logEvent "Connection established" 572 logEvent "Connection established"
578 iterM logMessage =$= exchange =$= iterM logMessage 573 iterM logMessage =$= exchange =$= iterM logMessage
579 lift finishedConnection 574 lift finishedConnection
580
581data Event = NewMessage (PeerAddr IP) Message
582 | Timeout -- for scheduling
583
584type Exchange a = Wire Session a
585
586awaitEvent :: Exchange Event
587awaitEvent = error "awaitEvent"
588
589yieldEvent :: Exchange Event
590yieldEvent = error "yieldEvent"
diff --git a/src/Network/BitTorrent/Internal/Types.hs b/src/Network/BitTorrent/Internal/Types.hs
new file mode 100644
index 00000000..d157db3e
--- /dev/null
+++ b/src/Network/BitTorrent/Internal/Types.hs
@@ -0,0 +1,10 @@
1{-# LANGUAGE TypeFamilies #-}
2module Network.BitTorrent.Internal.Types
3 ( EventSource (..)
4 ) where
5
6import Control.Concurrent.Chan.Split
7
8class EventSource source where
9 data Event source
10 listen :: source -> IO (ReceivePort (Event source))
diff --git a/src/Network/BitTorrent/Tracker.hs b/src/Network/BitTorrent/Tracker.hs
index 46589eb7..6db67559 100644
--- a/src/Network/BitTorrent/Tracker.hs
+++ b/src/Network/BitTorrent/Tracker.hs
@@ -22,12 +22,13 @@ module Network.BitTorrent.Tracker
22 -- * Multitracker session 22 -- * Multitracker session
23 , trackerList 23 , trackerList
24 , Session 24 , Session
25 , Event (..)
25 , newSession 26 , newSession
26 , closeSession 27 , closeSession
27 , withSession 28 , withSession
28 29
29 -- ** Events 30 -- ** Events
30 , Event (..) 31 , AnnounceEvent (..)
31 , notify 32 , notify
32 , askPeers 33 , askPeers
33 34
diff --git a/src/Network/BitTorrent/Tracker/Message.hs b/src/Network/BitTorrent/Tracker/Message.hs
index 8131ecf0..ffe36c82 100644
--- a/src/Network/BitTorrent/Tracker/Message.hs
+++ b/src/Network/BitTorrent/Tracker/Message.hs
@@ -30,8 +30,8 @@
30module Network.BitTorrent.Tracker.Message 30module Network.BitTorrent.Tracker.Message
31 ( -- * Announce 31 ( -- * Announce
32 -- ** Query 32 -- ** Query
33 Event(..) 33 AnnounceEvent (..)
34 , AnnounceQuery(..) 34 , AnnounceQuery (..)
35 , renderAnnounceQuery 35 , renderAnnounceQuery
36 , ParamParseFailure 36 , ParamParseFailure
37 , parseAnnounceQuery 37 , parseAnnounceQuery
@@ -136,7 +136,7 @@ import Network.BitTorrent.Core
136-----------------------------------------------------------------------} 136-----------------------------------------------------------------------}
137 137
138-- | Events are used to specify which kind of announce query is performed. 138-- | Events are used to specify which kind of announce query is performed.
139data Event 139data AnnounceEvent
140 -- | For the first request: when download first begins. 140 -- | For the first request: when download first begins.
141 = Started 141 = Started
142 142
@@ -150,10 +150,10 @@ data Event
150 | Completed 150 | Completed
151 deriving (Show, Read, Eq, Ord, Enum, Bounded, Typeable) 151 deriving (Show, Read, Eq, Ord, Enum, Bounded, Typeable)
152 152
153$(deriveJSON omitRecordPrefix ''Event) 153$(deriveJSON omitRecordPrefix ''AnnounceEvent)
154 154
155-- | HTTP tracker protocol compatible encoding. 155-- | HTTP tracker protocol compatible encoding.
156instance QueryValueLike Event where 156instance QueryValueLike AnnounceEvent where
157 toQueryValue e = toQueryValue (Char.toLower x : xs) 157 toQueryValue e = toQueryValue (Char.toLower x : xs)
158 where 158 where
159 (x : xs) = show e -- INVARIANT: this is always nonempty list 159 (x : xs) = show e -- INVARIANT: this is always nonempty list
@@ -161,17 +161,17 @@ instance QueryValueLike Event where
161type EventId = Word32 161type EventId = Word32
162 162
163-- | UDP tracker encoding event codes. 163-- | UDP tracker encoding event codes.
164eventId :: Event -> EventId 164eventId :: AnnounceEvent -> EventId
165eventId Completed = 1 165eventId Completed = 1
166eventId Started = 2 166eventId Started = 2
167eventId Stopped = 3 167eventId Stopped = 3
168 168
169-- TODO add Regular event 169-- TODO add Regular event
170putEvent :: Putter (Maybe Event) 170putEvent :: Putter (Maybe AnnounceEvent)
171putEvent Nothing = putWord32be 0 171putEvent Nothing = putWord32be 0
172putEvent (Just e) = putWord32be (eventId e) 172putEvent (Just e) = putWord32be (eventId e)
173 173
174getEvent :: S.Get (Maybe Event) 174getEvent :: S.Get (Maybe AnnounceEvent)
175getEvent = do 175getEvent = do
176 eid <- getWord32be 176 eid <- getWord32be
177 case eid of 177 case eid of
@@ -221,7 +221,7 @@ data AnnounceQuery = AnnounceQuery
221 221
222 -- | If not specified, the request is regular periodic 222 -- | If not specified, the request is regular periodic
223 -- request. Regular request should be sent 223 -- request. Regular request should be sent
224 , reqEvent :: Maybe Event 224 , reqEvent :: Maybe AnnounceEvent
225 } deriving (Show, Eq, Typeable) 225 } deriving (Show, Eq, Typeable)
226 226
227$(deriveJSON omitRecordPrefix ''AnnounceQuery) 227$(deriveJSON omitRecordPrefix ''AnnounceQuery)
@@ -351,7 +351,7 @@ instance FromParam Int where
351instance FromParam PortNumber where 351instance FromParam PortNumber where
352 fromParam bs = fromIntegral <$> (fromParam bs :: Maybe Word32) 352 fromParam bs = fromIntegral <$> (fromParam bs :: Maybe Word32)
353 353
354instance FromParam Event where 354instance FromParam AnnounceEvent where
355 fromParam bs = do 355 fromParam bs = do
356 (x, xs) <- BC.uncons bs 356 (x, xs) <- BC.uncons bs
357 readMaybe $ BC.unpack $ BC.cons (Char.toUpper x) xs 357 readMaybe $ BC.unpack $ BC.cons (Char.toUpper x) xs
diff --git a/src/Network/BitTorrent/Tracker/RPC.hs b/src/Network/BitTorrent/Tracker/RPC.hs
index 39d1b09f..dc1bd4ec 100644
--- a/src/Network/BitTorrent/Tracker/RPC.hs
+++ b/src/Network/BitTorrent/Tracker/RPC.hs
@@ -63,7 +63,7 @@ data SAnnounceQuery = SAnnounceQuery
63 { sInfoHash :: InfoHash 63 { sInfoHash :: InfoHash
64 , sProgress :: Progress 64 , sProgress :: Progress
65 , sNumWant :: Maybe Int 65 , sNumWant :: Maybe Int
66 , sEvent :: Maybe Event 66 , sEvent :: Maybe AnnounceEvent
67 } 67 }
68 68
69fillAnnounceQuery :: PeerInfo -> SAnnounceQuery -> AnnounceQuery 69fillAnnounceQuery :: PeerInfo -> SAnnounceQuery -> AnnounceQuery
diff --git a/src/Network/BitTorrent/Tracker/Session.hs b/src/Network/BitTorrent/Tracker/Session.hs
index e82501dd..5aa9c0eb 100644
--- a/src/Network/BitTorrent/Tracker/Session.hs
+++ b/src/Network/BitTorrent/Tracker/Session.hs
@@ -8,17 +8,18 @@
8-- Multitracker sessions. 8-- Multitracker sessions.
9-- 9--
10{-# LANGUAGE FlexibleInstances #-} 10{-# LANGUAGE FlexibleInstances #-}
11{-# LANGUAGE TypeFamilies #-}
11{-# LANGUAGE TypeSynonymInstances #-} 12{-# LANGUAGE TypeSynonymInstances #-}
12{-# LANGUAGE TemplateHaskell #-} 13{-# LANGUAGE TemplateHaskell #-}
13module Network.BitTorrent.Tracker.Session 14module Network.BitTorrent.Tracker.Session
14 ( -- * Session 15 ( -- * Session
15 Session 16 Session
17 , Event (..)
16 , newSession 18 , newSession
17 , closeSession 19 , closeSession
18 , withSession 20 , withSession
19 21
20 -- * Client send notifications 22 -- * Client send notifications
21 , Event (..)
22 , notify 23 , notify
23 , askPeers 24 , askPeers
24 25
@@ -39,16 +40,12 @@ module Network.BitTorrent.Tracker.Session
39 , addTracker 40 , addTracker
40 , removeTracker 41 , removeTracker
41 , getTrustedTrackers 42 , getTrustedTrackers
42
43 -- * Events
44 , SessionEvent (..)
45 , subscribe
46 ) where 43 ) where
47 44
48import Control.Applicative 45import Control.Applicative
49import Control.Exception 46import Control.Exception
50import Control.Concurrent 47import Control.Concurrent
51import Control.Concurrent.Chan.Split 48import Control.Concurrent.Chan.Split as CS
52import Control.Monad 49import Control.Monad
53import Data.Aeson 50import Data.Aeson
54import Data.Aeson.TH 51import Data.Aeson.TH
@@ -66,6 +63,7 @@ import Data.Torrent.InfoHash
66import Data.Torrent.JSON 63import Data.Torrent.JSON
67import Network.BitTorrent.Core 64import Network.BitTorrent.Core
68import Network.BitTorrent.Internal.Cache 65import Network.BitTorrent.Internal.Cache
66import Network.BitTorrent.Internal.Types
69import Network.BitTorrent.Tracker.List as TL 67import Network.BitTorrent.Tracker.List as TL
70import Network.BitTorrent.Tracker.Message 68import Network.BitTorrent.Tracker.Message
71import Network.BitTorrent.Tracker.RPC as RPC 69import Network.BitTorrent.Tracker.RPC as RPC
@@ -123,7 +121,7 @@ instance Default TrackerSession where
123 def = TrackerSession Nothing def def 121 def = TrackerSession Nothing def def
124 122
125-- | Do we need to notify this /specific/ tracker? 123-- | Do we need to notify this /specific/ tracker?
126needNotify :: Event -> Maybe Status -> Maybe Bool 124needNotify :: AnnounceEvent -> Maybe Status -> Maybe Bool
127needNotify Started Nothing = Just True 125needNotify Started Nothing = Just True
128needNotify Stopped Nothing = Just False 126needNotify Stopped Nothing = Just False
129needNotify Completed Nothing = Just False 127needNotify Completed Nothing = Just False
@@ -135,7 +133,7 @@ needNotify Stopped (Just Paused ) = Just False
135needNotify Completed (Just Paused ) = Just True 133needNotify Completed (Just Paused ) = Just True
136 134
137-- | Client status after event announce succeed. 135-- | Client status after event announce succeed.
138nextStatus :: Event -> Maybe Status 136nextStatus :: AnnounceEvent -> Maybe Status
139nextStatus Started = Just Running 137nextStatus Started = Just Running
140nextStatus Stopped = Just Paused 138nextStatus Stopped = Just Paused
141nextStatus Completed = Nothing -- must keep previous status 139nextStatus Completed = Nothing -- must keep previous status
@@ -159,7 +157,7 @@ cacheScrape AnnounceInfo {..} =
159 } 157 }
160 158
161-- | Make announce request to specific tracker returning new state. 159-- | Make announce request to specific tracker returning new state.
162notifyTo :: Manager -> Session -> Event 160notifyTo :: Manager -> Session -> AnnounceEvent
163 -> TierEntry TrackerSession -> IO TrackerSession 161 -> TierEntry TrackerSession -> IO TrackerSession
164notifyTo mgr s @ Session {..} event (uri, entry @ TrackerSession {..}) = do 162notifyTo mgr s @ Session {..} event (uri, entry @ TrackerSession {..}) = do
165 let shouldNotify = needNotify event statusSent 163 let shouldNotify = needNotify event statusSent
@@ -193,9 +191,20 @@ data Session = Session
193 -- must take a lock. 191 -- must take a lock.
194 , sessionTrackers :: !(MVar (TrackerList TrackerSession)) 192 , sessionTrackers :: !(MVar (TrackerList TrackerSession))
195 193
196 , sessionEvents :: !(SendPort SessionEvent) 194 , sessionEvents :: !(SendPort (Event Session))
197 } 195 }
198 196
197instance EventSource Session where
198 data Event Session
199 = TrackerAdded URI
200 | TrackerConfirmed URI
201 | TrackerRemoved URI
202 | AnnouncedTo URI
203 | SessionClosed
204
205 listen Session {..} = CS.listen sessionEvents
206
207
199-- | Create a new multitracker session in paused state. Tracker list 208-- | Create a new multitracker session in paused state. Tracker list
200-- must contant only /trusted/ tracker uris. To start announcing 209-- must contant only /trusted/ tracker uris. To start announcing
201-- client presence use 'notify'. 210-- client presence use 'notify'.
@@ -221,20 +230,6 @@ closeSession m s @ Session {..} = do
221 send sessionEvents SessionClosed 230 send sessionEvents SessionClosed
222 231
223{----------------------------------------------------------------------- 232{-----------------------------------------------------------------------
224-- Events
225-----------------------------------------------------------------------}
226
227data SessionEvent
228 = TrackerAdded URI
229 | TrackerConfirmed URI
230 | TrackerRemoved URI
231 | AnnouncedTo URI
232 | SessionClosed
233
234subscribe :: Session -> IO (ReceivePort SessionEvent)
235subscribe Session {..} = listen sessionEvents
236
237{-----------------------------------------------------------------------
238-- Operations 233-- Operations
239-----------------------------------------------------------------------} 234-----------------------------------------------------------------------}
240 235
@@ -253,12 +248,12 @@ getSessionState Session {..} = TL.toList <$> readMVar sessionTrackers
253 248
254-- | Do we need to sent this event to a first working tracker or to 249-- | Do we need to sent this event to a first working tracker or to
255-- the all known good trackers? 250-- the all known good trackers?
256allNotify :: Event -> Bool 251allNotify :: AnnounceEvent -> Bool
257allNotify Started = False 252allNotify Started = False
258allNotify Stopped = True 253allNotify Stopped = True
259allNotify Completed = True 254allNotify Completed = True
260 255
261notifyAll :: Manager -> Session -> Event -> IO () 256notifyAll :: Manager -> Session -> AnnounceEvent -> IO ()
262notifyAll mgr s @ Session {..} event = do 257notifyAll mgr s @ Session {..} event = do
263 modifyMVar_ sessionTrackers $ 258 modifyMVar_ sessionTrackers $
264 (traversal (notifyTo mgr s event)) 259 (traversal (notifyTo mgr s event))
@@ -271,7 +266,7 @@ notifyAll mgr s @ Session {..} event = do
271-- | 266-- |
272-- 267--
273-- This function /may/ block until tracker query proceed. 268-- This function /may/ block until tracker query proceed.
274notify :: Manager -> Session -> Event -> IO () 269notify :: Manager -> Session -> AnnounceEvent -> IO ()
275notify mgr ses event = do 270notify mgr ses event = do
276 prevStatus <- atomicModifyIORef (sessionStatus ses) $ \ s -> 271 prevStatus <- atomicModifyIORef (sessionStatus ses) $ \ s ->
277 (fromMaybe s (nextStatus event), s) 272 (fromMaybe s (nextStatus event), s)