diff options
author | Sam Truzjan <pxqr.sta@gmail.com> | 2014-01-09 05:28:09 +0400 |
---|---|---|
committer | Sam Truzjan <pxqr.sta@gmail.com> | 2014-01-09 05:28:09 +0400 |
commit | 735cddf5d2be9f5423d8e5dba18902d8276896aa (patch) | |
tree | 7e8e3cccb34cef337ba14edbfd62e6c6b8347113 | |
parent | 299a299412b0c3c15966996f3466db3960e324e7 (diff) |
Merge gettorrent to mktorrent
-rw-r--r-- | bittorrent.cabal | 22 | ||||
-rw-r--r-- | examples/GetTorrent.hs | 75 | ||||
-rw-r--r-- | examples/MkTorrent.hs | 78 |
3 files changed, 79 insertions, 96 deletions
diff --git a/bittorrent.cabal b/bittorrent.cabal index 28c26baf..9e63c227 100644 --- a/bittorrent.cabal +++ b/bittorrent.cabal | |||
@@ -104,7 +104,7 @@ library | |||
104 | , transformers-base | 104 | , transformers-base |
105 | 105 | ||
106 | -- Concurrency | 106 | -- Concurrency |
107 | -- , SafeSemaphore | 107 | , SafeSemaphore |
108 | -- , BoundedChan >= 1.0.1.0 | 108 | -- , BoundedChan >= 1.0.1.0 |
109 | , stm >= 2.4 | 109 | , stm >= 2.4 |
110 | 110 | ||
@@ -256,31 +256,19 @@ executable mktorrent | |||
256 | , text | 256 | , text |
257 | , pretty-class | 257 | , pretty-class |
258 | 258 | ||
259 | , mtl | ||
260 | , conduit | ||
259 | , lens | 261 | , lens |
260 | , parallel-io | 262 | , parallel-io |
263 | |||
261 | , network | 264 | , network |
262 | , bittorrent | 265 | , bittorrent |
263 | 266 | ||
267 | , filepath | ||
264 | , optparse-applicative | 268 | , optparse-applicative |
265 | , hslogger | 269 | , hslogger |
266 | ghc-options: -Wall -O2 -threaded | 270 | ghc-options: -Wall -O2 -threaded |
267 | 271 | ||
268 | -- Utility to fetch | ||
269 | executable gettorrent | ||
270 | if !flag(examples) | ||
271 | buildable: False | ||
272 | default-language: Haskell2010 | ||
273 | hs-source-dirs: examples | ||
274 | main-is: GetTorrent.hs | ||
275 | build-depends: base == 4.* | ||
276 | , optparse-applicative | ||
277 | , data-default | ||
278 | , conduit | ||
279 | , mtl | ||
280 | , network | ||
281 | , filepath | ||
282 | , bittorrent | ||
283 | |||
284 | -- nonfunctioning example of very basic bittorrent client | 272 | -- nonfunctioning example of very basic bittorrent client |
285 | executable client | 273 | executable client |
286 | if !flag(examples) | 274 | if !flag(examples) |
diff --git a/examples/GetTorrent.hs b/examples/GetTorrent.hs deleted file mode 100644 index 9a203bf0..00000000 --- a/examples/GetTorrent.hs +++ /dev/null | |||
@@ -1,75 +0,0 @@ | |||
1 | {-# LANGUAGE RecordWildCards #-} | ||
2 | module Main (main) where | ||
3 | import Control.Applicative | ||
4 | import Control.Concurrent | ||
5 | import Control.Monad | ||
6 | import Control.Monad.Trans | ||
7 | import Data.Conduit as C | ||
8 | import Data.Conduit.List as C | ||
9 | import Data.Default | ||
10 | import Options.Applicative | ||
11 | import System.Exit | ||
12 | import System.FilePath | ||
13 | |||
14 | import Data.Torrent | ||
15 | import Data.Torrent.InfoHash | ||
16 | import Network.BitTorrent.Core | ||
17 | import Network.BitTorrent.DHT.Session | ||
18 | import Network.BitTorrent.DHT as DHT | ||
19 | import Network.BitTorrent.Exchange.Message | ||
20 | import Network.BitTorrent.Exchange.Wire | ||
21 | |||
22 | |||
23 | data Params = Params | ||
24 | { topic :: InfoHash | ||
25 | , thisNode :: NodeAddr IPv4 | ||
26 | , bootNode :: NodeAddr IPv4 | ||
27 | , buckets :: Int | ||
28 | } deriving Show | ||
29 | |||
30 | paramsParser :: Parser Params | ||
31 | paramsParser = Params | ||
32 | <$> option (long "infohash" <> short 'i' | ||
33 | <> metavar "SHA1" <> help "infohash of torrent file") | ||
34 | <*> option (long "port" <> short 'p' | ||
35 | <> value def <> showDefault | ||
36 | <> metavar "NUM" <> help "port number to bind" | ||
37 | ) | ||
38 | <*> option (long "boot" <> short 'b' | ||
39 | <> metavar "NODE" <> help "bootstrap node address" | ||
40 | ) | ||
41 | <*> option (long "bucket" <> short 'n' | ||
42 | <> value 2 <> showDefault | ||
43 | <> metavar "NUM" <> help "number of buckets to maintain" | ||
44 | ) | ||
45 | |||
46 | programInfo :: ParserInfo Params | ||
47 | programInfo = info (helper <*> paramsParser) | ||
48 | ( fullDesc | ||
49 | <> progDesc "" | ||
50 | <> header "gettorrent - get torrent file by infohash" | ||
51 | ) | ||
52 | |||
53 | exchangeTorrent :: PeerAddr IP -> InfoHash -> IO InfoDict | ||
54 | exchangeTorrent addr ih = do | ||
55 | pid <- genPeerId | ||
56 | var <- newEmptyMVar | ||
57 | let hs = Handshake def (toCaps [ExtExtended]) ih pid | ||
58 | connectWire hs addr (toCaps [ExtMetadata]) $ do | ||
59 | infodict <- getMetadata | ||
60 | liftIO $ putMVar var infodict | ||
61 | takeMVar var | ||
62 | |||
63 | getTorrent :: Params -> IO () | ||
64 | getTorrent Params {..} = do | ||
65 | dht (def { optBucketCount = buckets }) thisNode $ do | ||
66 | bootstrap [bootNode] | ||
67 | DHT.lookup topic $$ C.mapM_ $ \ peers -> do | ||
68 | liftIO $ forM_ peers $ \ peer -> do | ||
69 | infodict <- exchangeTorrent (IPv4 <$> peer) topic | ||
70 | let torrent = nullTorrent infodict -- TODO add tNodes, tCreated, etc? | ||
71 | toFile (show topic <.> torrentExt) torrent | ||
72 | exitSuccess | ||
73 | |||
74 | main :: IO () | ||
75 | main = execParser programInfo >>= getTorrent | ||
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 | ||