+++ /dev/null
-{-
- - Copyright (C) 2015-2016 Ramakrishnan Muthukrishnan <ram@rkrishnan.org>
- -
- - This file is part of FuncTorrent.
- -
- - FuncTorrent is free software; you can redistribute it and/or modify
- - it under the terms of the GNU General Public License as published by
- - the Free Software Foundation; either version 3 of the License, or
- - (at your option) any later version.
- -
- - FuncTorrent is distributed in the hope that it will be useful,
- - but WITHOUT ANY WARRANTY; without even the implied warranty of
- - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- - GNU General Public License for more details.
- -
- - You should have received a copy of the GNU General Public License
- - along with FuncTorrent; if not, see <http://www.gnu.org/licenses/>
- -}
-
-module FuncTorrent.PieceManager
- (PieceDlState(..),
- PieceData(..),
- PieceMap,
- pieceNumToOffset,
- updatePieceAvailability,
- pickPiece,
- bytesDownloaded,
- initPieceMap,
- ) where
-
-import Prelude hiding (filter)
-
-import qualified Data.ByteString.Char8 as BC (length)
-import Control.Monad (liftM)
-import Data.ByteString (ByteString)
-import Data.Map (Map, (!), fromList, toList, mapWithKey, filter)
-import Safe (headMay)
-
-import FuncTorrent.PeerMsgs (Peer)
-import FuncTorrent.Utils (splitN, splitNum)
-
-data PieceDlState = Pending
- | Downloading
- | Have
- deriving (Show, Eq)
-
--- todo - map with index to a new data structure (peers who have that piece and state)
-data PieceData = PieceData { peers :: [Peer] -- ^ list of peers who have this piece
- , dlstate :: PieceDlState -- ^ state of the piece from download perspective.
- , hash :: ByteString -- ^ piece hash
- , len :: Integer } -- ^ piece length
-
--- which piece is with which peers
-type PieceMap = Map Integer PieceData
-
-pieceNumToOffset :: PieceMap -> Integer -> Integer
-pieceNumToOffset _ 0 = 0
-pieceNumToOffset pieceMap k = k * len (pieceMap ! (k - 1))
-
--- simple algorithm to pick piece.
--- pick the first piece from 0 that is not downloaded yet.
-pickPiece :: PieceMap -> Maybe Integer
-pickPiece =
- (fst `liftM`) . headMay . toList . filter (\v -> dlstate v == Pending)
-
-bytesDownloaded :: PieceMap -> Integer
-bytesDownloaded =
- sum . map (len . snd) . toList . filter (\v -> dlstate v == Have)
-
-updatePieceAvailability :: PieceMap -> Peer -> [Integer] -> PieceMap
-updatePieceAvailability pieceStatus p pieceList =
- mapWithKey (\k pd -> if k `elem` pieceList
- then (pd { peers = p : peers pd })
- else pd) pieceStatus
-
--- Make the initial Piece map, with the assumption that no peer has the
--- piece and that every piece is pending download.
-initPieceMap :: ByteString -> Integer -> Integer -> PieceMap
-initPieceMap pieceHash fileLen pieceLen = fromList kvs
- where
- numPieces = (toInteger . (`quot` 20) . BC.length) pieceHash
- kvs = [(i, PieceData { peers = []
- , dlstate = Pending
- , hash = h
- , len = pLen })
- | (i, h, pLen) <- zip3 [0..numPieces] hashes pLengths]
- hashes = splitN 20 pieceHash
- pLengths = splitNum fileLen pieceLen