    {-# LANGUAGE CPP #-}
    --------------------------------------------------------------------------------
    module Network.WebSockets.Connection.Options
        ( ConnectionOptions (..)
        , defaultConnectionOptions

        , CompressionOptions (..)
        , PermessageDeflate (..)
        , defaultPermessageDeflate

        , SizeLimit (..)
        , atMostSizeLimit
        ) where

    --------------------------------------------------------------------------------
    import           Data.Int    (Int64)
    import           Data.Monoid (Monoid (..))
    import           Prelude

    --------------------------------------------------------------------------------
    -- | Set options for a 'Connection'.  Please do not use this constructor
    -- directly, but rather use 'defaultConnectionOptions' and then set the fields
    -- you want, e.g.:
    --
    -- > myOptions = defaultConnectionOptions {connectionStrictUnicode = True}
    --
    -- This way your code does not break if the library introduces new fields.
    data ConnectionOptions = ConnectionOptions
        { ConnectionOptions -> IO ()
    connectionOnPong                :: !(IO ())
          -- ^ Whenever a 'pong' is received, this IO action is executed. It can be
          -- used to tickle connections or fire missiles.
        , ConnectionOptions -> Int
    connectionTimeout               :: !Int
          -- ^ Timeout for connection establishment in seconds. Only used in the client.
        , ConnectionOptions -> CompressionOptions
    connectionCompressionOptions    :: !CompressionOptions
          -- ^ Enable 'PermessageDeflate'.
        , ConnectionOptions -> Bool
    connectionStrictUnicode         :: !Bool
          -- ^ Enable strict unicode on the connection.  This means that if a client
          -- (or server) sends invalid UTF-8, we will throw a 'UnicodeException'
          -- rather than replacing it by the unicode replacement character U+FFFD.
        , ConnectionOptions -> SizeLimit
    connectionFramePayloadSizeLimit :: !SizeLimit
          -- ^ The maximum size for incoming frame payload size in bytes.  If a
          -- frame exceeds this limit, a 'ParseException' is thrown.
        , ConnectionOptions -> SizeLimit
    connectionMessageDataSizeLimit  :: !SizeLimit
          -- ^ 'connectionFrameSizeLimit' is often not enough since a malicious
          -- client can send many small frames to create a huge message.  This limit
          -- allows you to protect from that.  If a message exceeds this limit, a
          -- 'ParseException' is thrown.
          --
          -- Note that, if compression is enabled, we check the size of the
          -- compressed messages, as well as the size of the uncompressed messages
          -- as we are deflating them to ensure we don't use too much memory in any
          -- case.
        }

    --------------------------------------------------------------------------------
    -- | The default connection options:
    --
    -- * Nothing happens when a pong is received.
    -- * Compression is disabled.
    -- * Lenient unicode decoding.
    -- * 30 second timeout for connection establishment.
    defaultConnectionOptions :: ConnectionOptions
    defaultConnectionOptions :: ConnectionOptions
    defaultConnectionOptions = ConnectionOptions
        { connectionOnPong :: IO ()
    connectionOnPong                = () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
        , connectionTimeout :: Int
    connectionTimeout               = Int
    30
        , connectionCompressionOptions :: CompressionOptions
    connectionCompressionOptions    = CompressionOptions
    NoCompression
        , connectionStrictUnicode :: Bool
    connectionStrictUnicode         = Bool
    False
        , connectionFramePayloadSizeLimit :: SizeLimit
    connectionFramePayloadSizeLimit = SizeLimit
    forall a. Monoid a => a
    mempty
        , connectionMessageDataSizeLimit :: SizeLimit
    connectionMessageDataSizeLimit  = SizeLimit
    forall a. Monoid a => a
    mempty
        }

    --------------------------------------------------------------------------------
    data CompressionOptions
        = NoCompression
        | PermessageDeflateCompression PermessageDeflate
        deriving (CompressionOptions -> CompressionOptions -> Bool
    (CompressionOptions -> CompressionOptions -> Bool)
    -> (CompressionOptions -> CompressionOptions -> Bool)
    -> Eq CompressionOptions
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: CompressionOptions -> CompressionOptions -> Bool
    == :: CompressionOptions -> CompressionOptions -> Bool
    $c/= :: CompressionOptions -> CompressionOptions -> Bool
    /= :: CompressionOptions -> CompressionOptions -> Bool
    Eq, Int -> CompressionOptions -> ShowS
    [CompressionOptions] -> ShowS
    CompressionOptions -> String
    (Int -> CompressionOptions -> ShowS)
    -> (CompressionOptions -> String)
    -> ([CompressionOptions] -> ShowS)
    -> Show CompressionOptions
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> CompressionOptions -> ShowS
    showsPrec :: Int -> CompressionOptions -> ShowS
    $cshow :: CompressionOptions -> String
    show :: CompressionOptions -> String
    $cshowList :: [CompressionOptions] -> ShowS
    showList :: [CompressionOptions] -> ShowS
    Show)

    --------------------------------------------------------------------------------
    -- | Four extension parameters are defined for "permessage-deflate" to
    -- help endpoints manage per-connection resource usage.
    --
    -- - "server_no_context_takeover"
    -- - "client_no_context_takeover"
    -- - "server_max_window_bits"
    -- - "client_max_window_bits"
    data PermessageDeflate = PermessageDeflate
        { PermessageDeflate -> Bool
    serverNoContextTakeover :: Bool
        , PermessageDeflate -> Bool
    clientNoContextTakeover :: Bool
        , PermessageDeflate -> Int
    serverMaxWindowBits     :: Int
        , PermessageDeflate -> Int
    clientMaxWindowBits     :: Int
        , PermessageDeflate -> Int
    pdCompressionLevel      :: Int
        } deriving (PermessageDeflate -> PermessageDeflate -> Bool
    (PermessageDeflate -> PermessageDeflate -> Bool)
    -> (PermessageDeflate -> PermessageDeflate -> Bool)
    -> Eq PermessageDeflate
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: PermessageDeflate -> PermessageDeflate -> Bool
    == :: PermessageDeflate -> PermessageDeflate -> Bool
    $c/= :: PermessageDeflate -> PermessageDeflate -> Bool
    /= :: PermessageDeflate -> PermessageDeflate -> Bool
    Eq, Int -> PermessageDeflate -> ShowS
    [PermessageDeflate] -> ShowS
    PermessageDeflate -> String
    (Int -> PermessageDeflate -> ShowS)
    -> (PermessageDeflate -> String)
    -> ([PermessageDeflate] -> ShowS)
    -> Show PermessageDeflate
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> PermessageDeflate -> ShowS
    showsPrec :: Int -> PermessageDeflate -> ShowS
    $cshow :: PermessageDeflate -> String
    show :: PermessageDeflate -> String
    $cshowList :: [PermessageDeflate] -> ShowS
    showList :: [PermessageDeflate] -> ShowS
    Show)

    --------------------------------------------------------------------------------
    defaultPermessageDeflate :: PermessageDeflate
    defaultPermessageDeflate :: PermessageDeflate
    defaultPermessageDeflate = Bool -> Bool -> Int -> Int -> Int -> PermessageDeflate
    PermessageDeflate Bool
    False Bool
    False Int
    15 Int
    15 Int
    8

    --------------------------------------------------------------------------------
    -- | A size limit, in bytes.  The 'Monoid' instance takes the minimum limit.
    data SizeLimit
        = NoSizeLimit
        | SizeLimit !Int64
        deriving (SizeLimit -> SizeLimit -> Bool
    (SizeLimit -> SizeLimit -> Bool)
    -> (SizeLimit -> SizeLimit -> Bool) -> Eq SizeLimit
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: SizeLimit -> SizeLimit -> Bool
    == :: SizeLimit -> SizeLimit -> Bool
    $c/= :: SizeLimit -> SizeLimit -> Bool
    /= :: SizeLimit -> SizeLimit -> Bool
    Eq, Int -> SizeLimit -> ShowS
    [SizeLimit] -> ShowS
    SizeLimit -> String
    (Int -> SizeLimit -> ShowS)
    -> (SizeLimit -> String)
    -> ([SizeLimit] -> ShowS)
    -> Show SizeLimit
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> SizeLimit -> ShowS
    showsPrec :: Int -> SizeLimit -> ShowS
    $cshow :: SizeLimit -> String
    show :: SizeLimit -> String
    $cshowList :: [SizeLimit] -> ShowS
    showList :: [SizeLimit] -> ShowS
    Show)

    --------------------------------------------------------------------------------
    instance Monoid SizeLimit where
        mempty :: SizeLimit
    mempty = SizeLimit
    NoSizeLimit

    #if !MIN_VERSION_base(4,11,0)
        mappend NoSizeLimit   y             = y
        mappend x             NoSizeLimit   = x
        mappend (SizeLimit x) (SizeLimit y) = SizeLimit (min x y)
    #else
    instance Semigroup SizeLimit where
        <> :: SizeLimit -> SizeLimit -> SizeLimit
    (<>)    SizeLimit
    NoSizeLimit   SizeLimit
    y             = SizeLimit
    y
        (<>)    SizeLimit
    x             SizeLimit
    NoSizeLimit   = SizeLimit
    x
        (<>)    (SizeLimit Int64
    x) (SizeLimit Int64
    y) = Int64 -> SizeLimit
    SizeLimit (Int64 -> Int64 -> Int64
    forall a. Ord a => a -> a -> a
    min Int64
    x Int64
    y)
    #endif

    --------------------------------------------------------------------------------
    atMostSizeLimit :: Int64 -> SizeLimit -> Bool
    atMostSizeLimit :: Int64 -> SizeLimit -> Bool
    atMostSizeLimit Int64
    _ SizeLimit
    NoSizeLimit   = Bool
    True
    atMostSizeLimit Int64
    s (SizeLimit Int64
    l) = Int64
    s Int64 -> Int64 -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Int64
    l
    {-# INLINE atMostSizeLimit #-}