packages feed

pgmq-inspect-0.7.0.0: src/Pgmq/Inspect/Frames.hs

-- | Internal protocol representation. Public constructors are re-exported by WebSocket.
module Pgmq.Inspect.Frames (ClientFrame (..), ServerFrame (..), UpdateSource (..)) where

import Data.Aeson
import Data.Aeson.Types (Parser)
import Data.Text (Text)
import Pgmq.Hasql.Statements.Types (QueueMetrics)

data ClientFrame = Subscribe !Text | Unsubscribe !Text | Ping
  deriving stock (Eq, Show)

data UpdateSource = NotifySource | PollSource
  deriving stock (Eq, Show)

data ServerFrame
  = Snapshot !Text !QueueMetrics !Bool
  | Update !Text !QueueMetrics !UpdateSource
  | Pong
  | ErrorFrame !Text !Text !(Maybe Text)
  | Goodbye
  deriving stock (Show)

instance FromJSON ClientFrame where
  parseJSON = withObject "ClientFrame" $ \o -> do
    tag <- o .: "type" :: Parser Text
    case tag of
      "subscribe" -> Subscribe <$> o .: "queue"
      "unsubscribe" -> Unsubscribe <$> o .: "queue"
      "ping" -> pure Ping
      _ -> fail "unknown frame type"

instance ToJSON ClientFrame where
  toJSON = object . clientFields
  toEncoding = pairs . mconcat . clientFields

clientFields :: (KeyValue e kv) => ClientFrame -> [kv]
clientFields (Subscribe q) = ["type" .= ("subscribe" :: Text), "queue" .= q]
clientFields (Unsubscribe q) = ["type" .= ("unsubscribe" :: Text), "queue" .= q]
clientFields Ping = ["type" .= ("ping" :: Text)]

instance ToJSON UpdateSource where
  toJSON = toJSON . sourceText
  toEncoding = toEncoding . sourceText

sourceText :: UpdateSource -> Text
sourceText NotifySource = "notify"
sourceText PollSource = "poll"

instance ToJSON ServerFrame where
  toJSON = object . serverFields
  toEncoding = pairs . mconcat . serverFields

serverFields :: (KeyValue e kv) => ServerFrame -> [kv]
serverFields (Snapshot q metrics push) = ["type" .= ("snapshot" :: Text), "queue" .= q, "metrics" .= metrics, "push" .= push]
serverFields (Update q metrics source) = ["type" .= ("update" :: Text), "queue" .= q, "metrics" .= metrics, "source" .= source]
serverFields Pong = ["type" .= ("pong" :: Text)]
serverFields (ErrorFrame code message queue) = ["type" .= ("error" :: Text), "code" .= code, "message" .= message, "queue" .= queue]
serverFields Goodbye = ["type" .= ("goodbye" :: Text)]