module FuncTorrent.FileSystem
(startThread,
MsgChannel,
- initFS,
- Msg(..),
+ createMsgChannel,
+ writePiece,
Piece(..),
pieceMapFromFile
)
where
import Control.Concurrent (ThreadId, forkIO)
-import Control.Concurrent.Chan (Chan, newChan, readChan)
+import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)
import Control.Concurrent.MVar (MVar, putMVar)
import Control.Monad (forever)
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
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
+
+writePiece :: MsgChannel -> PieceNum -> BS.ByteString -> IO ()
+writePiece c pieceNum bs = do
+ writeChan c $ WritePiece (Piece pieceNum bs)
+