module FuncTorrent.FileSystem
(startThread,
MsgChannel,
- initFS,
+ createMsgChannel,
Msg(..),
Piece(..),
pieceMapFromFile
import qualified Data.ByteString as BS
import Data.Map ((!))
-import System.IO (Handle, openFile, IOMode (ReadWriteMode))
+import System.IO (Handle, IOMode (ReadWriteMode), withFile)
+import System.Directory (doesFileExist)
import FuncTorrent.PieceManager (PieceDlState(..), PieceData(..), PieceMap, pieceNumToOffset)
-import FuncTorrent.Utils (readFileAtOffset, writeFileAtOffset, verifyHash)
+import FuncTorrent.Utils (createDummyFile, readFileAtOffset, writeFileAtOffset, verifyHash)
type PieceNum = Integer
data Piece = Piece PieceNum BS.ByteString
type MsgChannel = Chan Msg
--- init :: FileName -> IO (Handle, MsgChannel)
-initFS :: FilePath -> IO (Handle, MsgChannel)
-initFS filepath = do
- c <- newChan
- h <- openFile filepath ReadWriteMode
- return (h, c)
+createMsgChannel :: IO (Chan Msg)
+createMsgChannel = newChan
-startThread :: Handle -> MsgChannel -> PieceMap -> IO ThreadId
-startThread handle c pieceMap = do
+startThread :: PieceMap -> MsgChannel -> Handle -> IO ThreadId
+startThread pieceMap c handle = do
forkIO $ forever $ recvMsg >>= sendResponse
where
recvMsg = readChan c
bs' <- readFileAtOffset handle offset len'
return $ verifyHash bs' hash'
-pieceMapFromFile :: Handle -> PieceMap -> IO PieceMap
-pieceMapFromFile handle pieceMap = do
- traverseWithKey f pieceMap
+pieceMapFromFile :: FilePath -> Integer -> PieceMap -> IO PieceMap
+pieceMapFromFile filePath fileLen pieceMap = do
+ dfe <- doesFileExist filePath
+ if dfe
+ then traverseWithKey f pieceMap
+ else createDummyFile filePath (fromIntegral fileLen) >> return pieceMap
where
f k v = do
let offset = pieceNumToOffset pieceMap k
- isHashValid <- flip verifyHash (hash v) <$> readFileAtOffset handle offset (len v)
+ isHashValid <- flip verifyHash (hash v) <$> withFile filePath ReadWriteMode (\handle -> readFileAtOffset handle offset (len v))
if isHashValid
then return $ v { dlstate = Have }
else return v
import Control.Concurrent (forkIO)
import Control.Concurrent.MVar (readMVar)
import Data.ByteString.Char8 (ByteString, getContents, readFile)
-import qualified FuncTorrent.FileSystem as FS (initFS, pieceMapFromFile, startThread)
+import qualified FuncTorrent.FileSystem as FS (createMsgChannel, pieceMapFromFile, startThread)
import FuncTorrent.Logger (initLogger, logMessage, logStop)
import FuncTorrent.Metainfo (Info(..), Metainfo(..), torrentToMetainfo)
import FuncTorrent.Peer (handlePeerMsgs)
import FuncTorrent.PieceManager (initPieceMap)
import qualified FuncTorrent.Server as Server
import FuncTorrent.Tracker (connectedPeers, initialTrackerState, trackerLoop, udpTrackerLoop)
-import FuncTorrent.Utils (createDummyFile)
import Network (PortID (PortNumber))
+import System.IO (withFile, IOMode (ReadWriteMode))
import System.Directory (doesFileExist)
import System.Environment (getArgs)
import System.Exit (exitSuccess)
pLen = pieceLength (info m)
defaultPieceMap = initPieceMap pieceHash fileLen pLen
log $ "create FS msg channel"
- (handle, fsMsgChannel) <- FS.initFS filePath
+ fsMsgChannel <- FS.createMsgChannel
log $ "Downloading file : " ++ filePath
- dfe <- doesFileExist filePath
- pieceMap <- if dfe
- then
- FS.pieceMapFromFile handle defaultPieceMap
- else do
- -- create a dummy file
- createDummyFile filePath (fromIntegral fileLen) >>
- return defaultPieceMap
+ pieceMap <- FS.pieceMapFromFile filePath fileLen defaultPieceMap
log $ "start filesystem manager thread"
- FS.startThread handle fsMsgChannel pieceMap
+ withFile filePath ReadWriteMode (FS.startThread pieceMap fsMsgChannel)
log $ "starting server"
(serverSock, (PortNumber portnum)) <- Server.start
log $ "server started on " ++ show portnum