summaryrefslogtreecommitdiff
path: root/src/Data/Torrent.hs
diff options
context:
space:
mode:
authorSam T <pxqr.sta@gmail.com>2013-06-06 11:39:42 +0400
committerSam T <pxqr.sta@gmail.com>2013-06-06 11:39:42 +0400
commit563d040a9ab920b715cf86caf0fb2646e2655792 (patch)
tree1809e09edeb7e5433d2e71dc62f6e7e09ef85f4a /src/Data/Torrent.hs
parent4de96724e4006589022e08b6ed247784f958b508 (diff)
~ Add docs to Torrent module.
Diffstat (limited to 'src/Data/Torrent.hs')
-rw-r--r--src/Data/Torrent.hs54
1 files changed, 45 insertions, 9 deletions
diff --git a/src/Data/Torrent.hs b/src/Data/Torrent.hs
index 464bc5bb..16b94828 100644
--- a/src/Data/Torrent.hs
+++ b/src/Data/Torrent.hs
@@ -5,7 +5,16 @@
5-- Stability : experimental 5-- Stability : experimental
6-- Portability : portable 6-- Portability : portable
7-- 7--
8-- This module provides torrent metainfo serialization. 8-- Torrent file contains metadata about files and folders but not
9-- content itself. The files are bencoded dictionaries. There is
10-- also other info which is used to help join the swarm.
11--
12-- This module provides torrent metainfo serialization and info hash
13-- extraction.
14--
15-- For more info see:
16-- <http://www.bittorrent.org/beps/bep_0003.html#metainfo-files>,
17-- <https://wiki.theory.org/BitTorrentSpecification#Metainfo_File_Structure>
9-- 18--
10{-# OPTIONS -fno-warn-orphans #-} 19{-# OPTIONS -fno-warn-orphans #-}
11{-# LANGUAGE FlexibleInstances #-} 20{-# LANGUAGE FlexibleInstances #-}
@@ -15,11 +24,11 @@
15module Data.Torrent 24module Data.Torrent
16 ( -- * Torrent 25 ( -- * Torrent
17 Torrent(..), ContentInfo(..), FileInfo(..) 26 Torrent(..), ContentInfo(..), FileInfo(..)
18 , contentLength, pieceCount, blockCount
19 , fromFile 27 , fromFile
20 28
21 -- * Files layout 29 -- * Files layout
22 , Layout, contentLayout 30 , Layout, contentLayout
31 , contentLength, pieceCount, blockCount
23 , isSingleFile, isMultiFile 32 , isSingleFile, isMultiFile
24 33
25 -- * Info hash 34 -- * Info hash
@@ -156,8 +165,14 @@ data FileInfo = FileInfo {
156 -- ^ One or more string elements that together represent the path and 165 -- ^ One or more string elements that together represent the path and
157 -- filename. Each element in the list corresponds to either a directory 166 -- filename. Each element in the list corresponds to either a directory
158 -- name or (in the case of the last element) the filename. 167 -- name or (in the case of the last element) the filename.
159 -- For example, the file "dir1/dir2/file.ext" would consist of three 168 -- For example, the file
160 -- string elements ["dir1", "dir2", "file.ext"] 169 --
170 -- > "dir1/dir2/file.ext"
171 --
172 -- would consist of three string elements:
173 --
174 -- > ["dir1", "dir2", "file.ext"]
175 --
161 } deriving (Show, Read, Eq) 176 } deriving (Show, Read, Eq)
162 177
163 178
@@ -250,6 +265,8 @@ instance BEncodable FileInfo where
250 265
251 fromBEncode _ = decodingError "FileInfo" 266 fromBEncode _ = decodingError "FileInfo"
252 267
268
269-- | Divide and round up.
253sizeInBase :: Integral a => a -> Int -> Int 270sizeInBase :: Integral a => a -> Int -> Int
254sizeInBase n b = fromIntegral (n `div` fromIntegral b) + align 271sizeInBase n b = fromIntegral (n `div` fromIntegral b) + align
255 where 272 where
@@ -257,14 +274,22 @@ sizeInBase n b = fromIntegral (n `div` fromIntegral b) + align
257{-# SPECIALIZE sizeInBase :: Int -> Int -> Int #-} 274{-# SPECIALIZE sizeInBase :: Int -> Int -> Int #-}
258{-# SPECIALIZE sizeInBase :: Integer -> Int -> Int #-} 275{-# SPECIALIZE sizeInBase :: Integer -> Int -> Int #-}
259 276
277
278-- | Find sum of sizes of the all torrent files.
260contentLength :: ContentInfo -> Integer 279contentLength :: ContentInfo -> Integer
261contentLength SingleFile { ciLength = len } = len 280contentLength SingleFile { ciLength = len } = len
262contentLength MultiFile { ciFiles = tfs } = sum (map fiLength tfs) 281contentLength MultiFile { ciFiles = tfs } = sum (map fiLength tfs)
263 282
283-- | Find count of pieces in the torrent. If torrent size is not a
284-- multiple of piece size then the count is rounded up.
264pieceCount :: ContentInfo -> Int 285pieceCount :: ContentInfo -> Int
265pieceCount ci = contentLength ci `sizeInBase` ciPieceLength ci 286pieceCount ci = contentLength ci `sizeInBase` ciPieceLength ci
266 287
267blockCount :: Int -> ContentInfo -> Int 288-- | Find number of blocks of the specified size. If torrent size is
289-- not a multiple of block size then the count is rounded up.
290blockCount :: Int -- ^ Block size.
291 -> ContentInfo -- ^ Torrent content info.
292 -> Int -- ^ Number of blocks.
268blockCount blkSize ci = contentLength ci `sizeInBase` blkSize 293blockCount blkSize ci = contentLength ci `sizeInBase` blkSize
269 294
270-- | File layout specifies the order and the size of each file in the storage. 295-- | File layout specifies the order and the size of each file in the storage.
@@ -273,7 +298,10 @@ blockCount blkSize ci = contentLength ci `sizeInBase` blkSize
273-- 298--
274type Layout = [(FilePath, Int)] 299type Layout = [(FilePath, Int)]
275 300
276contentLayout :: FilePath -> ContentInfo -> Layout 301-- | Extract files layout from torrent info with the given root path.
302contentLayout :: FilePath -- ^ Root path for the all torrent files.
303 -> ContentInfo -- ^ Torrent content information.
304 -> Layout -- ^ The all file paths prefixed with the given root.
277contentLayout rootPath = filesLayout 305contentLayout rootPath = filesLayout
278 where 306 where
279 filesLayout (SingleFile { ciName = name, ciLength = len }) 307 filesLayout (SingleFile { ciName = name, ciLength = len })
@@ -285,11 +313,12 @@ contentLayout rootPath = filesLayout
285 313
286 fl (FileInfo { fiPath = p, fiLength = len }) = (p, fromIntegral len) 314 fl (FileInfo { fiPath = p, fiLength = len }) = (p, fromIntegral len)
287 315
288 316-- | Test if this is single file torrent.
289isSingleFile :: ContentInfo -> Bool 317isSingleFile :: ContentInfo -> Bool
290isSingleFile SingleFile {} = True 318isSingleFile SingleFile {} = True
291isSingleFile _ = False 319isSingleFile _ = False
292 320
321-- | Test if this is multifile torrent.
293isMultiFile :: ContentInfo -> Bool 322isMultiFile :: ContentInfo -> Bool
294isMultiFile MultiFile {} = True 323isMultiFile MultiFile {} = True
295isMultiFile _ = False 324isMultiFile _ = False
@@ -299,10 +328,10 @@ fromFile :: FilePath -> IO (Result Torrent)
299fromFile filepath = decoded <$> B.readFile filepath 328fromFile filepath = decoded <$> B.readFile filepath
300 329
301{----------------------------------------------------------------------- 330{-----------------------------------------------------------------------
302 Serialization 331 Info hash
303-----------------------------------------------------------------------} 332-----------------------------------------------------------------------}
304 333
305-- | Exactly 20 bytes long SHA1 hash. 334-- | Exactly 20 bytes long SHA1 hash of the info part of torrent file.
306newtype InfoHash = InfoHash { getInfoHash :: ByteString } 335newtype InfoHash = InfoHash { getInfoHash :: ByteString }
307 deriving (Eq, Ord) 336 deriving (Eq, Ord)
308 337
@@ -325,18 +354,25 @@ instance BEncodable a => BEncodable (Map InfoHash a) where
325 toBEncode = toBEncode . M.mapKeys getInfoHash 354 toBEncode = toBEncode . M.mapKeys getInfoHash
326 {-# INLINE toBEncode #-} 355 {-# INLINE toBEncode #-}
327 356
357-- | Hash strict bytestring using SHA1 algorithm.
328hash :: ByteString -> InfoHash 358hash :: ByteString -> InfoHash
329hash = InfoHash . C.hash 359hash = InfoHash . C.hash
330 360
361-- | Hash lazy bytestring using SHA1 algorithm.
331hashlazy :: Lazy.ByteString -> InfoHash 362hashlazy :: Lazy.ByteString -> InfoHash
332hashlazy = InfoHash . C.hashlazy 363hashlazy = InfoHash . C.hashlazy
333 364
365-- | Pretty print info hash in hexadecimal format.
334ppInfoHash :: InfoHash -> Doc 366ppInfoHash :: InfoHash -> Doc
335ppInfoHash = text . BC.unpack . Lazy.toStrict . ppHex . getInfoHash 367ppInfoHash = text . BC.unpack . Lazy.toStrict . ppHex . getInfoHash
336 368
337ppHex :: ByteString -> Lazy.ByteString 369ppHex :: ByteString -> Lazy.ByteString
338ppHex = B.toLazyByteString . foldMap (B.primFixed B.word8HexFixed) . B.unpack 370ppHex = B.toLazyByteString . foldMap (B.primFixed B.word8HexFixed) . B.unpack
339 371
372-- | Add query info hash parameter to uri.
373--
374-- > info_hash=<url_encoded_info_hash>
375--
340addHashToURI :: URI -> InfoHash -> URI 376addHashToURI :: URI -> InfoHash -> URI
341addHashToURI uri s = uri { 377addHashToURI uri s = uri {
342 uriQuery = uriQuery uri ++ mkPref (uriQuery uri) ++ 378 uriQuery = uriQuery uri ++ mkPref (uriQuery uri) ++