1 module FuncTorrent.FileSystem
11 import Control.Concurrent (ThreadId, forkIO)
12 import Control.Concurrent.Chan (Chan, newChan, readChan)
13 import Control.Concurrent.MVar (MVar, putMVar)
14 import Control.Monad (forever)
15 import Data.Map (traverseWithKey)
17 import qualified Data.ByteString as BS
19 import System.IO (Handle, IOMode (ReadWriteMode), withFile)
20 import System.Directory (doesFileExist)
22 import FuncTorrent.PieceManager (PieceDlState(..), PieceData(..), PieceMap, pieceNumToOffset)
23 import FuncTorrent.Utils (createDummyFile, readFileAtOffset, writeFileAtOffset, verifyHash)
25 type PieceNum = Integer
26 data Piece = Piece PieceNum BS.ByteString
28 data Msg = ReadPiece PieceNum Integer (MVar Piece)
30 | VerifyPiece PieceNum (MVar Bool)
32 type MsgChannel = Chan Msg
34 createMsgChannel :: IO (Chan Msg)
35 createMsgChannel = newChan
37 startThread :: PieceMap -> MsgChannel -> Handle -> IO ThreadId
38 startThread pieceMap c handle = do
39 forkIO $ forever $ recvMsg >>= sendResponse
44 ReadPiece n len' var -> do
45 bs <- readPiece n len'
46 putMVar var (Piece n bs)
47 WritePiece (Piece n bs) -> do
49 VerifyPiece n var -> do
50 isHashValid <- verifyPiece n
51 putMVar var isHashValid
53 let offset = pieceNumToOffset pieceMap n
54 readFileAtOffset handle offset len'
55 writePiece n piece = do
56 let offset = pieceNumToOffset pieceMap n
57 writeFileAtOffset handle offset piece
59 let offset = pieceNumToOffset pieceMap n
60 hash' = hash (pieceMap ! n)
61 len' = len (pieceMap ! n)
62 bs' <- readFileAtOffset handle offset len'
63 return $ verifyHash bs' hash'
65 pieceMapFromFile :: FilePath -> Integer -> PieceMap -> IO PieceMap
66 pieceMapFromFile filePath fileLen pieceMap = do
67 dfe <- doesFileExist filePath
69 then traverseWithKey f pieceMap
70 else createDummyFile filePath (fromIntegral fileLen) >> return pieceMap
73 let offset = pieceNumToOffset pieceMap k
74 isHashValid <- flip verifyHash (hash v) <$> withFile filePath ReadWriteMode (\handle -> readFileAtOffset handle offset (len v))
76 then return $ v { dlstate = Have }