{-# LANGUAGE RecordWildCards #-}

module Network.HTTP2.H2.Config where

import Control.Concurrent.STM
import Data.IORef
import Foreign.Marshal.Alloc (free, mallocBytes)
import Network.HTTP.Semantics.Client
import Network.Socket
import Network.Socket.ByteString (sendAll)
import qualified System.TimeManager as T

import Network.HPACK
import Network.HTTP2.H2.Types

-- | Making simple configuration whose IO is not efficient.
--   A write buffer is allocated internally.
--   WAI timeout manger is initialized with 30_000_000 microseconds.
allocSimpleConfig :: Socket -> BufferSize -> IO Config
allocSimpleConfig :: Socket -> Int -> IO Config
allocSimpleConfig Socket
s Int
bufsiz = Socket -> Int -> Int -> IO Config
allocSimpleConfig' Socket
s Int
bufsiz (Int
30 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1000000)

-- | Making simple configuration whose IO is not efficient.
--   A write buffer is allocated internally.
--   The third argument is microseconds to initialize WAI
--   timeout manager.
allocSimpleConfig' :: Socket -> BufferSize -> Int -> IO Config
allocSimpleConfig' :: Socket -> Int -> Int -> IO Config
allocSimpleConfig' Socket
s Int
bufsiz Int
usec = Socket -> Int -> Int -> STM Any -> IO Config
forall a. Socket -> Int -> Int -> STM a -> IO Config
allocSimpleConfigWith Socket
s Int
bufsiz Int
usec STM Any
forall a. STM a
retry

-- | 'allocSimpleConfig'' whose receive the caller can give up on.  The
--   'STM' action is waited for beside each receive; when it fires, the
--   reader ends as it does at end of input.  Nothing is closed and no
--   thread is interrupted to make it return.
--
--   @since 5.4.11
allocSimpleConfigWith :: Socket -> BufferSize -> Int -> STM a -> IO Config
allocSimpleConfigWith :: forall a. Socket -> Int -> Int -> STM a -> IO Config
allocSimpleConfigWith Socket
s Int
bufsiz Int
usec STM a
giveUp = do
    Ptr Word8
confWriteBuffer <- Int -> IO (Ptr Word8)
forall a. Int -> IO (Ptr a)
mallocBytes Int
bufsiz
    let confBufferSize :: Int
confBufferSize = Int
bufsiz
    let confSendAll :: ByteString -> IO ()
confSendAll = Socket -> ByteString -> IO ()
sendAll Socket
s
    ReadN
confReadN <- (\IORef (Maybe ByteString)
ref -> Socket -> IORef (Maybe ByteString) -> STM a -> ReadN
forall a. Socket -> IORef (Maybe ByteString) -> STM a -> ReadN
defaultReadNWith Socket
s IORef (Maybe ByteString)
ref STM a
giveUp) (IORef (Maybe ByteString) -> ReadN)
-> IO (IORef (Maybe ByteString)) -> IO ReadN
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe ByteString -> IO (IORef (Maybe ByteString))
forall a. a -> IO (IORef a)
newIORef Maybe ByteString
forall a. Maybe a
Nothing
    let confPositionReadMaker :: PositionReadMaker
confPositionReadMaker = PositionReadMaker
defaultPositionReadMaker
    Manager
confTimeoutManager <- Int -> IO Manager
T.initialize Int
usec
    SockAddr
confMySockAddr <- Socket -> IO SockAddr
getSocketName Socket
s
    SockAddr
confPeerSockAddr <- Socket -> IO SockAddr
getPeerName Socket
s
    let confReadNTimeout :: Bool
confReadNTimeout = Bool
False
    let confOnInformational :: p -> p -> IO ()
confOnInformational = \p
_ p
_ -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    Config -> IO Config
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Config{Bool
Int
Ptr Word8
SockAddr
Manager
ReadN
Int -> TokenHeaderTable -> IO ()
PositionReadMaker
ByteString -> IO ()
forall {p} {p}. p -> p -> IO ()
confWriteBuffer :: Ptr Word8
confBufferSize :: Int
confSendAll :: ByteString -> IO ()
confReadN :: ReadN
confPositionReadMaker :: PositionReadMaker
confTimeoutManager :: Manager
confMySockAddr :: SockAddr
confPeerSockAddr :: SockAddr
confReadNTimeout :: Bool
confOnInformational :: forall {p} {p}. p -> p -> IO ()
confOnInformational :: Int -> TokenHeaderTable -> IO ()
confReadNTimeout :: Bool
confPeerSockAddr :: SockAddr
confMySockAddr :: SockAddr
confTimeoutManager :: Manager
confPositionReadMaker :: PositionReadMaker
confReadN :: ReadN
confSendAll :: ByteString -> IO ()
confBufferSize :: Int
confWriteBuffer :: Ptr Word8
..}

-- | Deallocating the resource of the simple configuration.
--
--   This does not cancel timeout actions registered with
--   'confTimeoutManager'.  Since time-manager 0.3, a manager holds no
--   registrations, so there is nothing to kill: an action registered with
--   'System.TimeManager.register' runs even after this returns unless it
--   is cancelled with 'System.TimeManager.cancel'.  Use
--   'System.TimeManager.withHandle', which cancels it when the scope ends.
freeSimpleConfig :: Config -> IO ()
freeSimpleConfig :: Config -> IO ()
freeSimpleConfig Config
conf = Ptr Word8 -> IO ()
forall a. Ptr a -> IO ()
free (Ptr Word8 -> IO ()) -> Ptr Word8 -> IO ()
forall a b. (a -> b) -> a -> b
$ Config -> Ptr Word8
confWriteBuffer Config
conf