diff options
-rw-r--r-- | bittorrent.cabal | 2 | ||||
-rw-r--r-- | examples/MkTorrent.hs | 54 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange.hs | 1 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange/Session.hs | 12 |
4 files changed, 25 insertions, 44 deletions
diff --git a/bittorrent.cabal b/bittorrent.cabal index 550a727d..dea8642b 100644 --- a/bittorrent.cabal +++ b/bittorrent.cabal | |||
@@ -289,7 +289,7 @@ executable mktorrent | |||
289 | , mtl | 289 | , mtl |
290 | , conduit | 290 | , conduit |
291 | , lens | 291 | , lens |
292 | , async | 292 | , lifted-async |
293 | , parallel-io | 293 | , parallel-io |
294 | 294 | ||
295 | , network | 295 | , network |
diff --git a/examples/MkTorrent.hs b/examples/MkTorrent.hs index 960f5acb..58e14af1 100644 --- a/examples/MkTorrent.hs +++ b/examples/MkTorrent.hs | |||
@@ -6,13 +6,14 @@ module Main (main) where | |||
6 | 6 | ||
7 | import Prelude as P | 7 | import Prelude as P |
8 | import Control.Concurrent | 8 | import Control.Concurrent |
9 | import Control.Concurrent.Async | 9 | import Control.Concurrent.Async.Lifted |
10 | import Control.Concurrent.ParallelIO | 10 | import Control.Concurrent.ParallelIO |
11 | import Control.Exception | 11 | import Control.Exception |
12 | import Control.Lens hiding (argument, (<.>)) | 12 | import Control.Lens hiding (argument, (<.>)) |
13 | import Control.Monad | 13 | import Control.Monad as M |
14 | import Control.Monad.Trans | 14 | import Control.Monad.Trans |
15 | import Data.Conduit as C | 15 | import Data.Conduit as C |
16 | import Data.Conduit.List as C | ||
16 | import Data.List as L | 17 | import Data.List as L |
17 | import Data.Maybe as L | 18 | import Data.Maybe as L |
18 | import Data.Monoid | 19 | import Data.Monoid |
@@ -31,17 +32,14 @@ import Text.Read | |||
31 | import Text.PrettyPrint.Class | 32 | import Text.PrettyPrint.Class |
32 | 33 | ||
33 | import Paths_bittorrent (version) | 34 | import Paths_bittorrent (version) |
34 | import Data.Torrent | 35 | import Data.Torrent hiding (Magnet (Magnet)) |
35 | import Data.Torrent.Bitfield as BF | 36 | import Network.BitTorrent.Address |
36 | import Data.Torrent.InfoHash | ||
37 | import Data.Torrent.Piece | ||
38 | import Data.Torrent.Layout | ||
39 | import Data.Torrent.Magnet hiding (Magnet) | ||
40 | import Network.BitTorrent.Core | ||
41 | import Network.BitTorrent.DHT.Session hiding (Options, options) | 37 | import Network.BitTorrent.DHT.Session hiding (Options, options) |
42 | import Network.BitTorrent.DHT as DHT hiding (Options) | 38 | import Network.BitTorrent.DHT as DHT hiding (Options) |
43 | import Network.BitTorrent.Exchange.Message | 39 | import Network.BitTorrent.Exchange.Bitfield as BF |
44 | import Network.BitTorrent.Exchange.Connection hiding (Options) | 40 | import Network.BitTorrent.Exchange.Connection hiding (Options) |
41 | import Network.BitTorrent.Exchange.Message | ||
42 | import Network.BitTorrent.Exchange.Session | ||
45 | import System.Torrent.Storage | 43 | import System.Torrent.Storage |
46 | 44 | ||
47 | 45 | ||
@@ -356,43 +354,17 @@ getInfo = info (helper <*> paramsParser) | |||
356 | <> header "get torrent file by infohash" | 354 | <> header "get torrent file by infohash" |
357 | ) | 355 | ) |
358 | 356 | ||
359 | exchangeTorrent :: InfoHash -> PeerAddr IP -> IO InfoDict | ||
360 | exchangeTorrent ih addr = do | ||
361 | pid <- genPeerId | ||
362 | var <- newEmptyMVar | ||
363 | let hs = Handshake def (toCaps [ExtExtended]) ih pid | ||
364 | chan <- newChan | ||
365 | connectWire () hs addr (toCaps [ExtMetadata]) chan $ do | ||
366 | infodict <- undefined -- getMetadata | ||
367 | liftIO $ putMVar var infodict | ||
368 | takeMVar var | ||
369 | |||
370 | exchangeConc :: InfoHash -> [PeerAddr IP] -> IO (Maybe InfoDict) | ||
371 | exchangeConc ih peers = do | ||
372 | workers <- forM peers $ async . exchangeTorrent ih | ||
373 | (_, result) <- waitAnyCatchCancel workers | ||
374 | return $ either (const Nothing) Just result | ||
375 | |||
376 | sinkInfoDict :: InfoHash -> Sink [PeerAddr IPv4] (DHT ip) InfoDict | ||
377 | sinkInfoDict ih = do | ||
378 | m <- await | ||
379 | case m of | ||
380 | Nothing -> liftIO $ throwIO $ userError "impossible: end of peer stream" | ||
381 | Just peers -> do | ||
382 | minfodict <- liftIO $ exchangeConc ih (fmap IPv4 <$> peers) | ||
383 | maybe (sinkInfoDict ih) return minfodict | ||
384 | |||
385 | -- TODO add tNodes, tCreated, etc? | 357 | -- TODO add tNodes, tCreated, etc? |
386 | getTorrent :: GetOpts -> IO () | 358 | getTorrent :: GetOpts -> IO () |
387 | getTorrent GetOpts {..} = do | 359 | getTorrent GetOpts {..} = do |
388 | infoM "get" "starting..." | 360 | infoM "get" "searching for peers..." |
361 | s <- newSession (\ _ _ _ _ -> return ()) (PeerAddr Nothing Nothing 7000) "/tmp" (Left topic) | ||
389 | dht (def { optBucketCount = buckets }) (NodeAddr "0.0.0.0" servPort) $ do | 362 | dht (def { optBucketCount = buckets }) (NodeAddr "0.0.0.0" servPort) $ do |
390 | bootstrap [bootNode] | 363 | bootstrap [bootNode] |
391 | liftIO $ infoM "get" "searching for peers..." | 364 | infodict <- withAsync (DHT.lookup topic $$ connectSink s) |
392 | infodict <- DHT.lookup topic $$ sinkInfoDict topic | 365 | (const (liftIO $ waitMetadata s)) |
393 | liftIO $ infoM "get" "saving torrent file..." | ||
394 | liftIO $ toFile (show topic <.> torrentExt) $ nullTorrent infodict | 366 | liftIO $ toFile (show topic <.> torrentExt) $ nullTorrent infodict |
395 | infoM "get" "done" | 367 | infoM "get" "saved torrent file" |
396 | 368 | ||
397 | {----------------------------------------------------------------------- | 369 | {----------------------------------------------------------------------- |
398 | -- Command | 370 | -- Command |
diff --git a/src/Network/BitTorrent/Exchange.hs b/src/Network/BitTorrent/Exchange.hs index ce71e286..143bf090 100644 --- a/src/Network/BitTorrent/Exchange.hs +++ b/src/Network/BitTorrent/Exchange.hs | |||
@@ -27,6 +27,7 @@ module Network.BitTorrent.Exchange | |||
27 | 27 | ||
28 | -- * Connections | 28 | -- * Connections |
29 | , connect | 29 | , connect |
30 | , connectSink | ||
30 | ) where | 31 | ) where |
31 | 32 | ||
32 | import Network.BitTorrent.Exchange.Manager | 33 | import Network.BitTorrent.Exchange.Manager |
diff --git a/src/Network/BitTorrent/Exchange/Session.hs b/src/Network/BitTorrent/Exchange/Session.hs index 30b7ed0e..2bd275bd 100644 --- a/src/Network/BitTorrent/Exchange/Session.hs +++ b/src/Network/BitTorrent/Exchange/Session.hs | |||
@@ -16,6 +16,7 @@ module Network.BitTorrent.Exchange.Session | |||
16 | 16 | ||
17 | -- * Connection Set | 17 | -- * Connection Set |
18 | , connect | 18 | , connect |
19 | , connectSink | ||
19 | , establish | 20 | , establish |
20 | 21 | ||
21 | -- * Query | 22 | -- * Query |
@@ -29,12 +30,13 @@ import Control.Concurrent.Chan.Split as CS | |||
29 | import Control.Concurrent.STM | 30 | import Control.Concurrent.STM |
30 | import Control.Exception hiding (Handler) | 31 | import Control.Exception hiding (Handler) |
31 | import Control.Lens | 32 | import Control.Lens |
33 | import Control.Monad as M | ||
32 | import Control.Monad.Logger | 34 | import Control.Monad.Logger |
33 | import Control.Monad.Reader | 35 | import Control.Monad.Reader |
34 | import Data.ByteString as BS | 36 | import Data.ByteString as BS |
35 | import Data.ByteString.Lazy as BL | 37 | import Data.ByteString.Lazy as BL |
36 | import Data.Conduit | 38 | import Data.Conduit as C |
37 | import Data.Conduit.List as CL (iterM) | 39 | import Data.Conduit.List as C |
38 | import Data.Map as M | 40 | import Data.Map as M |
39 | import Data.Monoid | 41 | import Data.Monoid |
40 | import Data.Set as S | 42 | import Data.Set as S |
@@ -333,6 +335,12 @@ establish :: PendingConnection -> Session -> IO () | |||
333 | establish conn = runConnection (acceptWire conn) (closePending conn) | 335 | establish conn = runConnection (acceptWire conn) (closePending conn) |
334 | (pendingPeer conn) | 336 | (pendingPeer conn) |
335 | 337 | ||
338 | -- | Conduit version of 'connect'. | ||
339 | connectSink :: MonadIO m => Session -> Sink [PeerAddr IPv4] m () | ||
340 | connectSink s = C.mapM_ (liftIO . connectBatch) | ||
341 | where | ||
342 | connectBatch = M.mapM_ (\ addr -> connect (IPv4 <$> addr) s) | ||
343 | |||
336 | -- | Why do we need this message? | 344 | -- | Why do we need this message? |
337 | type BroadcastMessage = ExtendedCaps -> Message | 345 | type BroadcastMessage = ExtendedCaps -> Message |
338 | 346 | ||