summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bittorrent.cabal2
-rw-r--r--examples/MkTorrent.hs54
-rw-r--r--src/Network/BitTorrent/Exchange.hs1
-rw-r--r--src/Network/BitTorrent/Exchange/Session.hs12
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
7import Prelude as P 7import Prelude as P
8import Control.Concurrent 8import Control.Concurrent
9import Control.Concurrent.Async 9import Control.Concurrent.Async.Lifted
10import Control.Concurrent.ParallelIO 10import Control.Concurrent.ParallelIO
11import Control.Exception 11import Control.Exception
12import Control.Lens hiding (argument, (<.>)) 12import Control.Lens hiding (argument, (<.>))
13import Control.Monad 13import Control.Monad as M
14import Control.Monad.Trans 14import Control.Monad.Trans
15import Data.Conduit as C 15import Data.Conduit as C
16import Data.Conduit.List as C
16import Data.List as L 17import Data.List as L
17import Data.Maybe as L 18import Data.Maybe as L
18import Data.Monoid 19import Data.Monoid
@@ -31,17 +32,14 @@ import Text.Read
31import Text.PrettyPrint.Class 32import Text.PrettyPrint.Class
32 33
33import Paths_bittorrent (version) 34import Paths_bittorrent (version)
34import Data.Torrent 35import Data.Torrent hiding (Magnet (Magnet))
35import Data.Torrent.Bitfield as BF 36import Network.BitTorrent.Address
36import Data.Torrent.InfoHash
37import Data.Torrent.Piece
38import Data.Torrent.Layout
39import Data.Torrent.Magnet hiding (Magnet)
40import Network.BitTorrent.Core
41import Network.BitTorrent.DHT.Session hiding (Options, options) 37import Network.BitTorrent.DHT.Session hiding (Options, options)
42import Network.BitTorrent.DHT as DHT hiding (Options) 38import Network.BitTorrent.DHT as DHT hiding (Options)
43import Network.BitTorrent.Exchange.Message 39import Network.BitTorrent.Exchange.Bitfield as BF
44import Network.BitTorrent.Exchange.Connection hiding (Options) 40import Network.BitTorrent.Exchange.Connection hiding (Options)
41import Network.BitTorrent.Exchange.Message
42import Network.BitTorrent.Exchange.Session
45import System.Torrent.Storage 43import 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
359exchangeTorrent :: InfoHash -> PeerAddr IP -> IO InfoDict
360exchangeTorrent 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
370exchangeConc :: InfoHash -> [PeerAddr IP] -> IO (Maybe InfoDict)
371exchangeConc ih peers = do
372 workers <- forM peers $ async . exchangeTorrent ih
373 (_, result) <- waitAnyCatchCancel workers
374 return $ either (const Nothing) Just result
375
376sinkInfoDict :: InfoHash -> Sink [PeerAddr IPv4] (DHT ip) InfoDict
377sinkInfoDict 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?
386getTorrent :: GetOpts -> IO () 358getTorrent :: GetOpts -> IO ()
387getTorrent GetOpts {..} = do 359getTorrent 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
32import Network.BitTorrent.Exchange.Manager 33import 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
29import Control.Concurrent.STM 30import Control.Concurrent.STM
30import Control.Exception hiding (Handler) 31import Control.Exception hiding (Handler)
31import Control.Lens 32import Control.Lens
33import Control.Monad as M
32import Control.Monad.Logger 34import Control.Monad.Logger
33import Control.Monad.Reader 35import Control.Monad.Reader
34import Data.ByteString as BS 36import Data.ByteString as BS
35import Data.ByteString.Lazy as BL 37import Data.ByteString.Lazy as BL
36import Data.Conduit 38import Data.Conduit as C
37import Data.Conduit.List as CL (iterM) 39import Data.Conduit.List as C
38import Data.Map as M 40import Data.Map as M
39import Data.Monoid 41import Data.Monoid
40import Data.Set as S 42import Data.Set as S
@@ -333,6 +335,12 @@ establish :: PendingConnection -> Session -> IO ()
333establish conn = runConnection (acceptWire conn) (closePending conn) 335establish conn = runConnection (acceptWire conn) (closePending conn)
334 (pendingPeer conn) 336 (pendingPeer conn)
335 337
338-- | Conduit version of 'connect'.
339connectSink :: MonadIO m => Session -> Sink [PeerAddr IPv4] m ()
340connectSink 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?
337type BroadcastMessage = ExtendedCaps -> Message 345type BroadcastMessage = ExtendedCaps -> Message
338 346