module Network.HTTP.Semantics.File (
    -- * Position read
    PositionRead,
    PositionReadMaker,
    Sentinel (..),
    defaultPositionReadMaker,
) where

import System.IO

import Network.ByteOrder
import Network.HTTP.Semantics

-- | Position read for files.
type PositionRead = FileOffset -> ByteCount -> Buffer -> IO ByteCount

-- | Making a position read and its closer.
type PositionReadMaker = FilePath -> IO (PositionRead, Sentinel)

--- | Manipulating a file resource.
data Sentinel
    = -- | Closing a file resource. Its refresher is automatiaclly generated by
      --   the internal timer.
      Closer (IO ())
    | -- | Refreshing a file resource while reading.
      --   Closing the file must be done by its own timer or something.
      Refresher (IO ())

-- | Position read based on 'Handle'.
defaultPositionReadMaker :: PositionReadMaker
defaultPositionReadMaker :: PositionReadMaker
defaultPositionReadMaker FilePath
file = do
    Handle
hdl <- FilePath -> IOMode -> IO Handle
openBinaryFile FilePath
file IOMode
ReadMode
    (PositionRead, Sentinel) -> IO (PositionRead, Sentinel)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Handle -> PositionRead
pread Handle
hdl, IO () -> Sentinel
Closer (IO () -> Sentinel) -> IO () -> Sentinel
forall a b. (a -> b) -> a -> b
$ Handle -> IO ()
hClose Handle
hdl)
  where
    pread :: Handle -> PositionRead
    pread :: Handle -> PositionRead
pread Handle
hdl FileOffset
off FileOffset
bytes Buffer
buf = do
        Handle -> SeekMode -> Integer -> IO ()
hSeek Handle
hdl SeekMode
AbsoluteSeek (Integer -> IO ()) -> Integer -> IO ()
forall a b. (a -> b) -> a -> b
$ FileOffset -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral FileOffset
off
        Int -> FileOffset
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> FileOffset) -> IO Int -> IO FileOffset
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Handle -> Buffer -> Int -> IO Int
forall a. Handle -> Ptr a -> Int -> IO Int
hGetBufSome Handle
hdl Buffer
buf (FileOffset -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral FileOffset
bytes)