diff options
author | Sam Truzjan <pxqr.sta@gmail.com> | 2014-04-04 04:51:36 +0400 |
---|---|---|
committer | Sam Truzjan <pxqr.sta@gmail.com> | 2014-04-04 04:51:36 +0400 |
commit | 1beb66f98504a39c8a6c976f243a1f69ffb48d8d (patch) | |
tree | e26f7eff93b2ef100a768e01b0fbeb239c09dd8a /src | |
parent | 13793b8d4cf7c5b4a914d778e3523e950aa2493a (diff) |
[Internal] Add EventSource class
Diffstat (limited to 'src')
-rw-r--r-- | src/Network/BitTorrent.hs | 16 | ||||
-rw-r--r-- | src/Network/BitTorrent/Client.hs | 9 | ||||
-rw-r--r-- | src/Network/BitTorrent/Client/Handle.hs | 7 | ||||
-rw-r--r-- | src/Network/BitTorrent/Client/Types.hs | 27 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange.hs | 5 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange/Session.hs | 46 | ||||
-rw-r--r-- | src/Network/BitTorrent/Internal/Types.hs | 10 | ||||
-rw-r--r-- | src/Network/BitTorrent/Tracker.hs | 3 | ||||
-rw-r--r-- | src/Network/BitTorrent/Tracker/Message.hs | 20 | ||||
-rw-r--r-- | src/Network/BitTorrent/Tracker/RPC.hs | 2 | ||||
-rw-r--r-- | src/Network/BitTorrent/Tracker/Session.hs | 49 |
11 files changed, 82 insertions, 112 deletions
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 | ||
60 | import Data.Torrent as BT | 59 | import Data.Torrent |
61 | import Data.Torrent.InfoHash as BT | 60 | import Data.Torrent.InfoHash |
62 | import Data.Torrent.Magnet as BT | 61 | import Data.Torrent.Magnet |
63 | import Network.BitTorrent.Client as BT \ No newline at end of file | 62 | import Network.BitTorrent.Client |
63 | import 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 | ||
169 | subscription :: BitTorrent (ReceivePort ClientEvent) | ||
170 | subscription = 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 | ||
24 | import Control.Concurrent.Chan.Split | 20 | import Control.Concurrent.Chan.Split |
@@ -192,6 +188,3 @@ getHandle ih = do | |||
192 | 188 | ||
193 | getStatus :: Handle -> IO HandleStatus | 189 | getStatus :: Handle -> IO HandleStatus |
194 | getStatus Handle {..} = readMVar handleStatus | 190 | getStatus Handle {..} = readMVar handleStatus |
195 | |||
196 | subscription :: Handle -> IO (ReceivePort HandleEvent) | ||
197 | subscription 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 | ||
24 | import Control.Applicative | 23 | import Control.Applicative |
25 | import Control.Concurrent | 24 | import Control.Concurrent |
26 | import Control.Concurrent.Chan.Split | 25 | import Control.Concurrent.Chan.Split as CS |
27 | import Control.Monad.Base | 26 | import Control.Monad.Base |
28 | import Control.Monad.Logger | 27 | import Control.Monad.Logger |
29 | import Control.Monad.Reader | 28 | import Control.Monad.Reader |
@@ -36,19 +35,17 @@ import Network | |||
36 | import System.Log.FastLogger | 35 | import System.Log.FastLogger |
37 | 36 | ||
38 | import Data.Torrent.InfoHash | 37 | import Data.Torrent.InfoHash |
38 | import Network.BitTorrent.Internal.Types as Types | ||
39 | import Network.BitTorrent.Core | 39 | import Network.BitTorrent.Core |
40 | import Network.BitTorrent.DHT as DHT | 40 | import Network.BitTorrent.DHT as DHT |
41 | import Network.BitTorrent.Exchange as Exchange | 41 | import Network.BitTorrent.Exchange as Exchange |
42 | import Network.BitTorrent.Tracker as Tracker | 42 | import Network.BitTorrent.Tracker as Tracker hiding (Event) |
43 | 43 | ||
44 | data HandleStatus | 44 | data HandleStatus |
45 | = Running | 45 | = Running |
46 | | Stopped | 46 | | Stopped |
47 | deriving (Show, Eq) | 47 | deriving (Show, Eq) |
48 | 48 | ||
49 | data HandleEvent | ||
50 | = StatusChanged HandleStatus | ||
51 | |||
52 | data Handle = Handle | 49 | data 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 | ||
59 | instance EventSource Handle where | ||
60 | data Event Handle = StatusChanged HandleStatus | ||
61 | listen Handle {..} = CS.listen undefined | ||
62 | |||
62 | data Client = Client | 63 | data 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 | ||
75 | instance Eq Client where | 76 | instance Eq Client where |
@@ -78,6 +79,10 @@ instance Eq Client where | |||
78 | instance Ord Client where | 79 | instance Ord Client where |
79 | compare = comparing clientPeerId | 80 | compare = comparing clientPeerId |
80 | 81 | ||
82 | instance 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 | ||
91 | data 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 | ||
36 | import Network.BitTorrent.Exchange.Connection hiding (Options) | ||
37 | import Network.BitTorrent.Exchange.Manager | 32 | import Network.BitTorrent.Exchange.Manager |
38 | import Network.BitTorrent.Exchange.Message | 33 | import Network.BitTorrent.Exchange.Message |
39 | import Network.BitTorrent.Exchange.Session | 34 | import 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 #-} |
4 | module Network.BitTorrent.Exchange.Session | 5 | module 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 | ||
28 | import Control.Applicative | 26 | import Control.Applicative |
@@ -52,6 +50,7 @@ import Data.Torrent.Bitfield as BF | |||
52 | import Data.Torrent.InfoHash | 50 | import Data.Torrent.InfoHash |
53 | import Data.Torrent.Piece | 51 | import Data.Torrent.Piece |
54 | import qualified Data.Torrent.Piece as Torrent (Piece ()) | 52 | import qualified Data.Torrent.Piece as Torrent (Piece ()) |
53 | import Network.BitTorrent.Internal.Types | ||
55 | import Network.BitTorrent.Core | 54 | import Network.BitTorrent.Core |
56 | import Network.BitTorrent.Exchange.Block as Block | 55 | import Network.BitTorrent.Exchange.Block as Block |
57 | import Network.BitTorrent.Exchange.Connection | 56 | import 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 | ||
164 | instance 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 | |||
165 | newSession :: LogFun | 175 | newSession :: 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 :: () | |||
205 | withSession = error "withSession" | 215 | withSession = error "withSession" |
206 | 216 | ||
207 | {----------------------------------------------------------------------- | 217 | {----------------------------------------------------------------------- |
208 | -- Session events | ||
209 | -----------------------------------------------------------------------} | ||
210 | |||
211 | data SessionEvent | ||
212 | = ConnectingTo (PeerAddr IP) | ||
213 | | ConnectionEstablished (PeerAddr IP) | ||
214 | | ConnectionAborted | ||
215 | | ConnectionClosed (PeerAddr IP) | ||
216 | | SessionClosed | ||
217 | deriving Show | ||
218 | |||
219 | subscription :: Session -> IO (ReceivePort SessionEvent) | ||
220 | subscription 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 | |||
581 | data Event = NewMessage (PeerAddr IP) Message | ||
582 | | Timeout -- for scheduling | ||
583 | |||
584 | type Exchange a = Wire Session a | ||
585 | |||
586 | awaitEvent :: Exchange Event | ||
587 | awaitEvent = error "awaitEvent" | ||
588 | |||
589 | yieldEvent :: Exchange Event | ||
590 | yieldEvent = 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 #-} | ||
2 | module Network.BitTorrent.Internal.Types | ||
3 | ( EventSource (..) | ||
4 | ) where | ||
5 | |||
6 | import Control.Concurrent.Chan.Split | ||
7 | |||
8 | class 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 @@ | |||
30 | module Network.BitTorrent.Tracker.Message | 30 | module 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. |
139 | data Event | 139 | data 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. |
156 | instance QueryValueLike Event where | 156 | instance 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 | |||
161 | type EventId = Word32 | 161 | type EventId = Word32 |
162 | 162 | ||
163 | -- | UDP tracker encoding event codes. | 163 | -- | UDP tracker encoding event codes. |
164 | eventId :: Event -> EventId | 164 | eventId :: AnnounceEvent -> EventId |
165 | eventId Completed = 1 | 165 | eventId Completed = 1 |
166 | eventId Started = 2 | 166 | eventId Started = 2 |
167 | eventId Stopped = 3 | 167 | eventId Stopped = 3 |
168 | 168 | ||
169 | -- TODO add Regular event | 169 | -- TODO add Regular event |
170 | putEvent :: Putter (Maybe Event) | 170 | putEvent :: Putter (Maybe AnnounceEvent) |
171 | putEvent Nothing = putWord32be 0 | 171 | putEvent Nothing = putWord32be 0 |
172 | putEvent (Just e) = putWord32be (eventId e) | 172 | putEvent (Just e) = putWord32be (eventId e) |
173 | 173 | ||
174 | getEvent :: S.Get (Maybe Event) | 174 | getEvent :: S.Get (Maybe AnnounceEvent) |
175 | getEvent = do | 175 | getEvent = 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 | |||
351 | instance FromParam PortNumber where | 351 | instance FromParam PortNumber where |
352 | fromParam bs = fromIntegral <$> (fromParam bs :: Maybe Word32) | 352 | fromParam bs = fromIntegral <$> (fromParam bs :: Maybe Word32) |
353 | 353 | ||
354 | instance FromParam Event where | 354 | instance 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 | ||
69 | fillAnnounceQuery :: PeerInfo -> SAnnounceQuery -> AnnounceQuery | 69 | fillAnnounceQuery :: 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 #-} |
13 | module Network.BitTorrent.Tracker.Session | 14 | module 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 | ||
48 | import Control.Applicative | 45 | import Control.Applicative |
49 | import Control.Exception | 46 | import Control.Exception |
50 | import Control.Concurrent | 47 | import Control.Concurrent |
51 | import Control.Concurrent.Chan.Split | 48 | import Control.Concurrent.Chan.Split as CS |
52 | import Control.Monad | 49 | import Control.Monad |
53 | import Data.Aeson | 50 | import Data.Aeson |
54 | import Data.Aeson.TH | 51 | import Data.Aeson.TH |
@@ -66,6 +63,7 @@ import Data.Torrent.InfoHash | |||
66 | import Data.Torrent.JSON | 63 | import Data.Torrent.JSON |
67 | import Network.BitTorrent.Core | 64 | import Network.BitTorrent.Core |
68 | import Network.BitTorrent.Internal.Cache | 65 | import Network.BitTorrent.Internal.Cache |
66 | import Network.BitTorrent.Internal.Types | ||
69 | import Network.BitTorrent.Tracker.List as TL | 67 | import Network.BitTorrent.Tracker.List as TL |
70 | import Network.BitTorrent.Tracker.Message | 68 | import Network.BitTorrent.Tracker.Message |
71 | import Network.BitTorrent.Tracker.RPC as RPC | 69 | import 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? |
126 | needNotify :: Event -> Maybe Status -> Maybe Bool | 124 | needNotify :: AnnounceEvent -> Maybe Status -> Maybe Bool |
127 | needNotify Started Nothing = Just True | 125 | needNotify Started Nothing = Just True |
128 | needNotify Stopped Nothing = Just False | 126 | needNotify Stopped Nothing = Just False |
129 | needNotify Completed Nothing = Just False | 127 | needNotify Completed Nothing = Just False |
@@ -135,7 +133,7 @@ needNotify Stopped (Just Paused ) = Just False | |||
135 | needNotify Completed (Just Paused ) = Just True | 133 | needNotify Completed (Just Paused ) = Just True |
136 | 134 | ||
137 | -- | Client status after event announce succeed. | 135 | -- | Client status after event announce succeed. |
138 | nextStatus :: Event -> Maybe Status | 136 | nextStatus :: AnnounceEvent -> Maybe Status |
139 | nextStatus Started = Just Running | 137 | nextStatus Started = Just Running |
140 | nextStatus Stopped = Just Paused | 138 | nextStatus Stopped = Just Paused |
141 | nextStatus Completed = Nothing -- must keep previous status | 139 | nextStatus 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. |
162 | notifyTo :: Manager -> Session -> Event | 160 | notifyTo :: Manager -> Session -> AnnounceEvent |
163 | -> TierEntry TrackerSession -> IO TrackerSession | 161 | -> TierEntry TrackerSession -> IO TrackerSession |
164 | notifyTo mgr s @ Session {..} event (uri, entry @ TrackerSession {..}) = do | 162 | notifyTo 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 | ||
197 | instance 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 | |||
227 | data SessionEvent | ||
228 | = TrackerAdded URI | ||
229 | | TrackerConfirmed URI | ||
230 | | TrackerRemoved URI | ||
231 | | AnnouncedTo URI | ||
232 | | SessionClosed | ||
233 | |||
234 | subscribe :: Session -> IO (ReceivePort SessionEvent) | ||
235 | subscribe 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? |
256 | allNotify :: Event -> Bool | 251 | allNotify :: AnnounceEvent -> Bool |
257 | allNotify Started = False | 252 | allNotify Started = False |
258 | allNotify Stopped = True | 253 | allNotify Stopped = True |
259 | allNotify Completed = True | 254 | allNotify Completed = True |
260 | 255 | ||
261 | notifyAll :: Manager -> Session -> Event -> IO () | 256 | notifyAll :: Manager -> Session -> AnnounceEvent -> IO () |
262 | notifyAll mgr s @ Session {..} event = do | 257 | notifyAll 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. |
274 | notify :: Manager -> Session -> Event -> IO () | 269 | notify :: Manager -> Session -> AnnounceEvent -> IO () |
275 | notify mgr ses event = do | 270 | notify 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) |