diff options
author | Sam Truzjan <pxqr.sta@gmail.com> | 2014-04-04 21:44:18 +0400 |
---|---|---|
committer | Sam Truzjan <pxqr.sta@gmail.com> | 2014-04-04 21:44:18 +0400 |
commit | 052bed30a3d83aa8fb7b8b42509ad96f573439af (patch) | |
tree | 106b44c06226595870c3bf54f890824eec2b7f0e | |
parent | 88ef120511caae5ed74a48a87617b43aec4b7f76 (diff) |
Move HashList to Torrent module
-rw-r--r-- | bittorrent.cabal | 1 | ||||
-rw-r--r-- | src/Data/Torrent.hs | 199 | ||||
-rw-r--r-- | src/Data/Torrent/Bitfield.hs | 2 | ||||
-rw-r--r-- | src/Data/Torrent/Piece.hs | 232 | ||||
-rw-r--r-- | src/Network/BitTorrent/DHT/Session.hs | 2 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange/Assembler.hs | 2 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange/Block.hs | 2 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange/Message.hs | 10 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange/Session.hs | 3 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange/Session/Metadata.hs | 1 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange/Session/Status.hs | 2 | ||||
-rw-r--r-- | src/System/Torrent/Storage.hs | 2 | ||||
-rw-r--r-- | tests/Data/Torrent/MetainfoSpec.hs | 1 | ||||
-rw-r--r-- | tests/Data/Torrent/PieceSpec.hs | 2 | ||||
-rw-r--r-- | tests/Network/BitTorrent/Exchange/Session/MetadataSpec.hs | 5 | ||||
-rw-r--r-- | tests/System/Torrent/StorageSpec.hs | 3 |
16 files changed, 213 insertions, 256 deletions
diff --git a/bittorrent.cabal b/bittorrent.cabal index 9d687d7d..9a86702d 100644 --- a/bittorrent.cabal +++ b/bittorrent.cabal | |||
@@ -46,7 +46,6 @@ library | |||
46 | hs-source-dirs: src | 46 | hs-source-dirs: src |
47 | exposed-modules: Data.Torrent | 47 | exposed-modules: Data.Torrent |
48 | Data.Torrent.Bitfield | 48 | Data.Torrent.Bitfield |
49 | Data.Torrent.Piece | ||
50 | Data.Torrent.Progress | 49 | Data.Torrent.Progress |
51 | Data.Torrent.Tree | 50 | Data.Torrent.Tree |
52 | Network.BitTorrent | 51 | Network.BitTorrent |
diff --git a/src/Data/Torrent.hs b/src/Data/Torrent.hs index 701da9dd..98d6f94e 100644 --- a/src/Data/Torrent.hs +++ b/src/Data/Torrent.hs | |||
@@ -86,6 +86,34 @@ module Data.Torrent | |||
86 | -- ** Internal | 86 | -- ** Internal |
87 | , sizeInBase | 87 | , sizeInBase |
88 | 88 | ||
89 | -- * Pieces | ||
90 | -- ** Attributes | ||
91 | , PieceIx | ||
92 | , PieceCount | ||
93 | , PieceSize | ||
94 | , minPieceSize | ||
95 | , maxPieceSize | ||
96 | , defaultPieceSize | ||
97 | , PieceHash | ||
98 | |||
99 | -- ** Piece data | ||
100 | , Piece (..) | ||
101 | , pieceSize | ||
102 | , hashPiece | ||
103 | |||
104 | -- ** Piece control | ||
105 | , HashList (..) | ||
106 | , PieceInfo (..) | ||
107 | , pieceCount | ||
108 | |||
109 | -- ** Lens | ||
110 | , pieceLength | ||
111 | , pieceHashes | ||
112 | |||
113 | -- ** Validation | ||
114 | , pieceHash | ||
115 | , checkPieceLazy | ||
116 | |||
89 | -- * Info dictionary | 117 | -- * Info dictionary |
90 | , InfoDict (..) | 118 | , InfoDict (..) |
91 | , infoDictionary | 119 | , infoDictionary |
@@ -133,8 +161,11 @@ import Control.Exception | |||
133 | import Control.Lens hiding (unsnoc) | 161 | import Control.Lens hiding (unsnoc) |
134 | import Control.Monad | 162 | import Control.Monad |
135 | import qualified Crypto.Hash.SHA1 as C | 163 | import qualified Crypto.Hash.SHA1 as C |
164 | import qualified Crypto.Hash.SHA1 as SHA1 | ||
136 | import Data.BEncode as BE | 165 | import Data.BEncode as BE |
137 | import Data.BEncode.Types as BE | 166 | import Data.BEncode.Types as BE |
167 | import Data.Bits | ||
168 | import Data.Bits.Extras | ||
138 | import Data.ByteString as BS | 169 | import Data.ByteString as BS |
139 | import Data.ByteString.Base16 as Base16 | 170 | import Data.ByteString.Base16 as Base16 |
140 | import Data.ByteString.Base32 as Base32 | 171 | import Data.ByteString.Base32 as Base32 |
@@ -146,6 +177,7 @@ import Data.Convertible | |||
146 | import Data.Default | 177 | import Data.Default |
147 | import Data.Foldable as F | 178 | import Data.Foldable as F |
148 | import Data.Hashable as Hashable | 179 | import Data.Hashable as Hashable |
180 | import Data.Int | ||
149 | import qualified Data.List as L | 181 | import qualified Data.List as L |
150 | import Data.Map as M | 182 | import Data.Map as M |
151 | import Data.Maybe | 183 | import Data.Maybe |
@@ -166,7 +198,6 @@ import Text.PrettyPrint.Class | |||
166 | import System.FilePath | 198 | import System.FilePath |
167 | import System.Posix.Types | 199 | import System.Posix.Types |
168 | 200 | ||
169 | import Data.Torrent.Piece | ||
170 | import Network.BitTorrent.Core.NodeInfo | 201 | import Network.BitTorrent.Core.NodeInfo |
171 | 202 | ||
172 | 203 | ||
@@ -527,6 +558,171 @@ sizeInBase n b = fromIntegral (n `div` fromIntegral b) + align | |||
527 | {-# SPECIALIZE sizeInBase :: Integer -> Int -> Int #-} | 558 | {-# SPECIALIZE sizeInBase :: Integer -> Int -> Int #-} |
528 | 559 | ||
529 | {----------------------------------------------------------------------- | 560 | {----------------------------------------------------------------------- |
561 | -- Piece attributes | ||
562 | -----------------------------------------------------------------------} | ||
563 | |||
564 | -- | Zero-based index of piece in torrent content. | ||
565 | type PieceIx = Int | ||
566 | |||
567 | -- | Size of piece in bytes. Should be a power of 2. | ||
568 | -- | ||
569 | -- NOTE: Have max and min size constrained to wide used | ||
570 | -- semi-standard values. This bounds should be used to make decision | ||
571 | -- about piece size for new torrents. | ||
572 | -- | ||
573 | type PieceSize = Int | ||
574 | |||
575 | -- | Number of pieces in torrent or a part of torrent. | ||
576 | type PieceCount = Int | ||
577 | |||
578 | defaultBlockSize :: Int | ||
579 | defaultBlockSize = 16 * 1024 | ||
580 | |||
581 | -- | Optimal number of pieces in torrent. | ||
582 | optimalPieceCount :: PieceCount | ||
583 | optimalPieceCount = 1000 | ||
584 | {-# INLINE optimalPieceCount #-} | ||
585 | |||
586 | -- | Piece size should not be less than this value. | ||
587 | minPieceSize :: Int | ||
588 | minPieceSize = defaultBlockSize * 4 | ||
589 | {-# INLINE minPieceSize #-} | ||
590 | |||
591 | -- | To prevent transfer degradation piece size should not exceed this | ||
592 | -- value. | ||
593 | maxPieceSize :: Int | ||
594 | maxPieceSize = 4 * 1024 * 1024 | ||
595 | {-# INLINE maxPieceSize #-} | ||
596 | |||
597 | toPow2 :: Int -> Int | ||
598 | toPow2 x = bit $ fromIntegral (leadingZeros (0 :: Int) - leadingZeros x) | ||
599 | |||
600 | -- | Find the optimal piece size for a given torrent size. | ||
601 | defaultPieceSize :: Int64 -> Int | ||
602 | defaultPieceSize x = max minPieceSize $ min maxPieceSize $ toPow2 pc | ||
603 | where | ||
604 | pc = fromIntegral (x `div` fromIntegral optimalPieceCount) | ||
605 | |||
606 | {----------------------------------------------------------------------- | ||
607 | -- Piece data | ||
608 | -----------------------------------------------------------------------} | ||
609 | |||
610 | type PieceHash = ByteString | ||
611 | |||
612 | hashsize :: Int | ||
613 | hashsize = 20 | ||
614 | {-# INLINE hashsize #-} | ||
615 | |||
616 | -- TODO check if pieceLength is power of 2 | ||
617 | -- | Piece payload should be strict or lazy bytestring. | ||
618 | data Piece a = Piece | ||
619 | { -- | Zero-based piece index in torrent. | ||
620 | pieceIndex :: {-# UNPACK #-} !PieceIx | ||
621 | |||
622 | -- | Payload. | ||
623 | , pieceData :: !a | ||
624 | } deriving (Show, Read, Eq, Functor, Typeable) | ||
625 | |||
626 | instance NFData (Piece a) | ||
627 | |||
628 | -- | Payload bytes are omitted. | ||
629 | instance Pretty (Piece a) where | ||
630 | pretty Piece {..} = "Piece" <+> braces ("index" <+> "=" <+> int pieceIndex) | ||
631 | |||
632 | -- | Get size of piece in bytes. | ||
633 | pieceSize :: Piece BL.ByteString -> PieceSize | ||
634 | pieceSize Piece {..} = fromIntegral (BL.length pieceData) | ||
635 | |||
636 | -- | Get piece hash. | ||
637 | hashPiece :: Piece BL.ByteString -> PieceHash | ||
638 | hashPiece Piece {..} = SHA1.hashlazy pieceData | ||
639 | |||
640 | {----------------------------------------------------------------------- | ||
641 | -- Piece control | ||
642 | -----------------------------------------------------------------------} | ||
643 | |||
644 | -- | A flat array of SHA1 hash for each piece. | ||
645 | newtype HashList = HashList { unHashList :: ByteString } | ||
646 | deriving (Show, Read, Eq, BEncode, Typeable) | ||
647 | |||
648 | -- | Empty hash list. | ||
649 | instance Default HashList where | ||
650 | def = HashList "" | ||
651 | |||
652 | -- | Part of torrent file used for torrent content validation. | ||
653 | data PieceInfo = PieceInfo | ||
654 | { piPieceLength :: {-# UNPACK #-} !PieceSize | ||
655 | -- ^ Number of bytes in each piece. | ||
656 | |||
657 | , piPieceHashes :: !HashList | ||
658 | -- ^ Concatenation of all 20-byte SHA1 hash values. | ||
659 | } deriving (Show, Read, Eq, Typeable) | ||
660 | |||
661 | -- | Number of bytes in each piece. | ||
662 | makeLensesFor [("piPieceLength", "pieceLength")] ''PieceInfo | ||
663 | |||
664 | -- | Concatenation of all 20-byte SHA1 hash values. | ||
665 | makeLensesFor [("piPieceHashes", "pieceHashes")] ''PieceInfo | ||
666 | |||
667 | instance NFData PieceInfo | ||
668 | |||
669 | instance Default PieceInfo where | ||
670 | def = PieceInfo 1 def | ||
671 | |||
672 | class Lint a where | ||
673 | lint :: a -> Either String a | ||
674 | |||
675 | instance Lint PieceInfo where | ||
676 | lint pinfo @ PieceInfo {..} | ||
677 | | BS.length (unHashList piPieceHashes) `rem` hashsize == 0 | ||
678 | , piPieceLength >= 0 = return pinfo | ||
679 | | otherwise = Left undefined | ||
680 | |||
681 | |||
682 | putPieceInfo :: Data.Torrent.Put PieceInfo | ||
683 | putPieceInfo PieceInfo {..} cont = | ||
684 | "piece length" .=! piPieceLength | ||
685 | .: "pieces" .=! piPieceHashes | ||
686 | .: cont | ||
687 | |||
688 | getPieceInfo :: BE.Get PieceInfo | ||
689 | getPieceInfo = do | ||
690 | PieceInfo <$>! "piece length" | ||
691 | <*>! "pieces" | ||
692 | |||
693 | instance BEncode PieceInfo where | ||
694 | toBEncode = toDict . (`putPieceInfo` endDict) | ||
695 | fromBEncode = fromDict getPieceInfo | ||
696 | |||
697 | -- | Hashes are omitted. | ||
698 | instance Pretty PieceInfo where | ||
699 | pretty PieceInfo {..} = "Piece size: " <> int piPieceLength | ||
700 | |||
701 | slice :: Int -> Int -> ByteString -> ByteString | ||
702 | slice start len = BS.take len . BS.drop start | ||
703 | {-# INLINE slice #-} | ||
704 | |||
705 | -- | Extract validation hash by specified piece index. | ||
706 | pieceHash :: PieceInfo -> PieceIx -> PieceHash | ||
707 | pieceHash PieceInfo {..} i = slice (hashsize * i) hashsize (unHashList piPieceHashes) | ||
708 | |||
709 | -- | Find count of pieces in the torrent. If torrent size is not a | ||
710 | -- multiple of piece size then the count is rounded up. | ||
711 | pieceCount :: PieceInfo -> PieceCount | ||
712 | pieceCount PieceInfo {..} = BS.length (unHashList piPieceHashes) `quot` hashsize | ||
713 | |||
714 | -- | Test if this is last piece in torrent content. | ||
715 | isLastPiece :: PieceInfo -> PieceIx -> Bool | ||
716 | isLastPiece ci i = pieceCount ci == succ i | ||
717 | |||
718 | -- | Validate piece with metainfo hash. | ||
719 | checkPieceLazy :: PieceInfo -> Piece BL.ByteString -> Bool | ||
720 | checkPieceLazy pinfo @ PieceInfo {..} Piece {..} | ||
721 | = (fromIntegral (BL.length pieceData) == piPieceLength | ||
722 | || isLastPiece pinfo pieceIndex) | ||
723 | && SHA1.hashlazy pieceData == pieceHash pinfo pieceIndex | ||
724 | |||
725 | {----------------------------------------------------------------------- | ||
530 | -- Info dictionary | 726 | -- Info dictionary |
531 | -----------------------------------------------------------------------} | 727 | -----------------------------------------------------------------------} |
532 | 728 | ||
@@ -620,6 +816,7 @@ instance Pretty InfoDict where | |||
620 | {----------------------------------------------------------------------- | 816 | {----------------------------------------------------------------------- |
621 | -- Torrent info | 817 | -- Torrent info |
622 | -----------------------------------------------------------------------} | 818 | -----------------------------------------------------------------------} |
819 | -- TODO add torrent file validation | ||
623 | 820 | ||
624 | -- | Metainfo about particular torrent. | 821 | -- | Metainfo about particular torrent. |
625 | data Torrent = Torrent | 822 | data Torrent = Torrent |
diff --git a/src/Data/Torrent/Bitfield.hs b/src/Data/Torrent/Bitfield.hs index b65f058b..ff701d75 100644 --- a/src/Data/Torrent/Bitfield.hs +++ b/src/Data/Torrent/Bitfield.hs | |||
@@ -92,7 +92,7 @@ import Data.List (foldl') | |||
92 | import Data.Monoid | 92 | import Data.Monoid |
93 | import Data.Ratio | 93 | import Data.Ratio |
94 | 94 | ||
95 | import Data.Torrent.Piece | 95 | import Data.Torrent |
96 | 96 | ||
97 | -- TODO cache some operations | 97 | -- TODO cache some operations |
98 | 98 | ||
diff --git a/src/Data/Torrent/Piece.hs b/src/Data/Torrent/Piece.hs deleted file mode 100644 index d4b2c399..00000000 --- a/src/Data/Torrent/Piece.hs +++ /dev/null | |||
@@ -1,232 +0,0 @@ | |||
1 | -- | | ||
2 | -- Copyright : (c) Sam Truzjan 2013 | ||
3 | -- License : BSD3 | ||
4 | -- Maintainer : pxqr.sta@gmail.com | ||
5 | -- Stability : experimental | ||
6 | -- Portability : portable | ||
7 | -- | ||
8 | -- Pieces are used to validate torrent content. | ||
9 | -- | ||
10 | {-# LANGUAGE TemplateHaskell #-} | ||
11 | {-# LANGUAGE DeriveDataTypeable #-} | ||
12 | {-# LANGUAGE DeriveFunctor #-} | ||
13 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} | ||
14 | module Data.Torrent.Piece | ||
15 | ( -- * Piece attributes | ||
16 | PieceIx | ||
17 | , PieceCount | ||
18 | , PieceSize | ||
19 | , minPieceSize | ||
20 | , maxPieceSize | ||
21 | , defaultPieceSize | ||
22 | , PieceHash | ||
23 | |||
24 | -- * Piece data | ||
25 | , Piece (..) | ||
26 | , pieceSize | ||
27 | , hashPiece | ||
28 | |||
29 | -- * Piece control | ||
30 | , HashList (..) | ||
31 | , PieceInfo (..) | ||
32 | , pieceCount | ||
33 | |||
34 | -- * Lens | ||
35 | , pieceLength | ||
36 | , pieceHashes | ||
37 | |||
38 | -- * Validation | ||
39 | , pieceHash | ||
40 | , checkPieceLazy | ||
41 | |||
42 | -- * Internal | ||
43 | , getPieceInfo | ||
44 | , putPieceInfo | ||
45 | ) where | ||
46 | |||
47 | import Control.DeepSeq | ||
48 | import Control.Lens | ||
49 | import qualified Crypto.Hash.SHA1 as SHA1 | ||
50 | import Data.BEncode | ||
51 | import Data.BEncode.Types | ||
52 | import Data.Bits | ||
53 | import Data.Bits.Extras | ||
54 | import Data.ByteString as BS | ||
55 | import qualified Data.ByteString.Lazy as BL | ||
56 | import qualified Data.ByteString.Base64 as Base64 | ||
57 | import Data.Default | ||
58 | import Data.Int | ||
59 | import Data.Text.Encoding as T | ||
60 | import Data.Typeable | ||
61 | import Text.PrettyPrint | ||
62 | import Text.PrettyPrint.Class | ||
63 | |||
64 | |||
65 | -- TODO add torrent file validation | ||
66 | class Lint a where | ||
67 | lint :: a -> Either String a | ||
68 | |||
69 | --class Validation a where | ||
70 | -- validate :: PieceInfo -> Piece a -> Bool | ||
71 | |||
72 | {----------------------------------------------------------------------- | ||
73 | -- Piece attributes | ||
74 | -----------------------------------------------------------------------} | ||
75 | |||
76 | -- | Zero-based index of piece in torrent content. | ||
77 | type PieceIx = Int | ||
78 | |||
79 | -- | Size of piece in bytes. Should be a power of 2. | ||
80 | -- | ||
81 | -- NOTE: Have max and min size constrained to wide used | ||
82 | -- semi-standard values. This bounds should be used to make decision | ||
83 | -- about piece size for new torrents. | ||
84 | -- | ||
85 | type PieceSize = Int | ||
86 | |||
87 | -- | Number of pieces in torrent or a part of torrent. | ||
88 | type PieceCount = Int | ||
89 | |||
90 | defaultBlockSize :: Int | ||
91 | defaultBlockSize = 16 * 1024 | ||
92 | |||
93 | -- | Optimal number of pieces in torrent. | ||
94 | optimalPieceCount :: PieceCount | ||
95 | optimalPieceCount = 1000 | ||
96 | {-# INLINE optimalPieceCount #-} | ||
97 | |||
98 | -- | Piece size should not be less than this value. | ||
99 | minPieceSize :: Int | ||
100 | minPieceSize = defaultBlockSize * 4 | ||
101 | {-# INLINE minPieceSize #-} | ||
102 | |||
103 | -- | To prevent transfer degradation piece size should not exceed this | ||
104 | -- value. | ||
105 | maxPieceSize :: Int | ||
106 | maxPieceSize = 4 * 1024 * 1024 | ||
107 | {-# INLINE maxPieceSize #-} | ||
108 | |||
109 | toPow2 :: Int -> Int | ||
110 | toPow2 x = bit $ fromIntegral (leadingZeros (0 :: Int) - leadingZeros x) | ||
111 | |||
112 | -- | Find the optimal piece size for a given torrent size. | ||
113 | defaultPieceSize :: Int64 -> Int | ||
114 | defaultPieceSize x = max minPieceSize $ min maxPieceSize $ toPow2 pc | ||
115 | where | ||
116 | pc = fromIntegral (x `div` fromIntegral optimalPieceCount) | ||
117 | |||
118 | {----------------------------------------------------------------------- | ||
119 | -- Piece data | ||
120 | -----------------------------------------------------------------------} | ||
121 | |||
122 | type PieceHash = ByteString | ||
123 | |||
124 | hashsize :: Int | ||
125 | hashsize = 20 | ||
126 | {-# INLINE hashsize #-} | ||
127 | |||
128 | -- TODO check if pieceLength is power of 2 | ||
129 | -- | Piece payload should be strict or lazy bytestring. | ||
130 | data Piece a = Piece | ||
131 | { -- | Zero-based piece index in torrent. | ||
132 | pieceIndex :: {-# UNPACK #-} !PieceIx | ||
133 | |||
134 | -- | Payload. | ||
135 | , pieceData :: !a | ||
136 | } deriving (Show, Read, Eq, Functor, Typeable) | ||
137 | |||
138 | instance NFData (Piece a) | ||
139 | |||
140 | -- | Payload bytes are omitted. | ||
141 | instance Pretty (Piece a) where | ||
142 | pretty Piece {..} = "Piece" <+> braces ("index" <+> "=" <+> int pieceIndex) | ||
143 | |||
144 | -- | Get size of piece in bytes. | ||
145 | pieceSize :: Piece BL.ByteString -> PieceSize | ||
146 | pieceSize Piece {..} = fromIntegral (BL.length pieceData) | ||
147 | |||
148 | -- | Get piece hash. | ||
149 | hashPiece :: Piece BL.ByteString -> PieceHash | ||
150 | hashPiece Piece {..} = SHA1.hashlazy pieceData | ||
151 | |||
152 | {----------------------------------------------------------------------- | ||
153 | -- Piece control | ||
154 | -----------------------------------------------------------------------} | ||
155 | |||
156 | -- | A flat array of SHA1 hash for each piece. | ||
157 | newtype HashList = HashList { unHashList :: ByteString } | ||
158 | deriving (Show, Read, Eq, BEncode, Typeable) | ||
159 | |||
160 | -- | Empty hash list. | ||
161 | instance Default HashList where | ||
162 | def = HashList "" | ||
163 | |||
164 | -- | Part of torrent file used for torrent content validation. | ||
165 | data PieceInfo = PieceInfo | ||
166 | { piPieceLength :: {-# UNPACK #-} !PieceSize | ||
167 | -- ^ Number of bytes in each piece. | ||
168 | |||
169 | , piPieceHashes :: !HashList | ||
170 | -- ^ Concatenation of all 20-byte SHA1 hash values. | ||
171 | } deriving (Show, Read, Eq, Typeable) | ||
172 | |||
173 | -- | Number of bytes in each piece. | ||
174 | makeLensesFor [("piPieceLength", "pieceLength")] ''PieceInfo | ||
175 | |||
176 | -- | Concatenation of all 20-byte SHA1 hash values. | ||
177 | makeLensesFor [("piPieceHashes", "pieceHashes")] ''PieceInfo | ||
178 | |||
179 | instance NFData PieceInfo | ||
180 | |||
181 | instance Default PieceInfo where | ||
182 | def = PieceInfo 1 def | ||
183 | |||
184 | instance Lint PieceInfo where | ||
185 | lint pinfo @ PieceInfo {..} | ||
186 | | BS.length (unHashList piPieceHashes) `rem` hashsize == 0 | ||
187 | , piPieceLength >= 0 = return pinfo | ||
188 | | otherwise = Left undefined | ||
189 | |||
190 | |||
191 | putPieceInfo :: PieceInfo -> BDict -> BDict | ||
192 | putPieceInfo PieceInfo {..} cont = | ||
193 | "piece length" .=! piPieceLength | ||
194 | .: "pieces" .=! piPieceHashes | ||
195 | .: cont | ||
196 | |||
197 | getPieceInfo :: Get PieceInfo | ||
198 | getPieceInfo = do | ||
199 | PieceInfo <$>! "piece length" | ||
200 | <*>! "pieces" | ||
201 | |||
202 | instance BEncode PieceInfo where | ||
203 | toBEncode = toDict . (`putPieceInfo` endDict) | ||
204 | fromBEncode = fromDict getPieceInfo | ||
205 | |||
206 | -- | Hashes are omitted. | ||
207 | instance Pretty PieceInfo where | ||
208 | pretty PieceInfo {..} = "Piece size: " <> int piPieceLength | ||
209 | |||
210 | slice :: Int -> Int -> ByteString -> ByteString | ||
211 | slice start len = BS.take len . BS.drop start | ||
212 | {-# INLINE slice #-} | ||
213 | |||
214 | -- | Extract validation hash by specified piece index. | ||
215 | pieceHash :: PieceInfo -> PieceIx -> PieceHash | ||
216 | pieceHash PieceInfo {..} i = slice (hashsize * i) hashsize (unHashList piPieceHashes) | ||
217 | |||
218 | -- | Find count of pieces in the torrent. If torrent size is not a | ||
219 | -- multiple of piece size then the count is rounded up. | ||
220 | pieceCount :: PieceInfo -> PieceCount | ||
221 | pieceCount PieceInfo {..} = BS.length (unHashList piPieceHashes) `quot` hashsize | ||
222 | |||
223 | -- | Test if this is last piece in torrent content. | ||
224 | isLastPiece :: PieceInfo -> PieceIx -> Bool | ||
225 | isLastPiece ci i = pieceCount ci == succ i | ||
226 | |||
227 | -- | Validate piece with metainfo hash. | ||
228 | checkPieceLazy :: PieceInfo -> Piece BL.ByteString -> Bool | ||
229 | checkPieceLazy pinfo @ PieceInfo {..} Piece {..} | ||
230 | = (fromIntegral (BL.length pieceData) == piPieceLength | ||
231 | || isLastPiece pinfo pieceIndex) | ||
232 | && SHA1.hashlazy pieceData == pieceHash pinfo pieceIndex | ||
diff --git a/src/Network/BitTorrent/DHT/Session.hs b/src/Network/BitTorrent/DHT/Session.hs index 87a6d4ea..8fe81abd 100644 --- a/src/Network/BitTorrent/DHT/Session.hs +++ b/src/Network/BitTorrent/DHT/Session.hs | |||
@@ -91,7 +91,7 @@ import System.Random (randomIO) | |||
91 | import Text.PrettyPrint as PP hiding ((<>), ($$)) | 91 | import Text.PrettyPrint as PP hiding ((<>), ($$)) |
92 | import Text.PrettyPrint.Class | 92 | import Text.PrettyPrint.Class |
93 | 93 | ||
94 | import Data.Torrent | 94 | import Data.Torrent as Torrent |
95 | import Network.KRPC hiding (Options, def) | 95 | import Network.KRPC hiding (Options, def) |
96 | import qualified Network.KRPC as KRPC (def) | 96 | import qualified Network.KRPC as KRPC (def) |
97 | import Network.BitTorrent.Core | 97 | import Network.BitTorrent.Core |
diff --git a/src/Network/BitTorrent/Exchange/Assembler.hs b/src/Network/BitTorrent/Exchange/Assembler.hs index e5834948..e17dfbe2 100644 --- a/src/Network/BitTorrent/Exchange/Assembler.hs +++ b/src/Network/BitTorrent/Exchange/Assembler.hs | |||
@@ -67,7 +67,7 @@ import Data.Map as M | |||
67 | import Data.Maybe | 67 | import Data.Maybe |
68 | import Data.IP | 68 | import Data.IP |
69 | 69 | ||
70 | import Data.Torrent.Piece | 70 | import Data.Torrent |
71 | import Network.BitTorrent.Core | 71 | import Network.BitTorrent.Core |
72 | import Network.BitTorrent.Exchange.Block as B | 72 | import Network.BitTorrent.Exchange.Block as B |
73 | 73 | ||
diff --git a/src/Network/BitTorrent/Exchange/Block.hs b/src/Network/BitTorrent/Exchange/Block.hs index 16c124e9..ccc7a0a9 100644 --- a/src/Network/BitTorrent/Exchange/Block.hs +++ b/src/Network/BitTorrent/Exchange/Block.hs | |||
@@ -69,7 +69,7 @@ import Numeric | |||
69 | import Text.PrettyPrint as PP hiding ((<>)) | 69 | import Text.PrettyPrint as PP hiding ((<>)) |
70 | import Text.PrettyPrint.Class | 70 | import Text.PrettyPrint.Class |
71 | 71 | ||
72 | import Data.Torrent.Piece | 72 | import Data.Torrent |
73 | 73 | ||
74 | {----------------------------------------------------------------------- | 74 | {----------------------------------------------------------------------- |
75 | -- Block attributes | 75 | -- Block attributes |
diff --git a/src/Network/BitTorrent/Exchange/Message.hs b/src/Network/BitTorrent/Exchange/Message.hs index bd5c6526..5ca7c97e 100644 --- a/src/Network/BitTorrent/Exchange/Message.hs +++ b/src/Network/BitTorrent/Exchange/Message.hs | |||
@@ -118,8 +118,8 @@ import Text.PrettyPrint as PP hiding ((<>)) | |||
118 | import Text.PrettyPrint.Class | 118 | import Text.PrettyPrint.Class |
119 | 119 | ||
120 | import Data.Torrent.Bitfield | 120 | import Data.Torrent.Bitfield |
121 | import Data.Torrent | 121 | import Data.Torrent hiding (Piece (..)) |
122 | import qualified Data.Torrent.Piece as P | 122 | import qualified Data.Torrent as P (Piece (..)) |
123 | import Network.BitTorrent.Core | 123 | import Network.BitTorrent.Core |
124 | import Network.BitTorrent.Exchange.Block | 124 | import Network.BitTorrent.Exchange.Block |
125 | 125 | ||
@@ -864,7 +864,7 @@ instance PeerMessage ExtendedMetadata where | |||
864 | 864 | ||
865 | -- | All 'Piece's in 'MetadataData' messages MUST have size equal to | 865 | -- | All 'Piece's in 'MetadataData' messages MUST have size equal to |
866 | -- this value. The last trailing piece can be shorter. | 866 | -- this value. The last trailing piece can be shorter. |
867 | metadataPieceSize :: P.PieceSize | 867 | metadataPieceSize :: PieceSize |
868 | metadataPieceSize = 16 * 1024 | 868 | metadataPieceSize = 16 * 1024 |
869 | 869 | ||
870 | isLastPiece :: P.Piece a -> Int -> Bool | 870 | isLastPiece :: P.Piece a -> Int -> Bool |
@@ -877,8 +877,8 @@ isLastPiece P.Piece {..} total = succ pieceIndex == pcnt | |||
877 | -- length; otherwise serialization MUST fail. | 877 | -- length; otherwise serialization MUST fail. |
878 | isValidPiece :: P.Piece BL.ByteString -> Int -> Bool | 878 | isValidPiece :: P.Piece BL.ByteString -> Int -> Bool |
879 | isValidPiece p @ P.Piece {..} total | 879 | isValidPiece p @ P.Piece {..} total |
880 | | isLastPiece p total = P.pieceSize p <= metadataPieceSize | 880 | | isLastPiece p total = pieceSize p <= metadataPieceSize |
881 | | otherwise = P.pieceSize p == metadataPieceSize | 881 | | otherwise = pieceSize p == metadataPieceSize |
882 | 882 | ||
883 | setMetadataPayload :: BS.ByteString -> ExtendedMetadata -> ExtendedMetadata | 883 | setMetadataPayload :: BS.ByteString -> ExtendedMetadata -> ExtendedMetadata |
884 | setMetadataPayload bs (MetadataData (P.Piece pix _) t) = | 884 | setMetadataPayload bs (MetadataData (P.Piece pix _) t) = |
diff --git a/src/Network/BitTorrent/Exchange/Session.hs b/src/Network/BitTorrent/Exchange/Session.hs index 0adb08c8..cae3a2d5 100644 --- a/src/Network/BitTorrent/Exchange/Session.hs +++ b/src/Network/BitTorrent/Exchange/Session.hs | |||
@@ -45,8 +45,7 @@ import Text.PrettyPrint.Class | |||
45 | import System.Log.FastLogger (LogStr, ToLogStr (..)) | 45 | import System.Log.FastLogger (LogStr, ToLogStr (..)) |
46 | 46 | ||
47 | import Data.BEncode as BE | 47 | import Data.BEncode as BE |
48 | import Data.Torrent as T | 48 | import Data.Torrent as Torrent |
49 | import Data.Torrent.Piece as Torrent | ||
50 | import Data.Torrent.Bitfield as BF | 49 | import Data.Torrent.Bitfield as BF |
51 | import Network.BitTorrent.Internal.Types | 50 | import Network.BitTorrent.Internal.Types |
52 | import Network.BitTorrent.Core | 51 | import Network.BitTorrent.Core |
diff --git a/src/Network/BitTorrent/Exchange/Session/Metadata.hs b/src/Network/BitTorrent/Exchange/Session/Metadata.hs index bdd5b322..a4e54659 100644 --- a/src/Network/BitTorrent/Exchange/Session/Metadata.hs +++ b/src/Network/BitTorrent/Exchange/Session/Metadata.hs | |||
@@ -27,7 +27,6 @@ import Data.Tuple | |||
27 | 27 | ||
28 | import Data.BEncode as BE | 28 | import Data.BEncode as BE |
29 | import Data.Torrent as Torrent | 29 | import Data.Torrent as Torrent |
30 | import Data.Torrent.Piece as Torrent | ||
31 | import Network.BitTorrent.Core | 30 | import Network.BitTorrent.Core |
32 | import Network.BitTorrent.Exchange.Block as Block | 31 | import Network.BitTorrent.Exchange.Block as Block |
33 | import Network.BitTorrent.Exchange.Message as Message hiding (Status) | 32 | import Network.BitTorrent.Exchange.Message as Message hiding (Status) |
diff --git a/src/Network/BitTorrent/Exchange/Session/Status.hs b/src/Network/BitTorrent/Exchange/Session/Status.hs index 565c3bf3..4feff8d6 100644 --- a/src/Network/BitTorrent/Exchange/Session/Status.hs +++ b/src/Network/BitTorrent/Exchange/Session/Status.hs | |||
@@ -28,7 +28,7 @@ import Data.Map as M | |||
28 | import Data.Set as S | 28 | import Data.Set as S |
29 | import Data.Tuple | 29 | import Data.Tuple |
30 | 30 | ||
31 | import Data.Torrent.Piece | 31 | import Data.Torrent |
32 | import Data.Torrent.Bitfield as BF | 32 | import Data.Torrent.Bitfield as BF |
33 | import Network.BitTorrent.Core | 33 | import Network.BitTorrent.Core |
34 | import Network.BitTorrent.Exchange.Block as Block | 34 | import Network.BitTorrent.Exchange.Block as Block |
diff --git a/src/System/Torrent/Storage.hs b/src/System/Torrent/Storage.hs index 697e3def..1123cea9 100644 --- a/src/System/Torrent/Storage.hs +++ b/src/System/Torrent/Storage.hs | |||
@@ -57,8 +57,6 @@ import Data.Typeable | |||
57 | 57 | ||
58 | import Data.Torrent | 58 | import Data.Torrent |
59 | import Data.Torrent.Bitfield as BF | 59 | import Data.Torrent.Bitfield as BF |
60 | import Data.Torrent | ||
61 | import Data.Torrent.Piece | ||
62 | import System.Torrent.FileMap as FM | 60 | import System.Torrent.FileMap as FM |
63 | 61 | ||
64 | 62 | ||
diff --git a/tests/Data/Torrent/MetainfoSpec.hs b/tests/Data/Torrent/MetainfoSpec.hs index 537b3f99..1a8f97c7 100644 --- a/tests/Data/Torrent/MetainfoSpec.hs +++ b/tests/Data/Torrent/MetainfoSpec.hs | |||
@@ -14,7 +14,6 @@ import Test.QuickCheck | |||
14 | import Test.QuickCheck.Instances () | 14 | import Test.QuickCheck.Instances () |
15 | 15 | ||
16 | import Data.Torrent | 16 | import Data.Torrent |
17 | import Data.Torrent.Piece | ||
18 | import Data.Torrent.LayoutSpec () | 17 | import Data.Torrent.LayoutSpec () |
19 | import Network.BitTorrent.Core.NodeInfoSpec () | 18 | import Network.BitTorrent.Core.NodeInfoSpec () |
20 | 19 | ||
diff --git a/tests/Data/Torrent/PieceSpec.hs b/tests/Data/Torrent/PieceSpec.hs index ef1f2938..d3933396 100644 --- a/tests/Data/Torrent/PieceSpec.hs +++ b/tests/Data/Torrent/PieceSpec.hs | |||
@@ -3,7 +3,7 @@ module Data.Torrent.PieceSpec (spec) where | |||
3 | import Control.Applicative | 3 | import Control.Applicative |
4 | import Test.Hspec | 4 | import Test.Hspec |
5 | import Test.QuickCheck | 5 | import Test.QuickCheck |
6 | import Data.Torrent.Piece | 6 | import Data.Torrent |
7 | 7 | ||
8 | 8 | ||
9 | instance Arbitrary a => Arbitrary (Piece a) where | 9 | instance Arbitrary a => Arbitrary (Piece a) where |
diff --git a/tests/Network/BitTorrent/Exchange/Session/MetadataSpec.hs b/tests/Network/BitTorrent/Exchange/Session/MetadataSpec.hs index 975ceb5b..5392d74b 100644 --- a/tests/Network/BitTorrent/Exchange/Session/MetadataSpec.hs +++ b/tests/Network/BitTorrent/Exchange/Session/MetadataSpec.hs | |||
@@ -7,8 +7,7 @@ import Test.Hspec | |||
7 | import Test.QuickCheck | 7 | import Test.QuickCheck |
8 | 8 | ||
9 | import Data.BEncode as BE | 9 | import Data.BEncode as BE |
10 | import Data.Torrent | 10 | import Data.Torrent as Torrent |
11 | import Data.Torrent.Piece as P | ||
12 | import Network.BitTorrent.Core | 11 | import Network.BitTorrent.Core |
13 | import Network.BitTorrent.Exchange.Message | 12 | import Network.BitTorrent.Exchange.Message |
14 | import Network.BitTorrent.Exchange.Session.Metadata | 13 | import Network.BitTorrent.Exchange.Session.Metadata |
@@ -36,7 +35,7 @@ simulateFetch :: InfoDict -> Updates (Maybe InfoDict) | |||
36 | simulateFetch dict = go | 35 | simulateFetch dict = go |
37 | where | 36 | where |
38 | blocks = chunkBy metadataPieceSize (BL.toStrict (BE.encode dict)) | 37 | blocks = chunkBy metadataPieceSize (BL.toStrict (BE.encode dict)) |
39 | packPiece ix = P.Piece ix (blocks !! ix) | 38 | packPiece ix = Torrent.Piece ix (blocks !! ix) |
40 | ih = idInfoHash dict | 39 | ih = idInfoHash dict |
41 | 40 | ||
42 | go = do | 41 | go = do |
diff --git a/tests/System/Torrent/StorageSpec.hs b/tests/System/Torrent/StorageSpec.hs index ebf4fe3e..96f1b036 100644 --- a/tests/System/Torrent/StorageSpec.hs +++ b/tests/System/Torrent/StorageSpec.hs | |||
@@ -7,9 +7,8 @@ import System.Directory | |||
7 | import System.IO.Unsafe | 7 | import System.IO.Unsafe |
8 | import Test.Hspec | 8 | import Test.Hspec |
9 | 9 | ||
10 | import Data.Torrent.Bitfield as BF | ||
11 | import Data.Torrent | 10 | import Data.Torrent |
12 | import Data.Torrent.Piece | 11 | import Data.Torrent.Bitfield as BF |
13 | import System.Torrent.Storage | 12 | import System.Torrent.Storage |
14 | 13 | ||
15 | 14 | ||