@@ -4,14 +4,21 @@ module X
44, deleteTopic
55) where
66
7+ import Control.Exception
78import Control.Monad.IO.Class
9+ import Control.Monad.Trans.Class
10+ import Control.Monad.Trans.Except
11+ import Control.Monad.Trans.Maybe
12+ import Data.Bifunctor
13+ import Data.Foldable
814import Data.List.NonEmpty
9- import qualified Data.List.NonEmpty as NEL
10- import Data.Text
11- import qualified Data.Text as T
12-
13- import Kafka.Internal.RdKafka
14- import Kafka.Internal.Setup
15+ import qualified Data.List.NonEmpty as NEL
16+ import qualified Data.Map as M
17+ import Data.Maybe
18+ import qualified Data.Set as S
19+ import qualified Data.Text as T
20+ import Kafka.Internal.RdKafka
21+ import Kafka.Internal.Setup
1522
1623import Kafka.Topic.Types as X
1724import Kafka.Types as X
@@ -24,11 +31,17 @@ createTopic k topic = do
2431 opts <- newRdKAdminOptions kafkaPtr RdKafkaAdminOpAny
2532
2633 topicRes <- withNewTopic topic $ \ topic' -> rdKafkaCreateTopic kafkaPtr topic' opts queue
34+
2735 case topicRes of
2836 Left err -> do
2937 pure $ Left (NEL. head err)
3038 Right _ -> do
31- pure $ Right $ topicName topic
39+ res <- waitForResponse (topicName topic) rdKafkaEventCreateTopicsResult rdKafkaCreateTopicsResultTopics queue
40+ case listToMaybe res of
41+ Nothing -> pure $ Left KafkaInvalidReturnValue
42+ Just result -> pure $ case result of
43+ Left (_, e, _) -> Left e
44+ Right tName -> Right tName
3245
3346--- DELETE TOPIC ---
3447deleteTopic :: HasKafka k
@@ -45,19 +58,17 @@ deleteTopic k topic = liftIO $ do
4558 Left err -> do
4659 pure $ Left (NEL. head err)
4760 Right _ -> do
48- pure $ Right topic
61+ res <- waitForResponse topic rdKafkaEventDeleteTopicsResult rdKafkaDeleteTopicsResultTopics queue
62+ case listToMaybe res of
63+ Nothing -> pure $ Left KafkaInvalidReturnValue
64+ Just result -> pure $ case result of
65+ Left (_, e, _) -> Left e
66+ Right tName -> Right tName
4967
5068withNewTopic :: NewTopic
5169 -> (RdKafkaNewTopicTPtr -> IO a )
5270 -> IO (Either (NonEmpty KafkaError ) a )
53- withNewTopic t transform = do
54- mkNewTopicRes <- mkNewTopic t newTopicPtr
55- case mkNewTopicRes of
56- Left err -> do
57- return $ Left err
58- Right topic -> do
59- res <- transform topic
60- return $ Right res
71+ withNewTopic t = withUnsafeOne t mkNewTopicUnsafe rdKafkaNewTopicDestroy
6172
6273withOldTopic :: TopicName
6374 -> (RdKafkaDeleteTopicTPtr -> IO a )
@@ -71,28 +82,21 @@ withOldTopic tName transform = do
7182 res <- transform topic
7283 return $ Right res
7384
74- newTopicPtr :: NewTopic -> IO (Either KafkaError RdKafkaNewTopicTPtr )
75- newTopicPtr topic = do
76- ptrRes <- newRdKafkaNewTopic (unpack $ unTopicName $ topicName topic) (unPartitionCount $ topicPartitionCount topic) (unReplicationFactor $ topicReplicationFactor topic)
77- case ptrRes of
78- Left str -> pure $ Left (KafkaError $ T. pack str)
79- Right ptr -> pure $ Right ptr
80-
8185oldTopicPtr :: TopicName -> IO (Either KafkaError RdKafkaDeleteTopicTPtr )
8286oldTopicPtr tName = do
83- res <- newRdKafkaDeleteTopic $ unpack . unTopicName $ tName
87+ res <- newRdKafkaDeleteTopic $ T. unpack . unTopicName $ tName
8488 case res of
8589 Left str -> pure $ Left (KafkaError $ T. pack str)
8690 Right ptr -> pure $ Right ptr
8791
88- mkNewTopic :: NewTopic
89- -> ( NewTopic -> IO ( Either KafkaError a ))
90- -> IO ( Either ( NonEmpty KafkaError ) a )
91- mkNewTopic topic create = do
92- res <- create topic
93- case res of
94- Left err -> pure $ Left (singletonList err)
95- Right resource -> pure $ Right resource
92+ mkNewTopicUnsafe :: NewTopic -> IO ( Either KafkaError RdKafkaNewTopicTPtr )
93+ mkNewTopicUnsafe topic = runExceptT $ do
94+ topic' <- withErrStr $ newRdKafkaNewTopicUnsafe ( T. unpack $ unTopicName $ topicName topic) (unPartitionCount $ topicPartitionCount topic) (unReplicationFactor $ topicReplicationFactor topic )
95+ _ <- withErrKafka $ whileRight ( uncurry $ rdKafkaNewTopicSetConfig undefined ) ( M. toList $ topicConfig topic)
96+ pure topic'
97+ where
98+ withErrStr = withExceptT ( KafkaError . T. pack) . ExceptT
99+ withErrKafka = withExceptT KafkaResponseError . ExceptT
96100
97101rmOldTopic :: TopicName
98102 -> (TopicName -> IO (Either KafkaError a ))
@@ -103,5 +107,52 @@ rmOldTopic tName remove = do
103107 Left err -> pure $ Left (singletonList err)
104108 Right resource -> pure $ Right resource
105109
110+ withUnsafeOne :: a -- ^ Item to handle
111+ -> (a -> IO (Either KafkaError b )) -- ^ Create an unsafe element
112+ -> (b -> IO () ) -- ^ Destroy the unsafe element
113+ -> (b -> IO c ) -- ^ Handler
114+ -> IO (Either (NonEmpty KafkaError ) c )
115+ withUnsafeOne a mkOne cleanup f =
116+ bracket (mkOne a) cleanupOne processOne
117+ where
118+ cleanupOne (Right b) = cleanup b
119+ cleanupOne (Left _) = pure () -- no resource to clean if creation failed
120+
121+ processOne (Right b) = Right <$> f b
122+ processOne (Left e) = pure (Left (singletonList e))
123+
124+ whileRight :: Monad m
125+ => (a -> m (Either e () ))
126+ -> [a ]
127+ -> m (Either e () )
128+ whileRight f as = runExceptT $ traverse_ (ExceptT . f) as
129+
130+ waitForResponse :: TopicName
131+ -> (RdKafkaEventTPtr -> IO (Maybe a ))
132+ -> (a -> IO [Either (String , RdKafkaRespErrT , String ) String ])
133+ -> RdKafkaQueueTPtr
134+ -> IO [Either (TopicName , KafkaError , String ) TopicName ]
135+ waitForResponse topic fromEvent toResults q =
136+ fromMaybe [] <$> runMaybeT (go [] )
137+ where
138+ awaited = S. singleton topic
139+
140+ go accRes = do
141+ qRes <- MaybeT $ rdKafkaQueuePoll q 1000
142+ eRes <- MaybeT $ fromEvent qRes
143+ tRes <- lift $ toResults eRes
144+ let results = wrapTopicName <$> tRes
145+ let topics = S. fromList $ getTopicName <$> results
146+ let newRes = results <> accRes
147+ let remaining = S. difference awaited topics
148+ if S. null remaining
149+ then pure newRes
150+ else go newRes
151+
152+ getTopicName = either (\ (t,_,_) -> t) id
153+ wrapTopicName = bimap (\ (t,e,s) -> (TopicName (T. pack t), KafkaResponseError e, s))
154+ (TopicName . T. pack)
155+
106156singletonList :: a -> NonEmpty a
107157singletonList x = x :| []
158+
0 commit comments