packages feed

natskell-1.0.0.1: 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 (..)
  , Subject
  , Payload
  , Headers
  , PublishOption
  , SubscribeOption
  , RequestOption
  , UnsubscribeOption
  , PingOption
  , FlushOption
  , ResetOption
  , CloseOption
  , RequestConfig (..)
  , UnsubscribeConfig (..)
  , PingConfig (..)
  , FlushConfig (..)
  , ResetConfig (..)
  , CloseConfig (..)
  , withSubscriptionExpiry
  , withQueueGroup
  , withReplyTo
  , withHeaders
  , withRequestTimeout
  , withRequestHeaders
  ) where

import qualified Data.ByteString    as BS
import           Data.Time.Clock    (NominalDiffTime)
import           Lib.CallOption     (CallOption)
import           Publish.Config     (PublishConfig (..))
import           State.Types        (ClientExitReason)
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.
                , 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

data PingConfig = PingConfig
type PingOption = CallOption PingConfig

data FlushConfig = FlushConfig
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 }