2323
2424import asyncio
2525import functools
26- from typing import Any
26+ from typing import Any , Iterable , Optional
2727
2828import _pulsar
29+
2930import pulsar
3031
32+
3133class PulsarException (BaseException ):
3234 """
3335 The exception that wraps the Pulsar error code
@@ -56,6 +58,7 @@ def __str__(self):
5658 """
5759 return f'{ self ._result .value } { self ._result .name } '
5860
61+
5962class Producer :
6063 """
6164 The Pulsar message producer, used to publish messages on a topic.
@@ -116,6 +119,152 @@ async def close(self) -> None:
116119 self ._producer .close_async (functools .partial (_set_future , future , value = None ))
117120 await future
118121
122+ async def flush (self ):
123+ """
124+ Flush all the messages buffered in the client and wait until all messages have been successfully persisted.
125+
126+ Raises
127+ ------
128+ PulsarException
129+ """
130+ future = asyncio .get_running_loop ().create_future ()
131+ self ._producer .flush_async (functools .partial (_set_future , future , value = None ))
132+ await future
133+
134+ @property
135+ def is_connected (self ) -> bool :
136+ """
137+ Check if the producer is connected or not.
138+ """
139+
140+ return self ._producer .is_connected ()
141+
142+ @property
143+ def last_sequence_id (self ) -> int :
144+ """
145+ Get the last sequence id
146+ """
147+ return self ._producer .last_sequence_id ()
148+
149+ @property
150+ def name (self ) -> str :
151+ """
152+ Get the name of the producer.
153+ """
154+ return self ._producer .producer_name ()
155+
156+ @property
157+ def topic (self ) -> str :
158+ """
159+ Get the topic name of the producer.
160+ """
161+ return self ._producer .topic ()
162+
163+
164+ class Consumer :
165+ def __init__ (self , consumer : _pulsar .Consumer ) -> None :
166+ self ._consumer : _pulsar .Consumer = consumer
167+
168+ async def acknowledge (self , msg : pulsar .Message ) -> None :
169+ """
170+ Acknowledge the reception of a single message.
171+ """
172+ future = asyncio .get_running_loop ().create_future ()
173+ self ._consumer .acknowledge_async (msg , functools .partial (_set_future , future ))
174+ await future
175+
176+ async def acknowledge_cumulative (self , msg : pulsar .Message ) -> None :
177+ """
178+ Acknowledge the reception of all the messages in the stream up to (and including) the provided message.
179+ """
180+ future = asyncio .get_running_loop ().create_future ()
181+ self ._consumer .acknowledge_cumulative_async (msg , functools .partial (_set_future , future ))
182+ await future
183+
184+ async def negative_acknowledge (self , msg : pulsar .Message ) -> None :
185+ """
186+ Acknowledge the failure to process a single message.
187+ """
188+ future = asyncio .get_running_loop ().create_future ()
189+ self ._consumer .negative_acknowledge_async (msg , functools .partial (_set_future , future ))
190+ await future
191+
192+ async def batch_receive (self ) -> Iterable [pulsar .Message ]:
193+ """
194+ Batch receiving messages.
195+ """
196+ future = asyncio .get_running_loop ().create_future ()
197+ self ._consumer .batch_receive_async (functools .partial (_set_future , future ))
198+ return await future
199+
200+ async def receive (self ) -> pulsar .Message :
201+ """
202+ Receive a single message.
203+ """
204+ future = asyncio .get_running_loop ().create_future ()
205+
206+ self ._consumer .receive_async (functools .partial (_set_future , future ))
207+ return await future
208+
209+ async def close (self ):
210+ """
211+ Close the consumer.
212+ """
213+ future = asyncio .get_running_loop ().create_future ()
214+ self ._consumer .close_async (functools .partial (_set_future , future , value = None ))
215+ await future
216+
217+ async def seek (self , position : int ):
218+ """
219+ Reset the subscription associated with this consumer to a specific message id or publish timestamp. The message id can either be a specific message or represent the first or last messages in the topic. ...
220+ """
221+ future = asyncio .get_running_loop ().create_future ()
222+ self ._consumer .seek_async (position , functools .partial (_set_future , future ))
223+ await future
224+
225+ async def unsubscribe (self ):
226+ """
227+ Unsubscribe the current consumer from the topic.
228+ """
229+ future = asyncio .get_running_loop ().create_future ()
230+ self ._consumer .unsubscribe_async (functools .partial (_set_future , future ))
231+ await future
232+
233+ def pause_message_listener (self ):
234+ """
235+ Pause receiving messages via the message_listener until resume_message_listener() is called.
236+ """
237+ self ._consumer .pause_message_listener ()
238+
239+ def resume_message_listener (self ):
240+ """
241+ Resume receiving the messages via the message listener. Asynchronously receive all the messages enqueued from the time pause_message_listener() was called.
242+ """
243+ self ._consumer .resume_message_listener ()
244+
245+ def redeliver_unacknowledged_messages (self ):
246+ """
247+ Redelivers all the unacknowledged messages. In failover mode, the request is ignored if the consumer is not active for the given topic. In shared mode, the consumer's messages to be redelivered are distributed across all the connected consumers...
248+ """
249+ self ._consumer .redeliver_unacknowledged_messages ()
250+
251+ @property
252+ def last_message_id (self ) -> int :
253+ return self ._consumer .last_message_id
254+
255+ @property
256+ def is_connected (self ) -> bool :
257+ return self ._consumer .is_connected ()
258+
259+ @property
260+ def subscription_name (self ) -> str :
261+ return self ._consumer .subscription_name ()
262+
263+ @property
264+ def topic (self ) -> str :
265+ return self ._consumer .topic ()
266+
267+
119268class Client :
120269 """
121270 The asynchronous version of `pulsar.Client`.
@@ -125,7 +274,18 @@ def __init__(self, service_url, **kwargs) -> None:
125274 """
126275 See `pulsar.Client.__init__`
127276 """
128- self ._client : _pulsar .Client = pulsar .Client (service_url , ** kwargs )._client
277+ assert service_url .startswith ('pulsar://' ), "The service url must start with 'pulsar://'"
278+ self ._client = pulsar .Client (service_url , ** kwargs )._client
279+
280+ async def subscribe (self , topics : str , subscription_name : str , consumer_type : _pulsar .ConsumerType ,
281+ schema : Optional [_pulsar .SchemaInfo ] = _pulsar .SchemaInfo (_pulsar .SchemaType .BYTES , "bytes" , "" )) -> Consumer :
282+ conf = _pulsar .ConsumerConfiguration ()
283+ conf .consumer_type (consumer_type )
284+ conf .schema (schema )
285+
286+ future = asyncio .get_running_loop ().create_future ()
287+ self ._client .subscribe_async (topics , subscription_name , conf , functools .partial (_set_future , future ))
288+ return Consumer (await future )
129289
130290 async def create_producer (self , topic : str ) -> Producer :
131291 """
@@ -163,10 +323,20 @@ async def close(self) -> None:
163323 self ._client .close_async (functools .partial (_set_future , future , value = None ))
164324 await future
165325
326+ async def get_topic_partitions (self , topic : str ):
327+ future = asyncio .get_running_loop ().create_future ()
328+ self ._client .get_partitions_for_topic_async (topic , functools .partial (_set_future , future ))
329+ return await future
330+
331+ def shutdown (self ) -> None :
332+ self ._client .shutdown ()
333+
334+
166335def _set_future (future : asyncio .Future , result : _pulsar .Result , value : Any ):
167336 def complete ():
168337 if result == _pulsar .Result .Ok :
169338 future .set_result (value )
170339 else :
171340 future .set_exception (PulsarException (result ))
341+
172342 future .get_loop ().call_soon_threadsafe (complete )
0 commit comments