FileSystem: encapsulate more filesystem functionality into the module
authorRamakrishnan Muthukrishnan <ram@rkrishnan.org>
Thu, 10 Dec 2015 13:23:21 +0000 (18:53 +0530)
committerRamakrishnan Muthukrishnan <ram@rkrishnan.org>
Thu, 10 Dec 2015 13:23:21 +0000 (18:53 +0530)
src/FuncTorrent/FileSystem.hs
src/main/Main.hs

index 1b190ca88936b197ab3563e1fc8a1e8238629575..e064b713c68607bd05941e22e5bce8ae64d86ddb 100644 (file)
@@ -1,7 +1,7 @@
 module FuncTorrent.FileSystem
        (startThread,
         MsgChannel,
-        initFS,
+        createMsgChannel,
         Msg(..),
         Piece(..),
         pieceMapFromFile
@@ -16,10 +16,11 @@ import           Data.Map (traverseWithKey)
 
 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
@@ -30,15 +31,11 @@ data Msg = ReadPiece PieceNum Integer (MVar Piece)
 
 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
@@ -65,13 +62,16 @@ startThread handle c pieceMap = do
       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
index a75f01c122df050615e645c4ba9f0fb4f55563da..a7efef0570b878d7be548d1614a045ea4b83ee63 100644 (file)
@@ -6,15 +6,15 @@ import           Prelude hiding (log, length, readFile, getContents)
 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)
@@ -71,18 +71,11 @@ main = do
            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