module Hasura.GraphQL.Transport.WebSocket.Types
  ( ErrRespType (ERTGraphqlCompliant, ERTLegacy),
    WSConn,
    WSConnData (WSConnData, _wscOpMap, _wscUser),
    WSConnState (CSInitError, CSInitialised, CSNotInitialised),
    WSServerEnv (WSServerEnv, _wseCorsPolicy, _wseHManager, _wseKeepAliveDelay, _wseSubscriptionState, _wseLogger, _wseServer, _wseServerMetrics, _wsePrometheusMetrics),
    WsClientState (WsClientState, wscsIpAddress, wscsReqHeaders, wscsTokenExpTime, wscsUserInfo),
    WsHeaders (WsHeaders, unWsHeaders),
    SubscriberType (..),
  )
where

import Control.Concurrent.STM qualified as STM
import Data.Time.Clock qualified as TC
import Hasura.GraphQL.Execute qualified as E
import Hasura.GraphQL.Execute.Subscription.State qualified as ES
import Hasura.GraphQL.Transport.HTTP.Protocol
import Hasura.GraphQL.Transport.Instances ()
import Hasura.GraphQL.Transport.WebSocket.Protocol
import Hasura.GraphQL.Transport.WebSocket.Server qualified as WS
import Hasura.Logging qualified as L
import Hasura.Prelude
import Hasura.RQL.Types.Common
import Hasura.RQL.Types.SchemaCache
import Hasura.Server.Cors
import Hasura.Server.Init.Config (KeepAliveDelay (..))
import Hasura.Server.Metrics (ServerMetrics (..))
import Hasura.Server.Prometheus (PrometheusMetrics (..))
import Hasura.Server.Types (ReadOnlyMode (..))
import Hasura.Session
import Network.HTTP.Client qualified as HTTP
import Network.HTTP.Types qualified as HTTP
import Network.Wai.Extended qualified as Wai
import StmContainers.Map qualified as STMMap

newtype WsHeaders = WsHeaders {WsHeaders -> [Header]
unWsHeaders :: [HTTP.Header]}
  deriving (Int -> WsHeaders -> ShowS
[WsHeaders] -> ShowS
WsHeaders -> String
(Int -> WsHeaders -> ShowS)
-> (WsHeaders -> String)
-> ([WsHeaders] -> ShowS)
-> Show WsHeaders
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [WsHeaders] -> ShowS
$cshowList :: [WsHeaders] -> ShowS
show :: WsHeaders -> String
$cshow :: WsHeaders -> String
showsPrec :: Int -> WsHeaders -> ShowS
$cshowsPrec :: Int -> WsHeaders -> ShowS
Show, WsHeaders -> WsHeaders -> Bool
(WsHeaders -> WsHeaders -> Bool)
-> (WsHeaders -> WsHeaders -> Bool) -> Eq WsHeaders
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: WsHeaders -> WsHeaders -> Bool
$c/= :: WsHeaders -> WsHeaders -> Bool
== :: WsHeaders -> WsHeaders -> Bool
$c== :: WsHeaders -> WsHeaders -> Bool
Eq)

data ErrRespType
  = ERTLegacy
  | ERTGraphqlCompliant
  deriving (Int -> ErrRespType -> ShowS
[ErrRespType] -> ShowS
ErrRespType -> String
(Int -> ErrRespType -> ShowS)
-> (ErrRespType -> String)
-> ([ErrRespType] -> ShowS)
-> Show ErrRespType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ErrRespType] -> ShowS
$cshowList :: [ErrRespType] -> ShowS
show :: ErrRespType -> String
$cshow :: ErrRespType -> String
showsPrec :: Int -> ErrRespType -> ShowS
$cshowsPrec :: Int -> ErrRespType -> ShowS
Show)

