import Prelude hiding (lookup, concat, replicate, splitAt, take, filter)
import System.IO (Handle, BufferMode(..), hSetBuffering)
+import System.Directory (doesFileExist)
import Data.ByteString (ByteString, unpack, concat, hGet, hPut, take, empty)
import qualified Data.ByteString.Char8 as BC (length)
import Network (connectTo, PortID(..))
import Control.Monad.State
import Data.Bits
import Data.Word (Word8)
-import Data.Map (Map, fromList, toList, (!), mapWithKey, adjust, filter)
+import Data.Map (Map, fromList, toList, (!), mapWithKey, traverseWithKey, adjust, filter)
import qualified Crypto.Hash.SHA1 as SHA1 (hash)
import Safe (headMay)
import FuncTorrent.Metainfo (Info(..), Metainfo(..))
import FuncTorrent.Utils (splitN, splitNum)
-import FuncTorrent.Fileops (createDummyFile, writeFileAtOffset)
+import FuncTorrent.Fileops (createDummyFile, writeFileAtOffset, readFileAtOffset)
import FuncTorrent.PeerMsgs (Peer(..), PeerMsg(..), sendMsg, getMsg, genHandshakeMsg)
data PState = PState { handle :: Handle
hashes = splitN 20 pieceHash
pLengths = (splitNum fileLen pieceLen)
+updatePieceMap :: FilePath -> PieceMap -> IO PieceMap
+updatePieceMap filePath pieceMap = do
+ dfe <- doesFileExist filePath
+ -- TODO: this is not enough, file should have the same size as well
+ if dfe
+ then pieceMapFromFile filePath pieceMap
+ else return pieceMap
+
+pieceMapFromFile :: FilePath -> PieceMap -> IO PieceMap
+pieceMapFromFile filePath pieceMap = do
+ traverseWithKey f pieceMap
+ where
+ f k v = do
+ let offset = if k == 0 then 0 else k * len (pieceMap ! (k - 1))
+ isHashValid <- (flip verifyHash) (hash v) <$> (readFileAtOffset filePath offset (len v))
+ if isHashValid
+ then return $ v { dlstate = Have }
+ else return $ v
+
havePiece :: PieceMap -> Integer -> Bool
havePiece pm index =
dlstate (pm ! index) == Have
fileLen = lengthInBytes (info m)
fileName = name (info m)
pieceStatus = initPieceMap pieceHash fileLen pLen
+ pieceStatus' <- updatePieceMap fileName pieceStatus
createDummyFile fileName (fromIntegral fileLen)
- _ <- runStateT (msgLoop pieceStatus fileName) pstate
+ _ <- runStateT (msgLoop pieceStatus' fileName) pstate
return ()
msgLoop :: PieceMap -> FilePath -> StateT PState IO ()