From 30a3dc92168c3c82d4cfd7a773cd3b63f34a6b03 Mon Sep 17 00:00:00 2001 From: Sam Truzjan Date: Fri, 3 Jan 2014 22:51:16 +0400 Subject: Add basic gettorrent implementation --- bittorrent.cabal | 4 ++++ examples/GetTorrent.hs | 53 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/bittorrent.cabal b/bittorrent.cabal index 347cc38d..f1b2823f 100644 --- a/bittorrent.cabal +++ b/bittorrent.cabal @@ -244,6 +244,10 @@ executable gettorrent build-depends: base == 4.* , optparse-applicative , data-default + , conduit + , mtl + , network + , filepath , bittorrent executable client-example diff --git a/examples/GetTorrent.hs b/examples/GetTorrent.hs index a9d2a44f..5e624fa1 100644 --- a/examples/GetTorrent.hs +++ b/examples/GetTorrent.hs @@ -1,27 +1,49 @@ +{-# LANGUAGE RecordWildCards #-} module Main (main) where +import Control.Applicative +import Control.Concurrent +import Control.Monad +import Control.Monad.Trans +import Data.Conduit as C +import Data.Conduit.List as C import Data.Default - +import Data.Maybe +import Network.URI import Options.Applicative +import System.Exit +import System.FilePath + +import Data.Torrent import Data.Torrent.InfoHash import Network.BitTorrent.Core +import Network.BitTorrent.DHT.Session +import Network.BitTorrent.DHT as DHT +import Network.BitTorrent.Exchange.Message +import Network.BitTorrent.Exchange.Wire data Params = Params - { infohash :: InfoHash + { topic :: InfoHash , thisNode :: NodeAddr IPv4 , bootNode :: NodeAddr IPv4 + , buckets :: Int } deriving Show paramsParser :: Parser Params paramsParser = Params <$> option (long "infohash" <> short 'i' <> metavar "SHA1" <> help "infohash of torrent file") - <*> option (long "node" <> short 'n' <> value def - <> metavar "NODE" <> help "this node address" + <*> option (long "port" <> short 'p' + <> value def <> showDefault + <> metavar "NUM" <> help "port number to bind" ) <*> option (long "boot" <> short 'b' <> metavar "NODE" <> help "bootstrap node address" ) + <*> option (long "bucket" <> short 'n' + <> value 2 <> showDefault + <> metavar "NUM" <> help "number of buckets to maintain" + ) programInfo :: ParserInfo Params programInfo = info (helper <*> paramsParser) @@ -30,8 +52,29 @@ programInfo = info (helper <*> paramsParser) <> header "gettorrent - get torrent file by infohash" ) +fakeTracker :: URI +fakeTracker = fromJust $ parseURI "http://foo.org" + +exchangeTorrent :: PeerAddr IP -> InfoHash -> IO InfoDict +exchangeTorrent addr ih = do + pid <- genPeerId + var <- newEmptyMVar + let hs = Handshake def (toCaps [ExtExtended]) ih pid + connectWire hs addr (toCaps [ExtMetadata]) $ do + infodict <- getMetadata + liftIO $ putMVar var infodict + takeMVar var + getTorrent :: Params -> IO () -getTorrent = print +getTorrent Params {..} = do + dht (def { optBucketCount = buckets }) thisNode $ do + bootstrap [bootNode] + DHT.lookup topic $$ C.mapM_ $ \ peers -> do + liftIO $ forM_ peers $ \ peer -> do + infodict <- exchangeTorrent (IPv4 <$> peer) topic + let torrent = nullTorrent fakeTracker infodict + toFile (show topic <.> torrentExt) torrent + exitSuccess main :: IO () main = execParser programInfo >>= getTorrent -- cgit v1.2.3