diff options
Diffstat (limited to 'examples/MkTorrent.hs')
-rw-r--r-- | examples/MkTorrent.hs | 78 |
1 files changed, 74 insertions, 4 deletions
diff --git a/examples/MkTorrent.hs b/examples/MkTorrent.hs index 16e1e245..ab3144b4 100644 --- a/examples/MkTorrent.hs +++ b/examples/MkTorrent.hs | |||
@@ -5,12 +5,16 @@ | |||
5 | module Main (main) where | 5 | module Main (main) where |
6 | 6 | ||
7 | import Prelude as P | 7 | import Prelude as P |
8 | import Control.Concurrent | ||
8 | import Control.Concurrent.ParallelIO | 9 | import Control.Concurrent.ParallelIO |
9 | import Control.Exception | 10 | import Control.Exception |
10 | import Control.Lens hiding (argument) | 11 | import Control.Lens hiding (argument, (<.>)) |
11 | import Control.Monad | 12 | import Control.Monad |
13 | import Control.Monad.Trans | ||
14 | import Data.Conduit as C | ||
15 | import Data.Conduit.List as C | ||
12 | import Data.List as L | 16 | import Data.List as L |
13 | import Data.Maybe | 17 | import Data.Maybe as L |
14 | import Data.Monoid | 18 | import Data.Monoid |
15 | import Data.Text as T | 19 | import Data.Text as T |
16 | import qualified Data.Text.IO as T | 20 | import qualified Data.Text.IO as T |
@@ -18,18 +22,25 @@ import Data.Text.Read as T | |||
18 | import Data.Version | 22 | import Data.Version |
19 | import Network.URI | 23 | import Network.URI |
20 | import Options.Applicative | 24 | import Options.Applicative |
25 | import System.Exit | ||
26 | import System.FilePath | ||
21 | import System.Log | 27 | import System.Log |
22 | import System.Log.Logger | 28 | import System.Log.Logger |
23 | import System.Exit | ||
24 | import Text.Read | 29 | import Text.Read |
25 | import Text.PrettyPrint.Class | 30 | import Text.PrettyPrint.Class |
26 | 31 | ||
27 | import Paths_bittorrent (version) | 32 | import Paths_bittorrent (version) |
28 | import Data.Torrent | 33 | import Data.Torrent |
29 | import Data.Torrent.Bitfield as BF | 34 | import Data.Torrent.Bitfield as BF |
35 | import Data.Torrent.InfoHash | ||
30 | import Data.Torrent.Piece | 36 | import Data.Torrent.Piece |
31 | import Data.Torrent.Layout | 37 | import Data.Torrent.Layout |
32 | import Data.Torrent.Magnet hiding (Magnet) | 38 | import Data.Torrent.Magnet hiding (Magnet) |
39 | import Network.BitTorrent.Core | ||
40 | import Network.BitTorrent.DHT.Session hiding (Options) | ||
41 | import Network.BitTorrent.DHT as DHT | ||
42 | import Network.BitTorrent.Exchange.Message | ||
43 | import Network.BitTorrent.Exchange.Wire hiding (Options) | ||
33 | import System.Torrent.Storage | 44 | import System.Torrent.Storage |
34 | 45 | ||
35 | 46 | ||
@@ -179,7 +190,7 @@ validateStorage s pinfo = do | |||
179 | let total = totalPieces s | 190 | let total = totalPieces s |
180 | pixs <- parallel $ L.map (validatePiece s pinfo) [0 .. total - 1] | 191 | pixs <- parallel $ L.map (validatePiece s pinfo) [0 .. total - 1] |
181 | infoM "check" "storage validation finished" | 192 | infoM "check" "storage validation finished" |
182 | return $ fromList total $ catMaybes pixs | 193 | return $ fromList total $ L.catMaybes pixs |
183 | 194 | ||
184 | -- TODO use local thread pool | 195 | -- TODO use local thread pool |
185 | checkContent :: Storage -> PieceInfo -> IO () | 196 | checkContent :: Storage -> PieceInfo -> IO () |
@@ -297,6 +308,62 @@ putTorrent opts @ ShowOpts {..} = do | |||
297 | msg = "Torrent file is either invalid or do not exist" | 308 | msg = "Torrent file is either invalid or do not exist" |
298 | 309 | ||
299 | {----------------------------------------------------------------------- | 310 | {----------------------------------------------------------------------- |
311 | -- Get command - fetch torrent by infohash | ||
312 | -----------------------------------------------------------------------} | ||
313 | |||
314 | data GetOpts = GetOpts | ||
315 | { topic :: InfoHash | ||
316 | , thisNode :: NodeAddr IPv4 | ||
317 | , bootNode :: NodeAddr IPv4 | ||
318 | , buckets :: Int | ||
319 | } deriving Show | ||
320 | |||
321 | paramsParser :: Parser GetOpts | ||
322 | paramsParser = GetOpts | ||
323 | <$> option (long "infohash" <> short 'i' | ||
324 | <> metavar "SHA1" <> help "infohash of torrent file") | ||
325 | <*> option (long "port" <> short 'p' | ||
326 | <> value def <> showDefault | ||
327 | <> metavar "NUM" <> help "port number to bind" | ||
328 | ) | ||
329 | <*> option (long "boot" <> short 'b' | ||
330 | <> metavar "NODE" <> help "bootstrap node address" | ||
331 | ) | ||
332 | <*> option (long "bucket" <> short 'n' | ||
333 | <> value 2 <> showDefault | ||
334 | <> metavar "NUM" <> help "number of buckets to maintain" | ||
335 | ) | ||
336 | |||
337 | getInfo :: ParserInfo GetOpts | ||
338 | getInfo = info (helper <*> paramsParser) | ||
339 | ( fullDesc | ||
340 | <> progDesc "Get torrent file by infohash" | ||
341 | <> header "get torrent file by infohash" | ||
342 | ) | ||
343 | |||
344 | exchangeTorrent :: PeerAddr IP -> InfoHash -> IO InfoDict | ||
345 | exchangeTorrent addr ih = do | ||
346 | pid <- genPeerId | ||
347 | var <- newEmptyMVar | ||
348 | let hs = Handshake def (toCaps [ExtExtended]) ih pid | ||
349 | connectWire hs addr (toCaps [ExtMetadata]) $ do | ||
350 | infodict <- getMetadata | ||
351 | liftIO $ putMVar var infodict | ||
352 | takeMVar var | ||
353 | |||
354 | getTorrent :: GetOpts -> IO () | ||
355 | getTorrent GetOpts {..} = do | ||
356 | dht (def { optBucketCount = buckets }) thisNode $ do | ||
357 | bootstrap [bootNode] | ||
358 | DHT.lookup topic $$ C.mapM_ $ \ peers -> do | ||
359 | liftIO $ forM_ peers $ \ peer -> do | ||
360 | infodict <- exchangeTorrent (IPv4 <$> peer) topic | ||
361 | -- TODO add tNodes, tCreated, etc? | ||
362 | let torrent = nullTorrent infodict | ||
363 | toFile (show topic <.> torrentExt) torrent | ||
364 | exitSuccess | ||
365 | |||
366 | {----------------------------------------------------------------------- | ||
300 | -- Command | 367 | -- Command |
301 | -----------------------------------------------------------------------} | 368 | -----------------------------------------------------------------------} |
302 | 369 | ||
@@ -304,6 +371,7 @@ data Command | |||
304 | = Amend AmendOpts | 371 | = Amend AmendOpts |
305 | | Check CheckOpts | 372 | | Check CheckOpts |
306 | -- | Create CreateOpts | 373 | -- | Create CreateOpts |
374 | | Get GetOpts | ||
307 | | Magnet MagnetOpts | 375 | | Magnet MagnetOpts |
308 | | Show ShowOpts | 376 | | Show ShowOpts |
309 | deriving Show | 377 | deriving Show |
@@ -313,6 +381,7 @@ commandOpts = subparser $ mconcat | |||
313 | [ command "amend" (Amend <$> amendInfo) | 381 | [ command "amend" (Amend <$> amendInfo) |
314 | , command "check" (Check <$> checkInfo) | 382 | , command "check" (Check <$> checkInfo) |
315 | -- , command "create" (Create <$> createInfo) | 383 | -- , command "create" (Create <$> createInfo) |
384 | , command "get" (Get <$> getInfo) | ||
316 | , command "magnet" (Magnet <$> magnetInfo) | 385 | , command "magnet" (Magnet <$> magnetInfo) |
317 | , command "show" (Show <$> showInfo) | 386 | , command "show" (Show <$> showInfo) |
318 | ] | 387 | ] |
@@ -396,6 +465,7 @@ run :: Command -> IO () | |||
396 | run (Amend opts) = amend opts | 465 | run (Amend opts) = amend opts |
397 | run (Check opts) = checkTorrent opts | 466 | run (Check opts) = checkTorrent opts |
398 | --run (Create opts) = createTorrent opts | 467 | --run (Create opts) = createTorrent opts |
468 | run (Get opts) = getTorrent opts | ||
399 | run (Magnet opts) = magnet opts | 469 | run (Magnet opts) = magnet opts |
400 | run (Show opts) = putTorrent opts | 470 | run (Show opts) = putTorrent opts |
401 | 471 | ||