{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}

module Network.HTTP2.Server.Types where

import Control.Concurrent.STM
import Control.Exception (SomeException)
import Data.ByteString.Builder (Builder)
import Data.IORef
import Data.IntMap.Strict (IntMap)

import Imports
import Network.HPACK
import Network.HTTP2
import Network.HTTP2.Priority
import Network.HTTP2.Server.API

----------------------------------------------------------------

data OpenState =
    JustOpened
  | Continued [HeaderBlockFragment]
              !Int  -- Total size
              !Int  -- The number of continuation frames
              !Bool -- End of stream
              !Priority
  | NoBody HeaderTable !Priority
  | HasBody HeaderTable !Priority
  | Body !(TQueue ByteString)
         !(Maybe Int) -- received Content-Length
                      -- compared the body length for error checking
         !(IORef Int) -- actual body length
         !(IORef (Maybe HeaderTable)) -- trailers

data ClosedCode = Finished
                | Killed
                | Reset !ErrorCodeId
                | ResetByMe SomeException
                deriving Int -> ClosedCode -> ShowS
[ClosedCode] -> ShowS
ClosedCode -> String
(Int -> ClosedCode -> ShowS)
-> (ClosedCode -> String)
-> ([ClosedCode] -> ShowS)
-> Show ClosedCode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ClosedCode] -> ShowS
$cshowList :: [ClosedCode] -> ShowS
show :: ClosedCode -> String
$cshow :: ClosedCode -> String
showsPrec :: Int -> ClosedCode -> ShowS
$cshowsPrec :: Int -> ClosedCode -> ShowS
Show

----------------------------------------------------------------

data StreamState =
    Idle
  | Open !OpenState
  | HalfClosedRemote
  | HalfClosedLocal !ClosedCode
  | Closed !ClosedCode
  | Reserved

instance Show StreamState where
    show :: StreamState -> String
show Idle        = "Idle"
    show Open{}      = "Open"
    show HalfClosedRemote  = "HalfClosedRemote"
    show (HalfClosedLocal e :: ClosedCode
e)  = "HalfClosedLocal: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ClosedCode -> String
forall a. Show a => a -> String
show ClosedCode
e
    show (Closed e :: ClosedCode
e)  = "Closed: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ClosedCode -> String
forall a. Show a => a -> String
show ClosedCode
e
    show Reserved    = "Reserved"

----------------------------------------------------------------

data Stream = Stream {
    Stream -> Int
streamNumber     :: !StreamId
  , Stream -> IORef StreamState
streamState      :: !(IORef StreamState)
  , Stream -> TVar Int
streamWindow     :: !(TVar WindowSize)
  , Stream -> IORef Precedence
streamPrecedence :: !(IORef Precedence)
  }

instance Show Stream where
  show :: Stream -> String
show s :: Stream
s = Int -> String
forall a. Show a => a -> String
show (Stream -> Int
streamNumber Stream
s)

----------------------------------------------------------------

newtype StreamTable = StreamTable (IORef (IntMap Stream))

----------------------------------------------------------------

data Input = Input Stream Request

data Output = Output {
    Output -> Stream
outputStream   :: Stream
  , Output -> Response
outputResponse :: Response
  , Output -> OutputType
outputType     :: OutputType
  , Output -> Maybe (TBQueue RspStreaming)
outputStrmQ    :: Maybe (TBQueue RspStreaming)
  , Output -> IO ()
outputSentinel :: IO ()
  }

data OutputType = ORspn
                | OWait (IO ())
                | OPush !TokenHeaderList !StreamId -- associated stream id from client
                | ONext !DynaNext !TrailersMaker

----------------------------------------------------------------

type DynaNext = Buffer -> BufferSize -> WindowSize -> IO Next

type BytesFilled = Int

data Next = Next !BytesFilled (Maybe DynaNext)

----------------------------------------------------------------

data Control = CFinish
             | CGoaway    !ByteString
             | CFrame     !ByteString
             | CSettings  !ByteString !SettingsList
             | CSettings0 !ByteString !ByteString !SettingsList

----------------------------------------------------------------

data RspStreaming = RSFinish
                  | RSFlush
                  | RSBuilder Builder