diff options
author | Sam Truzjan <pxqr.sta@gmail.com> | 2014-01-23 02:47:42 +0400 |
---|---|---|
committer | Sam Truzjan <pxqr.sta@gmail.com> | 2014-01-23 02:47:42 +0400 |
commit | 7e61a78b975e586cde5c7f2729e5943d7a44699a (patch) | |
tree | d20037d9bc41bcbce9e3d4bf4b93058fbcb19e57 /src/Network/BitTorrent | |
parent | 5d5c52d5a558b49fb8db814198315627d1c119e5 (diff) |
Add class MonadDHT
Diffstat (limited to 'src/Network/BitTorrent')
-rw-r--r-- | src/Network/BitTorrent/DHT.hs | 32 | ||||
-rw-r--r-- | src/Network/BitTorrent/DHT/Session.hs | 59 |
2 files changed, 69 insertions, 22 deletions
diff --git a/src/Network/BitTorrent/DHT.hs b/src/Network/BitTorrent/DHT.hs index 77bb9da9..a97ebcf7 100644 --- a/src/Network/BitTorrent/DHT.hs +++ b/src/Network/BitTorrent/DHT.hs | |||
@@ -20,6 +20,7 @@ | |||
20 | module Network.BitTorrent.DHT | 20 | module Network.BitTorrent.DHT |
21 | ( -- * Distributed Hash Table | 21 | ( -- * Distributed Hash Table |
22 | DHT | 22 | DHT |
23 | , MonadDHT (..) | ||
23 | , dht | 24 | , dht |
24 | 25 | ||
25 | -- * Initialization | 26 | -- * Initialization |
@@ -31,6 +32,14 @@ module Network.BitTorrent.DHT | |||
31 | , Network.BitTorrent.DHT.lookup | 32 | , Network.BitTorrent.DHT.lookup |
32 | , Network.BitTorrent.DHT.insert | 33 | , Network.BitTorrent.DHT.insert |
33 | , Network.BitTorrent.DHT.delete | 34 | , Network.BitTorrent.DHT.delete |
35 | |||
36 | -- * Internal | ||
37 | -- | Can be used to implement instance of 'MonadDHT'. | ||
38 | , LogFun | ||
39 | , Node | ||
40 | , handlers | ||
41 | , startNode | ||
42 | , runDHT | ||
34 | ) where | 43 | ) where |
35 | 44 | ||
36 | import Control.Applicative | 45 | import Control.Applicative |
@@ -45,6 +54,15 @@ import Data.Torrent.InfoHash | |||
45 | import Network.BitTorrent.Core | 54 | import Network.BitTorrent.Core |
46 | import Network.BitTorrent.DHT.Session | 55 | import Network.BitTorrent.DHT.Session |
47 | 56 | ||
57 | {----------------------------------------------------------------------- | ||
58 | -- DHT types | ||
59 | -----------------------------------------------------------------------} | ||
60 | |||
61 | class MonadDHT m where | ||
62 | liftDHT :: DHT IPv4 a -> m a | ||
63 | |||
64 | instance MonadDHT (DHT IPv4) where | ||
65 | liftDHT = id | ||
48 | 66 | ||
49 | -- | Run DHT on specified port. <add note about resources> | 67 | -- | Run DHT on specified port. <add note about resources> |
50 | dht :: Address ip | 68 | dht :: Address ip |
@@ -52,9 +70,17 @@ dht :: Address ip | |||
52 | -> NodeAddr ip -- ^ address to bind this node; | 70 | -> NodeAddr ip -- ^ address to bind this node; |
53 | -> DHT ip a -- ^ actions to run: 'bootstrap', 'lookup', etc; | 71 | -> DHT ip a -- ^ actions to run: 'bootstrap', 'lookup', etc; |
54 | -> IO a -- ^ result. | 72 | -> IO a -- ^ result. |
55 | dht = runDHT handlers | 73 | dht opts addr action = do |
74 | runResourceT $ do | ||
75 | runStderrLoggingT $ LoggingT $ \ logger -> do | ||
76 | node <- startNode handlers opts addr logger | ||
77 | runDHT node action | ||
56 | {-# INLINE dht #-} | 78 | {-# INLINE dht #-} |
57 | 79 | ||
80 | {----------------------------------------------------------------------- | ||
81 | -- Initialization | ||
82 | -----------------------------------------------------------------------} | ||
83 | |||
58 | -- | One good node may be sufficient. The list of bootstrapping nodes | 84 | -- | One good node may be sufficient. The list of bootstrapping nodes |
59 | -- usually obtained from 'Data.Torrent.tNodes' field. Bootstrapping | 85 | -- usually obtained from 'Data.Torrent.tNodes' field. Bootstrapping |
60 | -- process can take up to 5 minutes. | 86 | -- process can take up to 5 minutes. |
@@ -87,6 +113,10 @@ restore = error "DHT.restore: not implemented" | |||
87 | snapshot :: DHT ip ByteString | 113 | snapshot :: DHT ip ByteString |
88 | snapshot = error "DHT.snapshot: not implemented" | 114 | snapshot = error "DHT.snapshot: not implemented" |
89 | 115 | ||
116 | {----------------------------------------------------------------------- | ||
117 | -- Operations | ||
118 | -----------------------------------------------------------------------} | ||
119 | |||
90 | -- | Get list of peers which downloading this torrent. | 120 | -- | Get list of peers which downloading this torrent. |
91 | -- | 121 | -- |
92 | -- This operation is incremental and do block. | 122 | -- This operation is incremental and do block. |
diff --git a/src/Network/BitTorrent/DHT/Session.hs b/src/Network/BitTorrent/DHT/Session.hs index 9455c465..50ca6db3 100644 --- a/src/Network/BitTorrent/DHT/Session.hs +++ b/src/Network/BitTorrent/DHT/Session.hs | |||
@@ -1,3 +1,10 @@ | |||
1 | -- | | ||
2 | -- Copyright : (c) Sam Truzjan 2013 | ||
3 | -- License : BSD3 | ||
4 | -- Maintainer : pxqr.sta@gmail.com | ||
5 | -- Stability : experimental | ||
6 | -- Portability : portable | ||
7 | -- | ||
1 | {-# LANGUAGE RecordWildCards #-} | 8 | {-# LANGUAGE RecordWildCards #-} |
2 | {-# LANGUAGE FlexibleContexts #-} | 9 | {-# LANGUAGE FlexibleContexts #-} |
3 | {-# LANGUAGE FlexibleInstances #-} | 10 | {-# LANGUAGE FlexibleInstances #-} |
@@ -14,6 +21,11 @@ module Network.BitTorrent.DHT.Session | |||
14 | , defaultK | 21 | , defaultK |
15 | , Options (..) | 22 | , Options (..) |
16 | 23 | ||
24 | -- * Node | ||
25 | , LogFun | ||
26 | , Node | ||
27 | , startNode | ||
28 | |||
17 | -- * Session | 29 | -- * Session |
18 | , DHT | 30 | , DHT |
19 | , runDHT | 31 | , runDHT |
@@ -233,7 +245,7 @@ invalidateTokens curTime ts @ SessionTokens {..} | |||
233 | type AnnounceSet = Set (InfoHash, PortNumber) | 245 | type AnnounceSet = Set (InfoHash, PortNumber) |
234 | 246 | ||
235 | -- | Logger function. | 247 | -- | Logger function. |
236 | type Logger = Loc -> LogSource -> LogLevel -> LogStr -> IO () | 248 | type LogFun = Loc -> LogSource -> LogLevel -> LogStr -> IO () |
237 | 249 | ||
238 | -- | DHT session keep track state of /this/ node. | 250 | -- | DHT session keep track state of /this/ node. |
239 | data Node ip = Node | 251 | data Node ip = Node |
@@ -244,7 +256,7 @@ data Node ip = Node | |||
244 | , contactInfo :: !(TVar (PeerStore ip)) -- ^ published by other nodes; | 256 | , contactInfo :: !(TVar (PeerStore ip)) -- ^ published by other nodes; |
245 | , announceInfo :: !(TVar AnnounceSet ) -- ^ to publish by this node; | 257 | , announceInfo :: !(TVar AnnounceSet ) -- ^ to publish by this node; |
246 | , sessionTokens :: !(TVar SessionTokens) -- ^ query session IDs. | 258 | , sessionTokens :: !(TVar SessionTokens) -- ^ query session IDs. |
247 | , loggerFun :: !Logger | 259 | , loggerFun :: !LogFun |
248 | } | 260 | } |
249 | 261 | ||
250 | -- | DHT keep track current session and proper resource allocation for | 262 | -- | DHT keep track current session and proper resource allocation for |
@@ -274,28 +286,35 @@ instance MonadLogger (DHT ip) where | |||
274 | logger <- asks loggerFun | 286 | logger <- asks loggerFun |
275 | liftIO $ logger loc src lvl (toLogStr msg) | 287 | liftIO $ logger loc src lvl (toLogStr msg) |
276 | 288 | ||
289 | type NodeHandler ip = Handler (DHT ip) | ||
290 | |||
277 | -- | Run DHT session. Some resources like listener thread may live for | 291 | -- | Run DHT session. Some resources like listener thread may live for |
278 | -- some short period of time right after this DHT session closed. | 292 | -- some short period of time right after this DHT session closed. |
279 | runDHT :: forall ip a. Address ip | 293 | startNode :: Address ip |
280 | => [Handler (DHT ip)] -- ^ handlers to run on accepted queries; | 294 | => [NodeHandler ip] -- ^ handlers to run on accepted queries; |
281 | -> Options -- ^ various dht options; | 295 | -> Options -- ^ various dht options; |
282 | -> NodeAddr ip -- ^ node address to bind; | 296 | -> NodeAddr ip -- ^ node address to bind; |
283 | -> DHT ip a -- ^ DHT action to run; | 297 | -> LogFun -- ^ |
284 | -> IO a -- ^ result. | 298 | -> ResIO (Node ip) -- ^ a new DHT node running at given address. |
285 | runDHT hs opts naddr action = runResourceT $ do | 299 | startNode hs opts naddr logger = do |
286 | runStderrLoggingT $ LoggingT $ \ logger -> do | 300 | -- (_, m) <- allocate (newManager rpcOpts nodeAddr hs) closeManager |
287 | let rpcOpts = KRPC.def { optQueryTimeout = seconds (optTimeout opts) } | 301 | m <- liftIO $ newManager rpcOpts nodeAddr hs |
288 | let nodeAddr = toSockAddr naddr | ||
289 | (_, m) <- allocate (newManager rpcOpts nodeAddr hs) closeManager | ||
290 | myId <- liftIO genNodeId | 302 | myId <- liftIO genNodeId |
291 | node <- liftIO $ Node opts myId m | 303 | node <- liftIO $ Node opts myId m |
292 | <$> newMVar (nullTable myId (optBucketCount opts)) | 304 | <$> newMVar (nullTable myId (optBucketCount opts)) |
293 | <*> newTVarIO def | 305 | <*> newTVarIO def |
294 | <*> newTVarIO S.empty | 306 | <*> newTVarIO S.empty |
295 | <*> (newTVarIO =<< nullSessionTokens) | 307 | <*> (newTVarIO =<< nullSessionTokens) |
296 | <*> pure logger | 308 | <*> pure logger |
297 | runReaderT (unDHT (listen >> action)) node | 309 | runReaderT (unDHT listen) node |
310 | return node | ||
311 | where | ||
312 | rpcOpts = KRPC.def { optQueryTimeout = seconds (optTimeout opts) } | ||
313 | nodeAddr = toSockAddr naddr | ||
298 | 314 | ||
315 | runDHT :: Node ip -> DHT ip a -> ResIO a | ||
316 | runDHT node action = runReaderT (unDHT action) node | ||
317 | {-# INLINE runDHT #-} | ||
299 | 318 | ||
300 | askOption :: (Options -> a) -> DHT ip a | 319 | askOption :: (Options -> a) -> DHT ip a |
301 | askOption f = asks (f . options) | 320 | askOption f = asks (f . options) |
@@ -475,8 +494,6 @@ ping addr = do | |||
475 | (nid, Ping) <- queryNode addr Ping | 494 | (nid, Ping) <- queryNode addr Ping |
476 | return (NodeInfo nid addr) | 495 | return (NodeInfo nid addr) |
477 | 496 | ||
478 | type NodeHandler ip = Handler (DHT ip) | ||
479 | |||
480 | nodeHandler :: Address ip => KRPC (Query a) (Response b) | 497 | nodeHandler :: Address ip => KRPC (Query a) (Response b) |
481 | => (NodeAddr ip -> a -> DHT ip b) -> NodeHandler ip | 498 | => (NodeAddr ip -> a -> DHT ip b) -> NodeHandler ip |
482 | nodeHandler action = handler $ \ sockAddr (Query remoteId q) -> do | 499 | nodeHandler action = handler $ \ sockAddr (Query remoteId q) -> do |