data WSConnState
  = -- | headers and IP address from the client for websockets
    CSNotInitialised !WsHeaders !Wai.IpAddress
  | CSInitError !Text
  | CSInitialised !WsClientState
  deriving (Int -> WSConnState -> ShowS
[WSConnState] -> ShowS
WSConnState -> String
(Int -> WSConnState -> ShowS)
-> (WSConnState -> String)
-> ([WSConnState] -> ShowS)
-> Show WSConnState
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [WSConnState] -> ShowS
$cshowList :: [WSConnState] -> ShowS
show :: WSConnState -> String
$cshow :: WSConnState -> String
showsPrec :: Int -> WSConnState -> ShowS
$cshowsPrec :: Int -> WSConnState -> ShowS
Show)

data WsClientState = WsClientState
  { -- | the 'UserInfo' required to execute the GraphQL query
    WsClientState -> UserInfo
wscsUserInfo :: !UserInfo,
    -- | the JWT/token expiry time, if any
    WsClientState -> Maybe UTCTime
wscsTokenExpTime :: !(Maybe TC.UTCTime),
    -- | headers from the client (in conn params) to forward to the remote schema
    WsClientState -> [Header]
wscsReqHeaders :: ![HTTP.Header],
    -- | IP address required for 'MonadGQLAuthorization'
    WsClientState -> IpAddress
wscsIpAddress :: !Wai.IpAddress
  }
  deriving (Int -> WsClientState -> ShowS
[WsClientState] -> ShowS
WsClientState -> String
(Int -> WsClientState -> ShowS)
-> (WsClientState -> String)
-> ([WsClientState] -> ShowS)
-> Show WsClientState
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [WsClientState] -> ShowS
$cshowList :: [WsClientState] -> ShowS
show :: WsClientState -> String
$cshow :: WsClientState -> String
showsPrec :: Int -> WsClientState -> ShowS
$cshowsPrec :: Int -> WsClientState -> ShowS
Show)

data WSConnData = WSConnData
  -- the role and headers are set only on connection_init message
  { WSConnData -> TVar WSConnState
_wscUser :: !(STM.TVar WSConnState),
    -- we only care about subscriptions,
    -- the other operations (query/mutations)
    -- are not tracked here
    WSConnData -> OperationMap
_wscOpMap :: !OperationMap,
    WSConnData -> ErrRespType
_wscErrRespTy :: !ErrRespType,
    WSConnData -> GraphQLQueryType
_wscAPIType :: !E.GraphQLQueryType
  }

data WSServerEnv = WSServerEnv
  { WSServerEnv -> Logger Hasura
_wseLogger :: !(L.Logger L.Hasura),
    WSServerEnv -> SubscriptionsState
_wseSubscriptionState :: !ES.SubscriptionsState,
    -- | an action that always returns the latest version of the schema cache. See 'SchemaCacheRef'.
    WSServerEnv -> IO (SchemaCache, SchemaCacheVer)
_wseGCtxMap :: !(IO (SchemaCache, SchemaCacheVer)),
    WSServerEnv -> Manager
_wseHManager :: !HTTP.Manager,
    WSServerEnv -> CorsPolicy
_wseCorsPolicy :: !CorsPolicy,
    WSServerEnv -> SQLGenCtx
_wseSQLCtx :: !SQLGenCtx,
    WSServerEnv -> ReadOnlyMode
_wseReadOnlyMode :: ReadOnlyMode,
    WSServerEnv -> WSServer
_wseServer :: !WSServer,
    WSServerEnv -> Bool
_wseEnableAllowlist :: !Bool,
    WSServerEnv -> KeepAliveDelay
_wseKeepAliveDelay :: !KeepAliveDelay,
    WSServerEnv -> ServerMetrics
_wseServerMetrics :: !ServerMetrics,
    WSServerEnv -> PrometheusMetrics
_wsePrometheusMetrics :: !PrometheusMetrics
  }

data SubscriberType
  = LiveQuerySubscriber !ES.LiveQuerySubscriberDetails
  | StreamingQuerySubscriber !ES.StreamingSubscriberDetails

type OperationMap =
  STMMap.Map OperationId (SubscriberType, Maybe OperationName)

type WSServer = WS.WSServer WSConnData

type WSConn = WS.WSConn WSConnData