<commit_before>-- |
--   Copyright   :  (c) <NAME> 2013
--   License     :  BSD3
--   Maintainer  :  <EMAIL>
--   Stability   :  experimental
--   Portability :  portable
--
--   This module implements mapping from single continious piece space
--   to file storage. Storage can be used in two modes:
--
--     * As in memory storage - in this case we don't touch filesystem.
--
--     * As ordinary mmaped file storage - when we need to store
--       data in the filesystem.
--
{-# LANGUAGE RecordWildCards            #-}
{-# LANGUAGE DeriveDataTypeable         #-}
module System.Torrent.Storage
       ( -- * Storage
         Storage
       , StorageFailure (..)

         -- * Construction
       , Mode (..)
       , def
       , open
       , close
       , withStorage

         -- * Query
       , totalPieces
       , verifyPiece
       , genPieceInfo
       , getBitfield

         -- * Modification
       , writePiece
       , readPiece
       , hintRead
       , unsafeReadPiece

         -- * Streaming
       , sourceStorage
       , sinkStorage
       ) where

import Control.Applicative
import Control.Exception
import Control.Monad as M
import Control.Monad.Trans
import Data.ByteString.Lazy as BL
import Data.Conduit as C
import Data.Conduit.Binary as C
import Data.Conduit.List as C
import Data.Typeable

import Data.Torrent.Bitfield as BF
import Data.Torrent.Layout
import Data.Torrent.Piece
import System.Torrent.FileMap as FM


-- | Some storage operations may throw an exception if misused.
data StorageFailure
    -- | Occurs on a write operation if the storage has been opened
    --   using 'ReadOnly' mode.
  = StorageIsRO

    -- | Piece index is out of bounds.
  | InvalidIndex PieceIx

    -- | Piece size do not match with one passed to the 'open'
    -- function.
  | InvalidSize  PieceSize
    deriving (Show, Eq, Typeable)

instance Exception StorageFailure

-- | Pieces store.
data Storage = Storage
  { mode     ::                !Mode
  , pieceLen :: {-# UNPACK #-} !PieceSize
  , fileMap  :: {-# UNPACK #-} !FileMap
  }

-- | Map torrent files:
--
--   * when torrent first created use 'ReadWriteEx' mode;
--
--   * when seeding, validation 'ReadOnly' mode.
--
open :: Mode -> PieceSize -> FileLayout FileSize -> IO Storage
open mode s l
  |   s <= 0  = throwIO (InvalidSize s)
  | otherwise = Storage mode s <$> mmapFiles mode l

-- | Unmaps all files forcefully. It is recommended but not required.
close :: Storage -> IO ()
close Storage {..} = unmapFiles fileMap

-- | Normally you need to use 'Control.Monad.Trans.Resource.allocate'.
withStorage :: Mode -> PieceSize -> FileLayout FileSize
            -> (Storage -> IO ()) -> IO ()
withStorage m s l = bracket (open m s l) close

-- TODO allocateStorage?

-- | Count of pieces in the storage.
totalPieces :: Storage -> PieceCount
totalPieces Storage {..} = FM.size fileMap `sizeInBase` pieceLen

isValidIx :: PieceIx -> Storage -> Bool
isValidIx i s = 0 <= i && i < totalPieces s
<commit_msg>Add openInfoDict function<commit_after>-- |
--   Copyright   :  (c) <NAME> 2013
--   License     :  BSD3
--   Maintainer  :  <EMAIL>
--   Stability   :  experimental
--   Portability :  portable
--
--   This module implements mapping from single continious piece space
--   to file storage. Storage can be used in two modes:
--
--     * As in memory storage - in this case we don't touch filesystem.
--
--     * As ordinary mmaped file storage - when we need to store
--       data in the filesystem.
--
{-# LANGUAGE RecordWildCards            #-}
{-# LANGUAGE DeriveDataTypeable         #-}
module System.Torrent.Storage
       ( -- * Storage
         Storage
       , StorageFailure (..)

         -- * Construction
       , Mode (..)
       , def
       , open
       , openInfoDict
       , close
       , withStorage

         -- * Query
       , totalPieces
       , verifyPiece
       , genPieceInfo
       , getBitfield

         -- * Modification
       , writePiece
       , readPiece
       , hintRead
       , unsafeReadPiece

         -- * Streaming
       , sourceStorage
       , sinkStorage
       ) where

import Control.Applicative
import Control.Exception
import Control.Monad as M
import Control.Monad.Trans
import Data.ByteString.Lazy as BL
import Data.Conduit as C
import Data.Conduit.Binary as C
import Data.Conduit.List as C
import Data.Typeable

import Data.Torrent
import Data.Torrent.Bitfield as BF
import Data.Torrent.Layout
import Data.Torrent.Piece
import System.Torrent.FileMap as FM


-- | Some storage operations may throw an exception if misused.
data StorageFailure
    -- | Occurs on a write operation if the storage has been opened
    --   using 'ReadOnly' mode.
  = StorageIsRO

    -- | Piece index is out of bounds.
  | InvalidIndex PieceIx

    -- | Piece size do not match with one passed to the 'open'
    -- function.
  | InvalidSize  PieceSize
    deriving (Show, Eq, Typeable)

instance Exception StorageFailure

-- | Pieces store.
data Storage = Storage
  { mode     ::                !Mode
  , pieceLen :: {-# UNPACK #-} !PieceSize
  , fileMap  :: {-# UNPACK #-} !FileMap
  }

-- | Map torrent files:
--
--   * when torrent first created use 'ReadWriteEx' mode;
--
--   * when seeding, validation 'ReadOnly' mode.
--
open :: Mode -> PieceSize -> FileLayout FileSize -> IO Storage
open mode s l
  |   s <= 0  = throwIO (InvalidSize s)
  | otherwise = Storage mode s <$> mmapFiles mode l

-- | Like 'open', but use 'InfoDict' file layout.
openInfoDict :: Mode -> FilePath -> InfoDict -> IO Storage
openInfoDict mode rootPath InfoDict {..} =
  open mode (piPieceLength idPieceInfo) (flatLayout rootPath idLayoutInfo)

-- | Unmaps all files forcefully. It is recommended but not required.
close :: Storage -> IO ()
close Storage {..} = unmapFiles fileMap

-- | Normally you need to use 'Control.Monad.Trans.Resource.allocate'.
withStorage :: Mode -> PieceSize -> FileLayout FileSize
            -> (Storage -> IO ()) -> IO ()
withStorage m s l = bracket (open m s l) close

-- TODO allocateStorage?

-- | Count of pieces in the storage.
totalPieces :: Storage -> PieceCount
totalPieces Storage {..} = FM.size fileMap `sizeInBase` pieceLen

isValidIx :: PieceIx -> Storage -> Bool
isValidIx i s = 0 <= i && i < totalPieces s

{'fraction_non_alphanumeric': 0.1039002557544757, 'fraction_numerical': 0.002237851662404092, 'mean_word_length': 2.3070824524312896, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 36, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1757556', 'n_tokens_mistral': 1911, 'n_tokens_neox': 1866, 'n_words': 633}