packages feed

natskell-1.1.0.0: internal/Client/API.hs

-- | Internal home for the core NATS client capability surface.
--
-- The public @API@ module deliberately hides the constructors defined here.
-- Keeping construction private lets the capability grow without changing the
-- public representation.
module Client.API
  ( Client (..)
  , Message (..)
  , MsgView
  , Subscription (..)
  , subscriptionSid
  , NatsError (..)
  , ConnectionState (..)
  , Subject
  , Payload
  , Headers
  , PublishOption
  , SubscribeOption
  , RequestOption
  , UnsubscribeOption
  , PingOption
  , FlushOption
  , ResetOption
  , CloseOption
  , RequestConfig (..)
  , UnsubscribeConfig (..)
  , PingConfig (..)
  , FlushConfig (..)
  , ResetConfig (..)
  , CloseConfig (..)
  , withSubscriptionExpiry
  , withQueueGroup
  , withReplyTo
  , withHeaders
  , withRequestTimeout
  , withRequestHeaders
  , withPingTimeout
  , withFlushTimeout
  ) where

import qualified Data.ByteString    as BS
import           Data.Time.Clock    (NominalDiffTime)
import           Lib.CallOption     (CallOption)
import           Publish.Config     (PublishConfig (..))
import           State.Types        (ClientExitReason, ConnectionState (..))
import           Subscription.Types (SubscribeConfig (..))
import           Types.Msg          (Headers, Payload, SID, Subject)

-- | Client capabilities for publishing, subscribing, request-reply, and
-- lifecycle control.
--
-- This constructor is internal. Public callers receive a 'Client' from
-- 'Client.newClient' and use the named operations re-exported by @API@.
data Client = Client
                { publish :: Subject -> Payload -> [PublishOption] -> IO (Either NatsError ())
                  -- ^ Publish a message.
                , subscribe :: Subject -> [SubscribeOption] -> (Message -> IO ()) -> IO (Either NatsError Subscription)
                  -- ^ Subscribe to a subject until explicitly unsubscribed.
                , subscribeOnce :: Subject -> [SubscribeOption] -> (Message -> IO ()) -> IO (Either NatsError Subscription)
                  -- ^ Subscribe until the first message is delivered.
                , request :: Subject -> Payload -> [RequestOption] -> IO (Either NatsError Message)
                  -- ^ Publish a request and wait for one response.
                , unsubscribe :: Subscription -> [UnsubscribeOption] -> IO (Either NatsError ())
                  -- ^ Unsubscribe a subscription created by this client.
                , newInbox :: IO Subject
                  -- ^ Create a unique inbox subject for replies.
                , ping :: [PingOption] -> IO (Either NatsError ())
                  -- ^ Round trip a PING through the server.
                , flush :: [FlushOption] -> IO (Either NatsError ())
                  -- ^ Wait until all previously buffered writes reach the server.
                , connectionState :: IO ConnectionState
                  -- ^ Read the client's current connection lifecycle state.
                , reset :: [ResetOption] -> IO ()
                  -- ^ Reset the client connection state.
                , close :: [CloseOption] -> IO ()
                -- ^ Close the client connection and release resources.
                }

-- | A message delivered by NATS.
--
-- NATS always has a payload, which may be empty. This is intentionally
-- represented by a strict 'BS.ByteString', not @Maybe ByteString@.
data Message = Message
                 { subject :: Subject
                 , sid     :: SID
                 , replyTo :: Maybe Subject
                 , payload :: Payload
                 , headers :: Maybe Headers
                 }
  deriving (Eq, Show)

-- | Compatibility name retained for code written against pre-0.4 releases.
type MsgView = Message

-- | An opaque handle to an active subscription.
newtype Subscription = Subscription SID
  deriving (Eq, Show)

-- | The protocol identifier used by the legacy @API@ module. New code should
-- treat 'Subscription' as an opaque handle.
subscriptionSid :: Subscription -> SID
subscriptionSid (Subscription value) = value

-- | Failures reported by core NATS operations.
data NatsError = NatsValidationError BS.ByteString
               | NatsPayloadTooLarge Int Int
               | NatsSlowConsumer
               | NatsConnectionClosed ClientExitReason
               | NatsRequestTimedOut
               | NatsNoResponders
  deriving (Eq, Show)

type PublishOption = CallOption PublishConfig

type SubscribeOption = CallOption SubscribeConfig

data RequestConfig = RequestConfig
                       { requestTimeout :: NominalDiffTime
                       , requestHeaders :: Maybe Headers
                       }

type RequestOption = CallOption RequestConfig

data UnsubscribeConfig = UnsubscribeConfig
type UnsubscribeOption = CallOption UnsubscribeConfig

-- Internal configuration constructors are not covered by public API stability.
data PingConfig = PingConfig
                | PingConfigTimeout NominalDiffTime
type PingOption = CallOption PingConfig

data FlushConfig = FlushConfig
                 | FlushConfigTimeout NominalDiffTime
type FlushOption = CallOption FlushConfig

data ResetConfig = ResetConfig
type ResetOption = CallOption ResetConfig

data CloseConfig = CloseConfig
type CloseOption = CallOption CloseConfig

-- | Stop a one-shot subscription if it has not received a message within the
-- given interval.
withSubscriptionExpiry :: NominalDiffTime -> SubscribeOption
withSubscriptionExpiry expirySeconds cfg = cfg { expiry = Just expirySeconds }

-- | Deliver messages to one member of the named queue group.
withQueueGroup :: Subject -> SubscribeOption
withQueueGroup queueGroup cfg = cfg { subscribeQueueGroup = Just queueGroup }

-- | Set the reply subject on an outgoing publish.
withReplyTo :: Subject -> PublishOption
withReplyTo replySubject cfg = cfg { publishReplyTo = Just replySubject }

-- | Set headers on an outgoing publish.
withHeaders :: Headers -> PublishOption
withHeaders messageHeaders cfg = cfg { publishHeaders = Just messageHeaders }

-- | Set the amount of time to wait for a request reply.
withRequestTimeout :: NominalDiffTime -> RequestOption
withRequestTimeout timeout cfg = cfg { requestTimeout = max 0 timeout }

-- | Set headers on an outgoing request.
withRequestHeaders :: Headers -> RequestOption
withRequestHeaders messageHeaders cfg = cfg { requestHeaders = Just messageHeaders }

-- | Set the maximum time to wait for a ping response.
withPingTimeout :: NominalDiffTime -> PingOption
withPingTimeout timeout _ = PingConfigTimeout (max 0 timeout)

-- | Set the maximum time to wait for a flush response.
withFlushTimeout :: NominalDiffTime -> FlushOption
withFlushTimeout timeout _ = FlushConfigTimeout (max 0 timeout)