These are chat archives for vu3rdd/functorrent

15th
Dec 2015
Ramakrishnan Muthukrishnan
@vu3rdd
Dec 15 2015 14:36
I am totally stumped on a very simple thing. How do we maintain statistics of uploaded/downloaded bytes. Sounds simple. I thought of using a State Monad in the FileSystem Module..
but I just can't fit it in an elegant way. :(
@jaseemabid ^^
Jaseem Abid
@jaseemabid
Dec 15 2015 14:37
Cant we keep track of uploaded peices and multiply by piece size?
Ah, when I think about it, you need to remember the number of times the piece was transferred
Ramakrishnan Muthukrishnan
@vu3rdd
Dec 15 2015 14:51
yes, the best place to do that is at the filesystem module when you get readPiece/writePiece message.
it would have been nice to use a StateT Stats IO () type.
where Stats is "data Stats = Stats {bytesUploaded :: Integer, bytesDownloaded :: Integer }
Ramakrishnan Muthukrishnan
@vu3rdd
Dec 15 2015 15:22
This message was deleted
run :: PieceMap -> MsgChannel -> Handle -> IO ()
run pieceMap c handle =
  recvMsg >>= sendResponse
  where
    recvMsg = readChan c
    sendResponse msg =
      case msg of
      ReadPiece n len' var -> do
        bs <- readPiece n len'
        putMVar var (Piece n bs)
      WritePiece (Piece n bs) -> do
        writePiece n bs
      VerifyPiece n var -> do
        isHashValid <- verifyPiece n
        putMVar var isHashValid
    readPiece n len' = do
      let offset = pieceNumToOffset pieceMap n
      readFileAtOffset handle offset len'
    writePiece n piece = do
      let offset = pieceNumToOffset pieceMap n
      writeFileAtOffset handle offset piece
    verifyPiece n = do
      let offset = pieceNumToOffset pieceMap n
          hash'  = hash (pieceMap ! n)
          len'   = len (pieceMap ! n)
      bs' <- readFileAtOffset handle offset len'
      return $ verifyHash bs' hash'
this is what I currently have.
but having Stat will totally break it. :(
Ramakrishnan Muthukrishnan
@vu3rdd
Dec 15 2015 16:31
OK, I solved it this way:
run :: PieceMap -> MsgChannel -> Handle -> IO ()
run pieceMap c handle = do
  _ <- runStateT (run' pieceMap c handle) initialStats
  return ()
    where initialStats = Stats { bytesRead = 0
                               , bytesWritten = 0 }

run' :: PieceMap -> MsgChannel -> Handle -> StateT Stats IO ()
run' pieceMap c handle = do
  msg <- liftIO recvMsg
  liftIO $ sendResponse msg
  updateState msg 
  where
    recvMsg = readChan c
    sendResponse msg =
      case msg of
      ReadPiece n len' var -> do
        bs <- readPiece n len'
        putMVar var (Piece n bs)
      WritePiece (Piece n bs) -> do
        writePiece n bs
      VerifyPiece n var -> do
        isHashValid <- verifyPiece n
        putMVar var isHashValid
    readPiece n len' = do
      let offset = pieceNumToOffset pieceMap n
      readFileAtOffset handle offset len'
    writePiece n piece = do
      let offset = pieceNumToOffset pieceMap n
      writeFileAtOffset handle offset piece
    verifyPiece n = do
      let offset = pieceNumToOffset pieceMap n
          hash'  = hash (pieceMap ! n)
          len'   = len (pieceMap ! n)
      bs' <- readFileAtOffset handle offset len'
      return $ verifyHash bs' hash'
    updateState (ReadPiece _ l _) = do
      st <- get
      modify (\st -> st {bytesRead = (bytesRead st) + l})
    updateState (WritePiece (Piece _ bs)) = do
      st <- get
      modify (\st -> st {bytesWritten = (bytesWritten st) + (fromIntegral (BS.length bs))})
    updateState _ = modify id
there must be better ways to do this.
Ramakrishnan Muthukrishnan
@vu3rdd
Dec 15 2015 16:36
hmm.. lots of stupidity there. no need for those get calls.
run' :: PieceMap -> MsgChannel -> Handle -> StateT Stats IO ()
run' pieceMap c handle = do
  msg <- liftIO recvMsg
  liftIO $ sendResponse msg
  updateState msg 
  where
    recvMsg = readChan c
    sendResponse msg =
      case msg of
      ReadPiece n len' var -> do
        bs <- readPiece n len'
        putMVar var (Piece n bs)
      WritePiece (Piece n bs) ->
        writePiece n bs
      VerifyPiece n var -> do
        isHashValid <- verifyPiece n
        putMVar var isHashValid
    readPiece n len' = do
      let offset = pieceNumToOffset pieceMap n
      readFileAtOffset handle offset len'
    writePiece n piece = do
      let offset = pieceNumToOffset pieceMap n
      writeFileAtOffset handle offset piece
    verifyPiece n = do
      let offset = pieceNumToOffset pieceMap n
          hash'  = hash (pieceMap ! n)
          len'   = len (pieceMap ! n)
      bs' <- readFileAtOffset handle offset len'
      return $ verifyHash bs' hash'
    updateState (ReadPiece _ l _) =
      modify (\st -> st {bytesRead = bytesRead st + l})
    updateState (WritePiece (Piece _ bs)) =
      modify (\st -> st {bytesWritten = bytesWritten st + fromIntegral (BS.length bs)})
    updateState _ = modify id
@jaseemabid
Ramakrishnan Muthukrishnan
@vu3rdd
Dec 15 2015 17:29
One problem with the independent threads with an associated msg channel is that even if the thread is dead, the channel could be active and misleading. It is just buffering messages but no one is acting on it.