From: Ramakrishnan Muthukrishnan Date: Thu, 17 Sep 2015 22:04:12 +0000 (+0530) Subject: refactor the piecemap initialization X-Git-Url: https://git.rkrishnan.org/%5B/%5D%20/uri/flags/%22doc.html/copyable.html?a=commitdiff_plain;h=9d4aab0d9382c070bfaf965ddfe139affa64dcd5;p=functorrent.git refactor the piecemap initialization Move parts of the download resume code into Main, since it avoids duplication of some code and makes the flow, a lot more easy to understand. --- diff --git a/src/FuncTorrent/Peer.hs b/src/FuncTorrent/Peer.hs index 13c07e3..157dab0 100644 --- a/src/FuncTorrent/Peer.hs +++ b/src/FuncTorrent/Peer.hs @@ -1,14 +1,16 @@ {-# LANGUAGE OverloadedStrings #-} module FuncTorrent.Peer (Peer(..), + PieceMap, handlePeerMsgs, - bytesDownloaded + bytesDownloaded, + initPieceMap, + pieceMapFromFile ) where 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(..)) @@ -20,7 +22,7 @@ import qualified Crypto.Hash.SHA1 as SHA1 (hash) import Safe (headMay) import FuncTorrent.Metainfo (Info(..), Metainfo(..)) -import FuncTorrent.Utils (splitN, splitNum, createDummyFile, writeFileAtOffset, readFileAtOffset) +import FuncTorrent.Utils (splitN, splitNum, writeFileAtOffset, readFileAtOffset) import FuncTorrent.PeerMsgs (Peer(..), PeerMsg(..), sendMsg, getMsg, genHandshakeMsg) data PState = PState { handle :: Handle @@ -61,14 +63,6 @@ initPieceMap pieceHash fileLen pieceLen = fromList kvs 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 @@ -139,19 +133,13 @@ updatePieceAvailability pieceStatus p pieceList = then (pd { peers = p : peers pd }) else pd) pieceStatus -handlePeerMsgs :: Peer -> String -> Metainfo -> IO () -handlePeerMsgs p peerId m = do +handlePeerMsgs :: Peer -> String -> Metainfo -> PieceMap -> IO () +handlePeerMsgs p peerId m pieceMap = do h <- connectToPeer p doHandshake h p (infoHash m) peerId let pstate = toPeerState h p False False True True - pieceHash = pieces (info m) - pLen = pieceLength (info m) - 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 + filePath = name (info m) + _ <- runStateT (msgLoop pieceMap filePath) pstate return () msgLoop :: PieceMap -> FilePath -> StateT PState IO () diff --git a/src/FuncTorrent/Server.hs b/src/FuncTorrent/Server.hs index e675c6c..b78be29 100644 --- a/src/FuncTorrent/Server.hs +++ b/src/FuncTorrent/Server.hs @@ -7,7 +7,7 @@ import Network (withSocketsDo, listenOn, accept, Socket, PortID ( PortNumber )) import System.IO (hSetBuffering, BufferMode ( NoBuffering )) import FuncTorrent.Metainfo (Metainfo) -import FuncTorrent.Peer (handlePeerMsgs, Peer(..)) +import FuncTorrent.Peer (handlePeerMsgs, Peer(..), PieceMap) -- server is listening on any port from 6881 - 6889 -- return the port number used @@ -17,9 +17,9 @@ start = withSocketsDo $ do sock <- listenOn $ PortNumber $ fromIntegral (head portnums) return (sock, PortNumber $ head portnums) -run :: Socket -> String -> Metainfo -> IO () -run listenSock peerid m = forever $ do +run :: Socket -> String -> Metainfo -> PieceMap -> IO () +run listenSock peerid m pieceMap = forever $ do (handle, ip, port) <- accept listenSock let peer = Peer "" ip (fromIntegral port) hSetBuffering handle NoBuffering - forkIO $ handlePeerMsgs peer peerid m + forkIO $ handlePeerMsgs peer peerid m pieceMap diff --git a/src/FuncTorrent/Utils.hs b/src/FuncTorrent/Utils.hs index de2a456..ac08927 100644 --- a/src/FuncTorrent/Utils.hs +++ b/src/FuncTorrent/Utils.hs @@ -13,7 +13,6 @@ import System.IO (withFile, hSeek, IOMode(..), SeekMode(..)) import System.Directory (doesFileExist) import Data.ByteString (ByteString, writeFile, hPut, hGet) import qualified Data.ByteString.Char8 as BC -import qualified Data.ByteString.Char8 as BC (replicate) splitN :: Int -> BC.ByteString -> [BC.ByteString] splitN n bs | BC.null bs = [] diff --git a/src/main/Main.hs b/src/main/Main.hs index ae3c035..79cd9bf 100644 --- a/src/main/Main.hs +++ b/src/main/Main.hs @@ -1,10 +1,10 @@ {-# LANGUAGE OverloadedStrings #-} module Main where -import Prelude hiding (log, length, readFile, getContents) +import Prelude hiding (log, length, readFile, getContents, replicate, writeFile) import Control.Concurrent (forkIO) -import Data.ByteString.Char8 (ByteString, getContents, readFile, unpack) +import Data.ByteString.Char8 (ByteString, getContents, readFile, writeFile, unpack, replicate) import Network (PortID (PortNumber)) import System.Environment (getArgs) import System.Exit (exitSuccess) @@ -13,7 +13,7 @@ import System.Random (getStdGen, randomRs) import FuncTorrent.Logger (initLogger, logMessage, logStop) import FuncTorrent.Metainfo (Info(..), Metainfo(..), torrentToMetainfo) -import FuncTorrent.Peer (handlePeerMsgs) +import FuncTorrent.Peer (initPieceMap, handlePeerMsgs, pieceMapFromFile) import qualified FuncTorrent.Server as Server import FuncTorrent.Tracker (peers, getTrackerResponse) @@ -57,18 +57,30 @@ main = do case torrentToMetainfo torrentStr of Left e -> logError e log Right m -> do - let p = name (info m) - log $ "Downloading file : " ++ p -- if we had downloaded the file before (partly or completely) -- then we should check the current directory for the existence -- of the file and then update the map of each piece' availability. -- This can be donw by reading each piece and verifying the checksum. -- If the checksum does not match, we don't have that piece. + let filePath = name (info m) -- really this is just the file name, not file path + fileLen = lengthInBytes (info m) + pieceHash = pieces (info m) + pLen = pieceLength (info m) + defaultPieceMap = initPieceMap pieceHash fileLen pLen + log $ "Downloading file : " ++ filePath + dfe <- doesFileExist filePath + pieceMap <- if dfe + then + pieceMapFromFile filePath defaultPieceMap + else do + -- create a dummy file + _ <- writeFile filePath (replicate (fromIntegral fileLen) '\0') + return defaultPieceMap log $ "starting server" (serverSock, (PortNumber portnum)) <- Server.start log $ "server started on " ++ show portnum log "Trying to fetch peers" - forkIO $ Server.run serverSock peerId m + forkIO $ Server.run serverSock peerId m pieceMap log $ "Trackers: " ++ head (announceList m) trackerResp <- getTrackerResponse portnum peerId m case trackerResp of @@ -76,5 +88,5 @@ main = do Right peerList -> do log $ "Peers List : " ++ (show . peers $ peerList) let p1 = head (peers peerList) - handlePeerMsgs p1 peerId m + handlePeerMsgs p1 peerId m pieceMap logStop logR