packages feed

natskell-0.3.0.0: jetstream/JetStream/Consumer.hs

{-# LANGUAGE OverloadedStrings #-}

module JetStream.Consumer
  ( consumerAPI
  , module JetStream.Consumer.API
  ) where

import           Data.Aeson                 (Value, object, toJSON, (.=))
import           Data.Maybe                 (catMaybes)
import           JetStream.Consumer.API     (ConsumerAPI (..))
import           JetStream.Consumer.Types
    ( ConsumerAction (..)
    , ConsumerConfigOption
    , ConsumerConfigRequest
    , ConsumerKind
    , ConsumerTarget (..)
    , applyConsumerKind
    , applyConsumerTarget
    , consumerActionValue
    , consumerConfigRequest
    , consumerListRequest
    , consumerNamesRequest
    , consumerPauseRequest
    , consumerResetRequest
    )
import           JetStream.Error
    ( JetStreamError (JetStreamDecodeError)
    )
import           JetStream.Options          (JetStreamContext)
import qualified JetStream.Protocol.Request as Request
import qualified JetStream.Protocol.Subject as Subject
import           JetStream.Types
    ( StreamName
    , Subject
    , byteStringToJSON
    )

consumerAPI :: JetStreamContext -> ConsumerAPI
consumerAPI context =
  ConsumerAPI
    { putConsumer = \stream action target kind options ->
        case consumerRequest context stream action target kind options of
          Left err ->
            pure (Left err)
          Right (subject, actionValue, config) ->
            Request.requestJSON context
              subject
              (Just (createConsumerRequest stream actionValue config))
    , consumerInfo = \stream consumer ->
        Request.requestJSON context
          (Subject.consumerInfoSubject context stream consumer)
          Nothing
    , pauseConsumer = \stream consumer pauseUntil ->
        Request.requestJSON context
          (Subject.consumerPauseSubject context stream consumer)
          (Just (toJSON (consumerPauseRequest (Just pauseUntil))))
    , resumeConsumer = \stream consumer ->
        Request.requestJSON context
          (Subject.consumerPauseSubject context stream consumer)
          (Just (toJSON (consumerPauseRequest Nothing)))
    , resetConsumer = \stream consumer options ->
        Request.requestJSON context
          (Subject.consumerResetSubject context stream consumer)
          (Just (toJSON (consumerResetRequest options)))
    , deleteConsumer = \stream consumer ->
        Request.requestJSON context
          (Subject.consumerDeleteSubject context stream consumer)
          Nothing
    , listConsumers = \stream options ->
        Request.requestJSON context
          (Subject.consumerListSubject context stream)
          (Just (toJSON (consumerListRequest options)))
    , consumerNames = \stream options ->
        Request.requestJSON context
          (Subject.consumerNamesSubject context stream)
          (Just (toJSON (consumerNamesRequest options)))
    }

consumerRequest
  :: JetStreamContext
  -> StreamName
  -> ConsumerAction
  -> ConsumerTarget
  -> ConsumerKind
  -> [ConsumerConfigOption]
  -> Either JetStreamError (Subject, Maybe StreamName, ConsumerConfigRequest)
consumerRequest context stream action target kind options =
  case consumerSubject context stream action target of
    Left err ->
      Left err
    Right subject ->
      Right
        ( subject
        , actionValue
        , applyConsumerTarget target . applyConsumerKind kind $ consumerConfigRequest options
        )
  where
    actionValue =
      case target of
        EphemeralConsumer ->
          Nothing
        DurableConsumer _ | action == ConsumerCreate ->
          Nothing
        _ ->
          consumerActionValue action

consumerSubject
  :: JetStreamContext
  -> StreamName
  -> ConsumerAction
  -> ConsumerTarget
  -> Either JetStreamError Subject
consumerSubject context stream ConsumerCreate EphemeralConsumer =
  Right (Subject.consumerCreateSubject context stream)
consumerSubject context stream ConsumerCreate (DurableConsumer durable) =
  Right (Subject.durableConsumerCreateSubject context stream durable)
consumerSubject context stream _ (NamedConsumer consumer) =
  Right (Subject.consumerCreateNamedSubject context stream consumer)
consumerSubject context stream _ (DurableConsumer durable) =
  Right (Subject.consumerCreateNamedSubject context stream durable)
consumerSubject _ _ _ EphemeralConsumer =
  Left (JetStreamDecodeError "ephemeral consumers can only be created")

createConsumerRequest :: StreamName -> Maybe StreamName -> ConsumerConfigRequest -> Value
createConsumerRequest stream action config =
  object . catMaybes $
    [ Just ("stream_name" .= byteStringToJSON stream)
    , Just ("config" .= toJSON config)
    , fmap (("action" .=) . byteStringToJSON) action
    ]