summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO.org1
-rw-r--r--bittorrent.cabal1
-rw-r--r--src/Data/Torrent/Piece.hs26
3 files changed, 22 insertions, 6 deletions
diff --git a/TODO.org b/TODO.org
index 359bbecf..24b33d0c 100644
--- a/TODO.org
+++ b/TODO.org
@@ -1,3 +1,4 @@
1* TODO torrent linting for indexing
1* TODO move PeerClient to Data.Torrent.Client 2* TODO move PeerClient to Data.Torrent.Client
2* TODO Word64 for Progress fields 3* TODO Word64 for Progress fields
3* TODO rename TConnection -> Connection, etc 4* TODO rename TConnection -> Connection, etc
diff --git a/bittorrent.cabal b/bittorrent.cabal
index a7d9114d..49f444e2 100644
--- a/bittorrent.cabal
+++ b/bittorrent.cabal
@@ -105,6 +105,7 @@ library
105 , aeson 105 , aeson
106 , base16-bytestring 106 , base16-bytestring
107 , base32-bytestring 107 , base32-bytestring
108 , base64-bytestring
108 , bencoding >= 0.4 109 , bencoding >= 0.4
109 , binary 110 , binary
110 , cereal >= 0.3 111 , cereal >= 0.3
diff --git a/src/Data/Torrent/Piece.hs b/src/Data/Torrent/Piece.hs
index ea4e6253..bff6f948 100644
--- a/src/Data/Torrent/Piece.hs
+++ b/src/Data/Torrent/Piece.hs
@@ -41,17 +41,19 @@ module Data.Torrent.Piece
41import Control.DeepSeq 41import Control.DeepSeq
42import Control.Lens 42import Control.Lens
43import qualified Crypto.Hash.SHA1 as SHA1 43import qualified Crypto.Hash.SHA1 as SHA1
44import Data.Aeson (ToJSON, FromJSON) 44import Data.Aeson (ToJSON(..), FromJSON(..), Value(..), withText)
45import Data.Aeson.TH 45import Data.Aeson.TH
46import Data.BEncode 46import Data.BEncode
47import Data.BEncode.Types 47import Data.BEncode.Types
48import Data.Bits 48import Data.Bits
49import Data.Bits.Extras 49import Data.Bits.Extras
50import Data.ByteString as BS 50import Data.ByteString as BS
51import qualified Data.ByteString.Lazy as BL 51import qualified Data.ByteString.Lazy as BL
52import qualified Data.ByteString.Base64 as Base64
52import Data.Char 53import Data.Char
53import Data.Int 54import Data.Int
54import Data.List as L 55import Data.List as L
56import Data.Text.Encoding as T
55import Data.Typeable 57import Data.Typeable
56import Text.PrettyPrint 58import Text.PrettyPrint
57 59
@@ -127,11 +129,23 @@ ppPiece :: Piece a -> Doc
127ppPiece Piece {..} 129ppPiece Piece {..}
128 = "Piece" <+> braces ("index" <+> "=" <+> int pieceIndex) 130 = "Piece" <+> braces ("index" <+> "=" <+> int pieceIndex)
129 131
132newtype HashArray = HashArray { unHashArray :: ByteString }
133 deriving (Show, Read, Eq, BEncode)
134
135-- | Represented as base64 encoded JSON string.
136instance ToJSON HashArray where
137 toJSON (HashArray bs) = String $ T.decodeUtf8 $ Base64.encode bs
138
139instance FromJSON HashArray where
140 parseJSON = withText "HashArray" $
141 either fail (return . HashArray) . Base64.decode . T.encodeUtf8
142
143-- | Part of torrent file used for torrent content validation.
130data PieceInfo = PieceInfo 144data PieceInfo = PieceInfo
131 { piPieceLength :: {-# UNPACK #-} !PieceSize 145 { piPieceLength :: {-# UNPACK #-} !PieceSize
132 -- ^ Number of bytes in each piece. 146 -- ^ Number of bytes in each piece.
133 147
134 , piPieceHashes :: !ByteString 148 , piPieceHashes :: !HashArray
135 -- ^ Concatenation of all 20-byte SHA1 hash values. 149 -- ^ Concatenation of all 20-byte SHA1 hash values.
136 } deriving (Show, Read, Eq, Typeable) 150 } deriving (Show, Read, Eq, Typeable)
137 151
@@ -147,7 +161,7 @@ instance NFData PieceInfo
147 161
148instance Lint PieceInfo where 162instance Lint PieceInfo where
149 lint pinfo @ PieceInfo {..} 163 lint pinfo @ PieceInfo {..}
150 | BS.length piPieceHashes `rem` hashsize == 0 164 | BS.length (unHashArray piPieceHashes) `rem` hashsize == 0
151 , piPieceLength >= 0 = return pinfo 165 , piPieceLength >= 0 = return pinfo
152 | otherwise = Left undefined 166 | otherwise = Left undefined
153 167
@@ -182,12 +196,12 @@ slice start len = BS.take len . BS.drop start
182 196
183-- | Extract validation hash by specified piece index. 197-- | Extract validation hash by specified piece index.
184pieceHash :: PieceInfo -> PieceIx -> ByteString 198pieceHash :: PieceInfo -> PieceIx -> ByteString
185pieceHash PieceInfo {..} i = slice (hashsize * i) hashsize piPieceHashes 199pieceHash PieceInfo {..} i = slice (hashsize * i) hashsize (unHashArray piPieceHashes)
186 200
187-- | Find count of pieces in the torrent. If torrent size is not a 201-- | Find count of pieces in the torrent. If torrent size is not a
188-- multiple of piece size then the count is rounded up. 202-- multiple of piece size then the count is rounded up.
189pieceCount :: PieceInfo -> PieceCount 203pieceCount :: PieceInfo -> PieceCount
190pieceCount PieceInfo {..} = BS.length piPieceHashes `quot` hashsize 204pieceCount PieceInfo {..} = BS.length (unHashArray piPieceHashes) `quot` hashsize
191 205
192isLastPiece :: PieceInfo -> PieceIx -> Bool 206isLastPiece :: PieceInfo -> PieceIx -> Bool
193isLastPiece ci i = pieceCount ci == succ i 207isLastPiece ci i = pieceCount ci == succ i