content: module Network.GRPC.Client (
      -- * Connecting to the server
      Connection -- opaque
    , Server(..)
    , ConnParams(..)
    , withConnection
    , openConnection
    , closeConnection
  
      -- ** Reconnection policy
    , ReconnectPolicy(..)
    , ReconnectDecision(..)
    , Reconnect(..)
    , OnConnection(..)
    , ReconnectTo(..)
    , exponentialBackoff
  
      -- ** Connection parameters
    , Scheme(..)
    , Address(..)
  
      -- ** Secure connection (TLS)
    , ServerValidation(..)
    , Util.TLS.CertificateStoreSpec
    , Util.TLS.certStoreFromSystem
    , Util.TLS.certStoreFromCerts
    , Util.TLS.certStoreFromPath
  
      -- * Make RPCs
    , Call -- opaque
    , withRPC
  
      -- ** Parameters
    , CallParams -- opaque
    , callTimeout
    , callRequestMetadata
  
      -- ** Timeouts
    , Timeout(..)
    , TimeoutValue(TimeoutValue, getTimeoutValue)
    , TimeoutUnit(..)
    , timeoutToMicro
  
      -- * Ongoing calls
      --
      -- $openRequest
    , sendInput
    , recvOutput
    , recvResponseMetadata
  
      -- ** Protocol specific wrappers
    , sendNextInput
    , sendFinalInput
    , sendEndOfInput
    , recvResponseInitialMetadata
    , recvNextOutput
    , recvFinalOutput
    , recvTrailers
  
      -- ** Low-level\/specialized API
    , ResponseHeaders_(..)
    , ResponseHeaders
    , ResponseHeaders'
    , ProperTrailers_(..)
    , ProperTrailers
    , ProperTrailers'
    , TrailersOnly_(..)
    , TrailersOnly
    , TrailersOnly'
    , recvNextOutputElem
    , recvInitialResponse
    , recvOutputWithMeta
    , sendInputWithMeta
  
      -- * Communication patterns
    , rpc
    , rpcWith
  
      -- * Exceptions
    , ServerDisconnected(..)
    , CallSetupFailure(..)
    , InvalidTrailers(..)
    ) where
  
  import Network.GRPC.Client.Call
  import Network.GRPC.Client.Connection
  import Network.GRPC.Client.Session (CallSetupFailure(..), InvalidTrailers(..))
  import Network.GRPC.Client.StreamType (rpc, rpcWith)
  import Network.GRPC.Spec
  import Network.GRPC.Util.HTTP2.Stream (ServerDisconnected(..))
  import Network.GRPC.Util.TLS qualified as Util.TLS
  
  {-------------------------------------------------------------------------------
    Ongoing calls
  -------------------------------------------------------------------------------}
  
  -- $openRequest
  --
  -- 'Call' denotes a previously opened request (see 'withRPC').
  --
  -- == Protobuf communication patterns
  --
  -- This is a general implementation of the
  -- [gRPC specification](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md).
  -- As such, these functions do not provide explicit support for the common
  -- communication patterns of non-streaming, server-side streaming, client-side
  -- streaming, or bidirectional streaming. These are not part of the gRPC
  -- standard, but are part of
  -- [its Protobuf instantiation](https://protobuf.dev/reference/protobuf/proto3-spec/#service_definition), although these
  -- patterns are of course not really Protobuf specific. We provide support for
  -- these communication patterns, independent from a choice of serialization
  -- format, in "Network.GRPC.Common.StreamType" and
  -- "Network.GRPC.Client.StreamType" (and "Network.GRPC.Server.StreamType" for the
  -- server side).
  --
  -- If you only use the abstractions provided in "Network.GRPC.*.StreamType",
  -- you can ignore the rest of the discussion below, which applies only to the
  -- more general interface.
  --
  -- == Stream elements
  --
  -- Both 'sendInput' and 'recvOutput' work with 'StreamElem':
  --
  -- > data StreamElem b a =
  -- >     StreamElem a
  -- >   | FinalElem a b
  -- >   | NoMoreElems b
  --
  -- The intuition is that we are sending messages of type @a@ (see \"Inputs and
  -- outputs\", below) and then when we send the final message, we can include
  -- some additional information of type @b@ (see \"Metadata\", below).
  --
  -- == Inputs and outputs
  --
  -- By convention, we refer to messages sent from the client to the server as
  -- \"inputs\" and messages sent from the server to the client as \"outputs\"
  -- (we inherited this terminology from
  -- [proto-lens](https://hackage.haskell.org/package/proto-lens-0.7.1.4/docs/Data-ProtoLens-Service-Types.html#t:HasMethodImpl).)
  -- On the client side we therefore have 'recvOutput' and 'sendInput' defined as
  --
  -- > recvOutput :: Call rpc -> m (StreamElem (ResponseTrailingMetadata rpc) (Output rpc))
  -- > sendInput  :: Call rpc -> StreamElem NoMetadata (Input rpc) -> m ()
  --
  -- and on the server side we have 'Network.GRPC.Server.recvInput' and
  -- 'Network.GRPC.Server.sendOutput':
  --
  -- > recvInput  :: Call rpc -> IO (StreamElem NoMetadata (Input rpc))
  -- > sendOutput :: Call rpc -> StreamElem (ResponseTrailingMetadata rpc) (Output rpc) -> IO ()
  --
  -- == Metadata
  --
  -- Both the server and the client can send some metadata before they send their
  -- first message; see 'withRPC' and 'callRequestMetadata' for the client-side
  -- (and 'Network.GRPC.Server.setResponseInitialMetadata' for the server-side).
  --
  -- The gRPC specification allows the server, but not the client, to include some
  -- /final/ metadata as well; this is the reason between the use of
  -- 'ResponseTrailingMetadata' for messages from the server to the client versus
  -- 'NoMetadata' for messages from the client.
  --
  -- == 'FinalElem' versus 'NoMoreElems'
  --
  -- 'Network.GRPC.Common.StreamElem' allows to mark the final message as final
  -- when it is /sent/ ('Network.GRPC.Common.FinalElem'), or retroactively
  -- indicate that the previous message was in fact final
  -- ('Network.GRPC.Common.NoMoreElems'). The reason for this is technical in
  -- nature.
  --
  -- Suppose we are doing a @grpc+proto@ non-streaming RPC call. The input message
  -- from the client to the server will be sent over one or more HTTP2 @DATA@
  -- frames (chunks of the input). The server will expect the last of those frames
  -- to be marked as @END_STREAM@. The HTTP2 specification /does/ allow sending an
  -- separate empty @DATA@ frame with the @END_STREAM@ flag set to indicate no
  -- further data is coming, but not all gRPC servers will wait for this, and
  -- might either think that the client is broken and disconnect, or might send
  -- the client a @RST_STREAM@ frame to force it to close the stream. To avoid
  -- problems, therefore, it is better to mark the final @DATA@ frame as
  -- @END_STREAM@; in order to be able to do that, 'sendInput' needs to know
  -- whether an input is the final one. It is therefore better to use 'FinalElem'
  -- instead of 'NoMoreElems' for outgoing messages, if possible.
  --
  -- For incoming messages the situation is different. Now we /do/ expect HTTP
  -- trailers (final metadata), which means that we cannot tell from @DATA@ frames
  -- alone if we have received the last message: it will be the frame containing
  -- the /trailers/ that is marked as @END_STREAM@, with no indication on the data
  -- frame just before it that it was the last one. We cannot wait for the next
  -- frame to come in, because that would be a blocking call (we might have to
  -- wait for the next TCP packet), and if the output was /not/ the last one, we
  -- would unnecessarily delay making the output we already received available to
  -- the client code. Typically therefore clients will receive a 'StreamElem'
  -- followed by 'NoMoreElems'.
  --
  -- Of course, for a given RPC and its associated communication pattern we may
  -- know whether any given message was the last; in the example above of a
  -- non-streaming @grpc+proto@ RPC call, we only expect a single output. In this
  -- case the client can (and should) call 'recvOutput' again to wait for the
  -- trailers (which, amongst other things, will include the 'trailerGrpcStatus').
  -- The specialized functions from "Network.GRPC.Client.StreamType" take care of
  -- this; if these functions are not applicable, users may wish to use
  -- 'recvFinalOutput'.
  