-----------------------------------------------------------------------------
-- |
-- Module providing various functions to dump information. These may be useful for 
-- debug/investigation but should probably not be used on production applications.
-----------------------------------------------------------------------------
module Kafka.Dump
( hPrintSupportedKafkaConf
, hPrintKafka
, dumpKafkaConf
, dumpTopicConf
)
where

import Kafka.Internal.RdKafka
  ( CSizePtr
  , rdKafkaConfDumpFree
  , peekCText
  , rdKafkaConfDump
  , rdKafkaTopicConfDump
  , rdKafkaDump
  , handleToCFile
  , rdKafkaConfPropertiesShow
  )
import Kafka.Internal.Setup
  ( HasKafka(..)
  , HasTopicConf(..)
  , HasKafkaConf(..)
  , getRdKafka
  , getRdTopicConf
  , getRdKafkaConf
  )

import           Control.Monad          ((<=<))
import           Control.Monad.IO.Class (MonadIO(liftIO))
import           Data.Map.Strict        (Map)
import qualified Data.Map.Strict        as Map
import           Foreign                (Ptr, alloca, Storable(peek, peekElemOff))
import           Foreign.C.String       (CString)
import           System.IO              (Handle)
import           Data.Text              (Text)

-- | Prints out all supported Kafka conf properties to a handle
hPrintSupportedKafkaConf :: MonadIO m => Handle -> m ()
hPrintSupportedKafkaConf :: Handle -> m ()
hPrintSupportedKafkaConf h :: Handle
h = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ Handle -> String -> IO CFilePtr
handleToCFile Handle
h "w" IO CFilePtr -> (CFilePtr -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CFilePtr -> IO ()
rdKafkaConfPropertiesShow

-- | Prints out all data associated with a specific kafka object to a handle
hPrintKafka :: (MonadIO m, HasKafka k) => Handle -> k -> m ()
hPrintKafka :: Handle -> k -> m ()
hPrintKafka h :: Handle
h k :: k
k = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ Handle -> String -> IO CFilePtr
handleToCFile Handle
h "w" IO CFilePtr -> (CFilePtr -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \f :: CFilePtr
f -> CFilePtr -> RdKafkaTPtr -> IO ()
rdKafkaDump CFilePtr
f (k -> RdKafkaTPtr
forall k. HasKafka k => k -> RdKafkaTPtr
getRdKafka k
k)

-- | Returns a map of the current topic configuration
dumpTopicConf :: (MonadIO m, HasTopicConf t) => t -> m (Map Text Text)
dumpTopicConf :: t -> m (Map Text Text)
dumpTopicConf t :: t
t = IO (Map Text Text) -> m (Map Text Text)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Map Text Text) -> m (Map Text Text))
-> IO (Map Text Text) -> m (Map Text Text)
forall a b. (a -> b) -> a -> b
$ (CSizePtr -> IO (Ptr CString)) -> IO (Map Text Text)
parseDump (RdKafkaTopicConfTPtr -> CSizePtr -> IO (Ptr CString)
rdKafkaTopicConfDump (t -> RdKafkaTopicConfTPtr
forall t. HasTopicConf t => t -> RdKafkaTopicConfTPtr
getRdTopicConf t
t))

-- | Returns a map of the current kafka configuration
dumpKafkaConf :: (MonadIO m, HasKafkaConf k) => k -> m (Map Text Text)
dumpKafkaConf :: k -> m (Map Text Text)
dumpKafkaConf k :: k
k = IO (Map Text Text) -> m (Map Text Text)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Map Text Text) -> m (Map Text Text))
-> IO (Map Text Text) -> m (Map Text Text)
forall a b. (a -> b) -> a -> b
$ (CSizePtr -> IO (Ptr CString)) -> IO (Map Text Text)
parseDump (RdKafkaConfTPtr -> CSizePtr -> IO (Ptr CString)
rdKafkaConfDump (k -> RdKafkaConfTPtr
forall k. HasKafkaConf k => k -> RdKafkaConfTPtr
getRdKafkaConf k
k))

parseDump :: (CSizePtr -> IO (Ptr CString)) -> IO (Map Text Text)
parseDump :: (CSizePtr -> IO (Ptr CString)) -> IO (Map Text Text)
parseDump cstr :: CSizePtr -> IO (Ptr CString)
cstr = (CSizePtr -> IO (Map Text Text)) -> IO (Map Text Text)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((CSizePtr -> IO (Map Text Text)) -> IO (Map Text Text))
-> (CSizePtr -> IO (Map Text Text)) -> IO (Map Text Text)
forall a b. (a -> b) -> a -> b
$ \sizeptr :: CSizePtr
sizeptr -> do
    Ptr CString
strPtr <- CSizePtr -> IO (Ptr CString)
cstr CSizePtr
sizeptr
    CSize
size <- CSizePtr -> IO CSize
forall a. Storable a => Ptr a -> IO a
peek CSizePtr
sizeptr

    [Text]
keysAndValues <- (Int -> IO Text) -> [Int] -> IO [Text]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (CString -> IO Text
peekCText (CString -> IO Text) -> (Int -> IO CString) -> Int -> IO Text
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< Ptr CString -> Int -> IO CString
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr CString
strPtr) [0..(CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
size Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1)]

    let ret :: Map Text Text
ret = [(Text, Text)] -> Map Text Text
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList ([(Text, Text)] -> Map Text Text)
-> [(Text, Text)] -> Map Text Text
forall a b. (a -> b) -> a -> b
$ [Text] -> [(Text, Text)]
listToTuple [Text]
keysAndValues
    Ptr CString -> CSize -> IO ()
rdKafkaConfDumpFree Ptr CString
strPtr CSize
size
    Map Text Text -> IO (Map Text Text)
forall (m :: * -> *) a. Monad m => a -> m a
return Map Text Text
ret

listToTuple :: [Text] -> [(Text, Text)]
listToTuple :: [Text] -> [(Text, Text)]
listToTuple []       = []
listToTuple (k :: Text
k:v :: Text
v:ts :: [Text]
ts) = (Text
k, Text
v) (Text, Text) -> [(Text, Text)] -> [(Text, Text)]
forall a. a -> [a] -> [a]
: [Text] -> [(Text, Text)]
listToTuple [Text]
ts
listToTuple _        = String -> [(Text, Text)]
forall a. HasCallStack => String -> a
error "list to tuple can only be called on even length lists"