pulsar-client 1.6.2-rc.1 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/Consumer.cc CHANGED
@@ -21,6 +21,7 @@
21
21
  #include "ConsumerConfig.h"
22
22
  #include "Message.h"
23
23
  #include "MessageId.h"
24
+ #include "ThreadSafeDeferred.h"
24
25
  #include <pulsar/c/result.h>
25
26
  #include <atomic>
26
27
  #include <thread>
@@ -50,10 +51,10 @@ void Consumer::Init(Napi::Env env, Napi::Object exports) {
50
51
  }
51
52
 
52
53
  struct MessageListenerProxyData {
53
- pulsar_message_t *cMessage;
54
+ std::shared_ptr<pulsar_message_t> cMessage;
54
55
  Consumer *consumer;
55
56
 
56
- MessageListenerProxyData(pulsar_message_t *cMessage, Consumer *consumer)
57
+ MessageListenerProxyData(std::shared_ptr<pulsar_message_t> cMessage, Consumer *consumer)
57
58
  : cMessage(cMessage), consumer(consumer) {}
58
59
  };
59
60
 
@@ -62,11 +63,16 @@ void MessageListenerProxy(Napi::Env env, Napi::Function jsCallback, MessageListe
62
63
  Consumer *consumer = data->consumer;
63
64
  delete data;
64
65
 
65
- jsCallback.Call({msg, consumer->Value()});
66
+ // `consumer` might be null in certain cases, segmentation fault might happend without this null check. We
67
+ // need to handle this rare case in future.
68
+ if (consumer) {
69
+ jsCallback.Call({msg, consumer->Value()});
70
+ }
66
71
  }
67
72
 
68
- void MessageListener(pulsar_consumer_t *cConsumer, pulsar_message_t *cMessage, void *ctx) {
69
- ListenerCallback *listenerCallback = (ListenerCallback *)ctx;
73
+ void MessageListener(pulsar_consumer_t *rawConsumer, pulsar_message_t *rawMessage, void *ctx) {
74
+ std::shared_ptr<pulsar_message_t> cMessage(rawMessage, pulsar_message_free);
75
+ MessageListenerCallback *listenerCallback = (MessageListenerCallback *)ctx;
70
76
 
71
77
  Consumer *consumer = (Consumer *)listenerCallback->consumer;
72
78
 
@@ -79,144 +85,131 @@ void MessageListener(pulsar_consumer_t *cConsumer, pulsar_message_t *cMessage, v
79
85
  listenerCallback->callback.Release();
80
86
  }
81
87
 
82
- void Consumer::SetCConsumer(std::shared_ptr<CConsumerWrapper> cConsumer) { this->wrapper = cConsumer; }
83
- void Consumer::SetListenerCallback(ListenerCallback *listener) {
84
- if (listener) {
85
- // Maintain reference to consumer, so it won't get garbage collected
86
- // since, when we have a listener, we don't have to maintain reference to consumer (in js code)
87
- this->Ref();
88
+ void Consumer::SetCConsumer(std::shared_ptr<pulsar_consumer_t> cConsumer) { this->cConsumer = cConsumer; }
89
+ void Consumer::SetListenerCallback(MessageListenerCallback *listener) {
90
+ if (this->listener != nullptr) {
91
+ // It is only safe to set the listener once for the lifecycle of the Consumer
92
+ return;
93
+ }
88
94
 
89
- // Pass consumer as argument
95
+ if (listener != nullptr) {
90
96
  listener->consumer = this;
97
+ // If a consumer listener is set, the Consumer instance is kept alive even if it goes out of scope in JS
98
+ // code.
99
+ this->Ref();
100
+ this->listener = listener;
91
101
  }
92
-
93
- this->listener = listener;
94
102
  }
95
103
 
96
104
  Consumer::Consumer(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Consumer>(info), listener(nullptr) {}
97
105
 
98
- class ConsumerNewInstanceWorker : public Napi::AsyncWorker {
99
- public:
100
- ConsumerNewInstanceWorker(const Napi::Promise::Deferred &deferred, pulsar_client_t *cClient,
101
- ConsumerConfig *consumerConfig, std::shared_ptr<CConsumerWrapper> consumerWrapper)
102
- : AsyncWorker(Napi::Function::New(deferred.Promise().Env(), [](const Napi::CallbackInfo &info) {})),
103
- deferred(deferred),
104
- cClient(cClient),
105
- consumerConfig(consumerConfig),
106
- consumerWrapper(consumerWrapper) {}
107
- ~ConsumerNewInstanceWorker() {}
108
- void Execute() {
109
- const std::string &topic = this->consumerConfig->GetTopic();
110
- const std::vector<std::string> &topics = this->consumerConfig->GetTopics();
111
- const std::string &topicsPattern = this->consumerConfig->GetTopicsPattern();
112
- if (topic.empty() && topics.size() == 0 && topicsPattern.empty()) {
113
- SetError(
114
- std::string("Topic, topics or topicsPattern is required and must be specified as a string when "
115
- "creating consumer"));
116
- return;
117
- }
118
- const std::string &subscription = this->consumerConfig->GetSubscription();
119
- if (subscription.empty()) {
120
- SetError(
121
- std::string("Subscription is required and must be specified as a string when creating consumer"));
122
- return;
123
- }
124
- int32_t ackTimeoutMs = this->consumerConfig->GetAckTimeoutMs();
125
- if (ackTimeoutMs != 0 && ackTimeoutMs < MIN_ACK_TIMEOUT_MILLIS) {
126
- std::string msg("Ack timeout should be 0 or greater than or equal to " +
127
- std::to_string(MIN_ACK_TIMEOUT_MILLIS));
128
- SetError(msg);
129
- return;
130
- }
131
- int32_t nAckRedeliverTimeoutMs = this->consumerConfig->GetNAckRedeliverTimeoutMs();
132
- if (nAckRedeliverTimeoutMs < 0) {
133
- std::string msg("NAck timeout should be greater than or equal to zero");
134
- SetError(msg);
135
- return;
136
- }
106
+ struct ConsumerNewInstanceContext {
107
+ ConsumerNewInstanceContext(std::shared_ptr<ThreadSafeDeferred> deferred,
108
+ std::shared_ptr<pulsar_client_t> cClient,
109
+ std::shared_ptr<ConsumerConfig> consumerConfig)
110
+ : deferred(deferred), cClient(cClient), consumerConfig(consumerConfig){};
111
+ std::shared_ptr<ThreadSafeDeferred> deferred;
112
+ std::shared_ptr<pulsar_client_t> cClient;
113
+ std::shared_ptr<ConsumerConfig> consumerConfig;
114
+
115
+ static void subscribeCallback(pulsar_result result, pulsar_consumer_t *rawConsumer, void *ctx) {
116
+ auto instanceContext = static_cast<ConsumerNewInstanceContext *>(ctx);
117
+ auto deferred = instanceContext->deferred;
118
+ auto cClient = instanceContext->cClient;
119
+ auto consumerConfig = instanceContext->consumerConfig;
120
+ delete instanceContext;
137
121
 
138
- this->done = false;
139
- if (!topicsPattern.empty()) {
140
- pulsar_client_subscribe_pattern_async(this->cClient, topicsPattern.c_str(), subscription.c_str(),
141
- this->consumerConfig->GetCConsumerConfig(),
142
- &ConsumerNewInstanceWorker::subscribeCallback, (void *)this);
143
- } else if (topics.size() > 0) {
144
- const char **cTopics = new const char *[topics.size()];
145
- for (size_t i = 0; i < topics.size(); i++) {
146
- cTopics[i] = topics[i].c_str();
147
- }
148
- pulsar_client_subscribe_multi_topics_async(this->cClient, cTopics, topics.size(), subscription.c_str(),
149
- this->consumerConfig->GetCConsumerConfig(),
150
- &ConsumerNewInstanceWorker::subscribeCallback, (void *)this);
151
- delete cTopics;
152
- } else {
153
- pulsar_client_subscribe_async(this->cClient, topic.c_str(), subscription.c_str(),
154
- this->consumerConfig->GetCConsumerConfig(),
155
- &ConsumerNewInstanceWorker::subscribeCallback, (void *)this);
156
- }
157
- while (!done) {
158
- std::this_thread::yield();
122
+ if (result != pulsar_result_Ok) {
123
+ return deferred->Reject(std::string("Failed to create consumer: ") + pulsar_result_str(result));
159
124
  }
160
- }
161
- void OnOK() {
162
- Napi::Object obj = Consumer::constructor.New({});
163
- Consumer *consumer = Consumer::Unwrap(obj);
164
125
 
165
- consumer->SetCConsumer(this->consumerWrapper);
166
- consumer->SetListenerCallback(this->listener);
126
+ auto cConsumer = std::shared_ptr<pulsar_consumer_t>(rawConsumer, pulsar_consumer_free);
127
+ auto listener = consumerConfig->GetListenerCallback();
167
128
 
168
- if (this->listener) {
169
- // resume to enable MessageListener function callback
170
- resume_message_listener(this->consumerWrapper->cConsumer);
129
+ if (listener) {
130
+ // pause, will resume in OnOK, to prevent MessageListener get a nullptr of consumer
131
+ pulsar_consumer_pause_message_listener(cConsumer.get());
171
132
  }
172
133
 
173
- this->deferred.Resolve(obj);
174
- }
175
- void OnError(const Napi::Error &e) { this->deferred.Reject(Napi::Error::New(Env(), e.Message()).Value()); }
134
+ deferred->Resolve([cConsumer, consumerConfig, listener](const Napi::Env env) {
135
+ Napi::Object obj = Consumer::constructor.New({});
136
+ Consumer *consumer = Consumer::Unwrap(obj);
176
137
 
177
- private:
178
- Napi::Promise::Deferred deferred;
179
- pulsar_client_t *cClient;
180
- pulsar_consumer_t *cConsumer;
181
- ConsumerConfig *consumerConfig;
182
- ListenerCallback *listener;
183
- std::shared_ptr<CConsumerWrapper> consumerWrapper;
184
- std::atomic<bool> done;
185
- static void subscribeCallback(pulsar_result result, pulsar_consumer_t *consumer, void *ctx) {
186
- ConsumerNewInstanceWorker *worker = (ConsumerNewInstanceWorker *)ctx;
187
- if (result != pulsar_result_Ok) {
188
- worker->SetError(std::string("Failed to create consumer: ") + pulsar_result_str(result));
189
- } else {
190
- worker->consumerWrapper->cConsumer = consumer;
191
- worker->listener = worker->consumerConfig->GetListenerCallback();
138
+ consumer->SetCConsumer(cConsumer);
139
+ consumer->SetListenerCallback(listener);
192
140
 
193
- if (worker->listener) {
194
- // pause, will resume in OnOK, to prevent MessageListener get a nullptr of consumer
195
- pulsar_consumer_pause_message_listener(consumer);
141
+ if (listener) {
142
+ // resume to enable MessageListener function callback
143
+ resume_message_listener(cConsumer.get());
196
144
  }
197
- }
198
145
 
199
- delete worker->consumerConfig;
200
- worker->done = true;
146
+ return obj;
147
+ });
201
148
  }
202
149
  };
203
150
 
204
- Napi::Value Consumer::NewInstance(const Napi::CallbackInfo &info, pulsar_client_t *cClient) {
205
- Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
206
- Napi::Object config = info[0].As<Napi::Object>();
151
+ Napi::Value Consumer::NewInstance(const Napi::CallbackInfo &info, std::shared_ptr<pulsar_client_t> cClient) {
152
+ auto deferred = ThreadSafeDeferred::New(info.Env());
153
+ auto config = info[0].As<Napi::Object>();
154
+ std::shared_ptr<ConsumerConfig> consumerConfig = std::make_shared<ConsumerConfig>(config, &MessageListener);
155
+
156
+ const std::string &topic = consumerConfig->GetTopic();
157
+ const std::vector<std::string> &topics = consumerConfig->GetTopics();
158
+ const std::string &topicsPattern = consumerConfig->GetTopicsPattern();
159
+ if (topic.empty() && topics.size() == 0 && topicsPattern.empty()) {
160
+ deferred->Reject(
161
+ std::string("Topic, topics or topicsPattern is required and must be specified as a string when "
162
+ "creating consumer"));
163
+ return deferred->Promise();
164
+ }
165
+ const std::string &subscription = consumerConfig->GetSubscription();
166
+ if (subscription.empty()) {
167
+ deferred->Reject(
168
+ std::string("Subscription is required and must be specified as a string when creating consumer"));
169
+ return deferred->Promise();
170
+ }
171
+ int32_t ackTimeoutMs = consumerConfig->GetAckTimeoutMs();
172
+ if (ackTimeoutMs != 0 && ackTimeoutMs < MIN_ACK_TIMEOUT_MILLIS) {
173
+ std::string msg("Ack timeout should be 0 or greater than or equal to " +
174
+ std::to_string(MIN_ACK_TIMEOUT_MILLIS));
175
+ deferred->Reject(msg);
176
+ return deferred->Promise();
177
+ }
178
+ int32_t nAckRedeliverTimeoutMs = consumerConfig->GetNAckRedeliverTimeoutMs();
179
+ if (nAckRedeliverTimeoutMs < 0) {
180
+ std::string msg("NAck timeout should be greater than or equal to zero");
181
+ deferred->Reject(msg);
182
+ return deferred->Promise();
183
+ }
207
184
 
208
- std::shared_ptr<CConsumerWrapper> consumerWrapper = std::make_shared<CConsumerWrapper>();
185
+ auto ctx = new ConsumerNewInstanceContext(deferred, cClient, consumerConfig);
209
186
 
210
- ConsumerConfig *consumerConfig = new ConsumerConfig(config, consumerWrapper, &MessageListener);
211
- ConsumerNewInstanceWorker *wk =
212
- new ConsumerNewInstanceWorker(deferred, cClient, consumerConfig, consumerWrapper);
213
- wk->Queue();
214
- return deferred.Promise();
187
+ if (!topicsPattern.empty()) {
188
+ pulsar_client_subscribe_pattern_async(cClient.get(), topicsPattern.c_str(), subscription.c_str(),
189
+ consumerConfig->GetCConsumerConfig().get(),
190
+ &ConsumerNewInstanceContext::subscribeCallback, ctx);
191
+ } else if (topics.size() > 0) {
192
+ const char **cTopics = new const char *[topics.size()];
193
+ for (size_t i = 0; i < topics.size(); i++) {
194
+ cTopics[i] = topics[i].c_str();
195
+ }
196
+ pulsar_client_subscribe_multi_topics_async(cClient.get(), cTopics, topics.size(), subscription.c_str(),
197
+ consumerConfig->GetCConsumerConfig().get(),
198
+ &ConsumerNewInstanceContext::subscribeCallback, ctx);
199
+ delete[] cTopics;
200
+ } else {
201
+ pulsar_client_subscribe_async(cClient.get(), topic.c_str(), subscription.c_str(),
202
+ consumerConfig->GetCConsumerConfig().get(),
203
+ &ConsumerNewInstanceContext::subscribeCallback, ctx);
204
+ }
205
+
206
+ return deferred->Promise();
215
207
  }
216
208
 
209
+ // We still need a receive worker because the c api is missing the equivalent async definition
217
210
  class ConsumerReceiveWorker : public Napi::AsyncWorker {
218
211
  public:
219
- ConsumerReceiveWorker(const Napi::Promise::Deferred &deferred, pulsar_consumer_t *cConsumer,
212
+ ConsumerReceiveWorker(const Napi::Promise::Deferred &deferred, std::shared_ptr<pulsar_consumer_t> cConsumer,
220
213
  int64_t timeout = -1)
221
214
  : AsyncWorker(Napi::Function::New(deferred.Promise().Env(), [](const Napi::CallbackInfo &info) {})),
222
215
  deferred(deferred),
@@ -225,14 +218,17 @@ class ConsumerReceiveWorker : public Napi::AsyncWorker {
225
218
  ~ConsumerReceiveWorker() {}
226
219
  void Execute() {
227
220
  pulsar_result result;
221
+ pulsar_message_t *rawMessage;
228
222
  if (timeout > 0) {
229
- result = pulsar_consumer_receive_with_timeout(this->cConsumer, &(this->cMessage), timeout);
223
+ result = pulsar_consumer_receive_with_timeout(this->cConsumer.get(), &rawMessage, timeout);
230
224
  } else {
231
- result = pulsar_consumer_receive(this->cConsumer, &(this->cMessage));
225
+ result = pulsar_consumer_receive(this->cConsumer.get(), &rawMessage);
232
226
  }
233
227
 
234
228
  if (result != pulsar_result_Ok) {
235
- SetError(std::string("Failed to received message ") + pulsar_result_str(result));
229
+ SetError(std::string("Failed to receive message: ") + pulsar_result_str(result));
230
+ } else {
231
+ this->cMessage = std::shared_ptr<pulsar_message_t>(rawMessage, pulsar_message_free);
236
232
  }
237
233
  }
238
234
  void OnOK() {
@@ -243,160 +239,193 @@ class ConsumerReceiveWorker : public Napi::AsyncWorker {
243
239
 
244
240
  private:
245
241
  Napi::Promise::Deferred deferred;
246
- pulsar_consumer_t *cConsumer;
247
- pulsar_message_t *cMessage;
242
+ std::shared_ptr<pulsar_consumer_t> cConsumer;
243
+ std::shared_ptr<pulsar_message_t> cMessage;
248
244
  int64_t timeout;
249
245
  };
250
246
 
251
247
  Napi::Value Consumer::Receive(const Napi::CallbackInfo &info) {
252
248
  Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
253
249
  if (info[0].IsUndefined()) {
254
- ConsumerReceiveWorker *wk = new ConsumerReceiveWorker(deferred, this->wrapper->cConsumer);
250
+ ConsumerReceiveWorker *wk = new ConsumerReceiveWorker(deferred, this->cConsumer);
255
251
  wk->Queue();
256
252
  } else {
257
253
  Napi::Number timeout = info[0].As<Napi::Object>().ToNumber();
258
- ConsumerReceiveWorker *wk =
259
- new ConsumerReceiveWorker(deferred, this->wrapper->cConsumer, timeout.Int64Value());
254
+ ConsumerReceiveWorker *wk = new ConsumerReceiveWorker(deferred, this->cConsumer, timeout.Int64Value());
260
255
  wk->Queue();
261
256
  }
262
257
  return deferred.Promise();
263
258
  }
264
259
 
265
- void Consumer::Acknowledge(const Napi::CallbackInfo &info) {
266
- Napi::Object obj = info[0].As<Napi::Object>();
267
- Message *msg = Message::Unwrap(obj);
268
- pulsar_consumer_acknowledge_async(this->wrapper->cConsumer, msg->GetCMessage(), NULL, NULL);
260
+ Napi::Value Consumer::Acknowledge(const Napi::CallbackInfo &info) {
261
+ auto obj = info[0].As<Napi::Object>();
262
+ auto msg = Message::Unwrap(obj);
263
+ auto deferred = ThreadSafeDeferred::New(Env());
264
+ auto ctx = new ExtDeferredContext(deferred);
265
+
266
+ pulsar_consumer_acknowledge_async(
267
+ this->cConsumer.get(), msg->GetCMessage().get(),
268
+ [](pulsar_result result, void *ctx) {
269
+ auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
270
+ auto deferred = deferredContext->deferred;
271
+ delete deferredContext;
272
+
273
+ if (result != pulsar_result_Ok) {
274
+ deferred->Reject(std::string("Failed to acknowledge: ") + pulsar_result_str(result));
275
+ } else {
276
+ deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
277
+ }
278
+ },
279
+ ctx);
280
+
281
+ return deferred->Promise();
269
282
  }
270
283
 
271
- void Consumer::AcknowledgeId(const Napi::CallbackInfo &info) {
272
- Napi::Object obj = info[0].As<Napi::Object>();
273
- MessageId *msgId = MessageId::Unwrap(obj);
274
- pulsar_consumer_acknowledge_async_id(this->wrapper->cConsumer, msgId->GetCMessageId(), NULL, NULL);
284
+ Napi::Value Consumer::AcknowledgeId(const Napi::CallbackInfo &info) {
285
+ auto obj = info[0].As<Napi::Object>();
286
+ auto *msgId = MessageId::Unwrap(obj);
287
+ auto deferred = ThreadSafeDeferred::New(Env());
288
+ auto ctx = new ExtDeferredContext(deferred);
289
+
290
+ pulsar_consumer_acknowledge_async_id(
291
+ this->cConsumer.get(), msgId->GetCMessageId().get(),
292
+ [](pulsar_result result, void *ctx) {
293
+ auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
294
+ auto deferred = deferredContext->deferred;
295
+ delete deferredContext;
296
+
297
+ if (result != pulsar_result_Ok) {
298
+ deferred->Reject(std::string("Failed to acknowledge id: ") + pulsar_result_str(result));
299
+ } else {
300
+ deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
301
+ }
302
+ },
303
+ ctx);
304
+
305
+ return deferred->Promise();
275
306
  }
276
307
 
277
308
  void Consumer::NegativeAcknowledge(const Napi::CallbackInfo &info) {
278
309
  Napi::Object obj = info[0].As<Napi::Object>();
279
310
  Message *msg = Message::Unwrap(obj);
280
- pulsar_consumer_negative_acknowledge(this->wrapper->cConsumer, msg->GetCMessage());
311
+ std::shared_ptr<pulsar_message_t> cMessage = msg->GetCMessage();
312
+ pulsar_consumer_negative_acknowledge(this->cConsumer.get(), cMessage.get());
281
313
  }
282
314
 
283
315
  void Consumer::NegativeAcknowledgeId(const Napi::CallbackInfo &info) {
284
316
  Napi::Object obj = info[0].As<Napi::Object>();
285
317
  MessageId *msgId = MessageId::Unwrap(obj);
286
- pulsar_consumer_negative_acknowledge_id(this->wrapper->cConsumer, msgId->GetCMessageId());
318
+ std::shared_ptr<pulsar_message_id_t> cMessageId = msgId->GetCMessageId();
319
+ pulsar_consumer_negative_acknowledge_id(this->cConsumer.get(), cMessageId.get());
287
320
  }
288
321
 
289
- void Consumer::AcknowledgeCumulative(const Napi::CallbackInfo &info) {
290
- Napi::Object obj = info[0].As<Napi::Object>();
291
- Message *msg = Message::Unwrap(obj);
292
- pulsar_consumer_acknowledge_cumulative_async(this->wrapper->cConsumer, msg->GetCMessage(), NULL, NULL);
322
+ Napi::Value Consumer::AcknowledgeCumulative(const Napi::CallbackInfo &info) {
323
+ auto obj = info[0].As<Napi::Object>();
324
+ auto *msg = Message::Unwrap(obj);
325
+ auto deferred = ThreadSafeDeferred::New(Env());
326
+ auto ctx = new ExtDeferredContext(deferred);
327
+
328
+ pulsar_consumer_acknowledge_cumulative_async(
329
+ this->cConsumer.get(), msg->GetCMessage().get(),
330
+ [](pulsar_result result, void *ctx) {
331
+ auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
332
+ auto deferred = deferredContext->deferred;
333
+ delete deferredContext;
334
+
335
+ if (result != pulsar_result_Ok) {
336
+ deferred->Reject(std::string("Failed to acknowledge cumulatively: ") + pulsar_result_str(result));
337
+ } else {
338
+ deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
339
+ }
340
+ },
341
+ ctx);
342
+
343
+ return deferred->Promise();
293
344
  }
294
345
 
295
- void Consumer::AcknowledgeCumulativeId(const Napi::CallbackInfo &info) {
296
- Napi::Object obj = info[0].As<Napi::Object>();
297
- MessageId *msgId = MessageId::Unwrap(obj);
298
- pulsar_consumer_acknowledge_cumulative_async_id(this->wrapper->cConsumer, msgId->GetCMessageId(), NULL,
299
- NULL);
346
+ Napi::Value Consumer::AcknowledgeCumulativeId(const Napi::CallbackInfo &info) {
347
+ auto obj = info[0].As<Napi::Object>();
348
+ auto *msgId = MessageId::Unwrap(obj);
349
+ auto deferred = ThreadSafeDeferred::New(Env());
350
+ auto ctx = new ExtDeferredContext(deferred);
351
+
352
+ pulsar_consumer_acknowledge_cumulative_async_id(
353
+ this->cConsumer.get(), msgId->GetCMessageId().get(),
354
+ [](pulsar_result result, void *ctx) {
355
+ auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
356
+ auto deferred = deferredContext->deferred;
357
+ delete deferredContext;
358
+
359
+ if (result != pulsar_result_Ok) {
360
+ deferred->Reject(std::string("Failed to acknowledge cumulatively by id: ") +
361
+ pulsar_result_str(result));
362
+ } else {
363
+ deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
364
+ }
365
+ },
366
+ ctx);
367
+
368
+ return deferred->Promise();
300
369
  }
301
370
 
302
371
  Napi::Value Consumer::IsConnected(const Napi::CallbackInfo &info) {
303
372
  Napi::Env env = info.Env();
304
- return Napi::Boolean::New(env, pulsar_consumer_is_connected(this->wrapper->cConsumer));
373
+ return Napi::Boolean::New(env, pulsar_consumer_is_connected(this->cConsumer.get()));
305
374
  }
306
375
 
307
- class ConsumerCloseWorker : public Napi::AsyncWorker {
308
- public:
309
- ConsumerCloseWorker(const Napi::Promise::Deferred &deferred, pulsar_consumer_t *cConsumer,
310
- Consumer *consumer)
311
- : AsyncWorker(Napi::Function::New(deferred.Promise().Env(), [](const Napi::CallbackInfo &info) {})),
312
- deferred(deferred),
313
- cConsumer(cConsumer),
314
- consumer(consumer) {}
315
-
316
- ~ConsumerCloseWorker() {}
317
- void Execute() {
318
- pulsar_consumer_pause_message_listener(this->cConsumer);
319
- pulsar_result result = pulsar_consumer_close(this->cConsumer);
320
- if (result != pulsar_result_Ok) {
321
- SetError(pulsar_result_str(result));
322
- }
323
- }
324
- void OnOK() {
325
- this->consumer->Cleanup();
326
- this->deferred.Resolve(Env().Null());
327
- }
328
- void OnError(const Napi::Error &e) {
329
- this->deferred.Reject(
330
- Napi::Error::New(Env(), std::string("Failed to close consumer: ") + e.Message()).Value());
331
- }
332
-
333
- private:
334
- Napi::Promise::Deferred deferred;
335
- pulsar_consumer_t *cConsumer;
336
- Consumer *consumer;
337
- };
338
-
339
- class ConsumerUnsubscribeWorker : public Napi::AsyncWorker {
340
- public:
341
- ConsumerUnsubscribeWorker(const Napi::Promise::Deferred &deferred, pulsar_consumer_t *cConsumer,
342
- Consumer *consumer)
343
- : AsyncWorker(Napi::Function::New(deferred.Promise().Env(), [](const Napi::CallbackInfo &info) {})),
344
- deferred(deferred),
345
- cConsumer(cConsumer),
346
- consumer(consumer) {}
347
-
348
- ~ConsumerUnsubscribeWorker() {}
349
- void Execute() {
350
- pulsar_consumer_pause_message_listener(this->cConsumer);
351
- pulsar_result result = pulsar_consumer_unsubscribe(this->cConsumer);
352
- if (result != pulsar_result_Ok) {
353
- SetError(pulsar_result_str(result));
354
- }
355
- }
356
- void OnOK() {
357
- this->consumer->Cleanup();
358
- this->deferred.Resolve(Env().Null());
359
- }
360
- void OnError(const Napi::Error &e) {
361
- this->deferred.Reject(
362
- Napi::Error::New(Env(), std::string("Failed to unsubscribe consumer: ") + e.Message()).Value());
363
- }
364
-
365
- private:
366
- Napi::Promise::Deferred deferred;
367
- pulsar_consumer_t *cConsumer;
368
- Consumer *consumer;
369
- };
370
-
371
376
  void Consumer::Cleanup() {
372
- if (this->listener) {
373
- this->CleanupListener();
377
+ if (this->listener != nullptr) {
378
+ pulsar_consumer_pause_message_listener(this->cConsumer.get());
379
+ this->listener->callback.Release();
380
+ this->listener = nullptr;
381
+ this->Unref();
374
382
  }
375
383
  }
376
384
 
377
- void Consumer::CleanupListener() {
378
- pulsar_consumer_pause_message_listener(this->wrapper->cConsumer);
379
- this->Unref();
380
- this->listener->callback.Release();
381
- this->listener = nullptr;
382
- }
383
-
384
385
  Napi::Value Consumer::Close(const Napi::CallbackInfo &info) {
385
- Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
386
- ConsumerCloseWorker *wk = new ConsumerCloseWorker(deferred, this->wrapper->cConsumer, this);
387
- wk->Queue();
388
- return deferred.Promise();
386
+ auto deferred = ThreadSafeDeferred::New(Env());
387
+ auto ctx = new ExtDeferredContext(deferred);
388
+ this->Cleanup();
389
+
390
+ pulsar_consumer_close_async(
391
+ this->cConsumer.get(),
392
+ [](pulsar_result result, void *ctx) {
393
+ auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
394
+ auto deferred = deferredContext->deferred;
395
+ delete deferredContext;
396
+
397
+ if (result != pulsar_result_Ok) {
398
+ deferred->Reject(std::string("Failed to close consumer: ") + pulsar_result_str(result));
399
+ } else {
400
+ deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
401
+ }
402
+ },
403
+ ctx);
404
+
405
+ return deferred->Promise();
389
406
  }
390
407
 
391
408
  Napi::Value Consumer::Unsubscribe(const Napi::CallbackInfo &info) {
392
- Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
393
- ConsumerUnsubscribeWorker *wk = new ConsumerUnsubscribeWorker(deferred, this->wrapper->cConsumer, this);
394
- wk->Queue();
395
- return deferred.Promise();
409
+ auto deferred = ThreadSafeDeferred::New(Env());
410
+ auto ctx = new ExtDeferredContext(deferred);
411
+
412
+ pulsar_consumer_pause_message_listener(this->cConsumer.get());
413
+ pulsar_consumer_unsubscribe_async(
414
+ this->cConsumer.get(),
415
+ [](pulsar_result result, void *ctx) {
416
+ auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
417
+ auto deferred = deferredContext->deferred;
418
+ delete deferredContext;
419
+
420
+ if (result != pulsar_result_Ok) {
421
+ deferred->Reject(std::string("Failed to unsubscribe consumer: ") + pulsar_result_str(result));
422
+ } else {
423
+ deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
424
+ }
425
+ },
426
+ ctx);
427
+
428
+ return deferred->Promise();
396
429
  }
397
430
 
398
- Consumer::~Consumer() {
399
- if (this->listener) {
400
- this->CleanupListener();
401
- }
402
- }
431
+ Consumer::~Consumer() { this->Cleanup(); }
package/src/Consumer.h CHANGED
@@ -28,26 +28,26 @@
28
28
  class Consumer : public Napi::ObjectWrap<Consumer> {
29
29
  public:
30
30
  static void Init(Napi::Env env, Napi::Object exports);
31
- static Napi::Value NewInstance(const Napi::CallbackInfo &info, pulsar_client_t *cClient);
31
+ static Napi::Value NewInstance(const Napi::CallbackInfo &info, std::shared_ptr<pulsar_client_t> cClient);
32
32
  static Napi::FunctionReference constructor;
33
33
  Consumer(const Napi::CallbackInfo &info);
34
34
  ~Consumer();
35
- void SetCConsumer(std::shared_ptr<CConsumerWrapper> cConsumer);
36
- void SetListenerCallback(ListenerCallback *listener);
35
+ void SetCConsumer(std::shared_ptr<pulsar_consumer_t> cConsumer);
36
+ void SetListenerCallback(MessageListenerCallback *listener);
37
37
  void Cleanup();
38
38
  void CleanupListener();
39
39
 
40
40
  private:
41
- std::shared_ptr<CConsumerWrapper> wrapper;
42
- ListenerCallback *listener;
41
+ std::shared_ptr<pulsar_consumer_t> cConsumer;
42
+ MessageListenerCallback *listener;
43
43
 
44
44
  Napi::Value Receive(const Napi::CallbackInfo &info);
45
- void Acknowledge(const Napi::CallbackInfo &info);
46
- void AcknowledgeId(const Napi::CallbackInfo &info);
45
+ Napi::Value Acknowledge(const Napi::CallbackInfo &info);
46
+ Napi::Value AcknowledgeId(const Napi::CallbackInfo &info);
47
47
  void NegativeAcknowledge(const Napi::CallbackInfo &info);
48
48
  void NegativeAcknowledgeId(const Napi::CallbackInfo &info);
49
- void AcknowledgeCumulative(const Napi::CallbackInfo &info);
50
- void AcknowledgeCumulativeId(const Napi::CallbackInfo &info);
49
+ Napi::Value AcknowledgeCumulative(const Napi::CallbackInfo &info);
50
+ Napi::Value AcknowledgeCumulativeId(const Napi::CallbackInfo &info);
51
51
  Napi::Value IsConnected(const Napi::CallbackInfo &info);
52
52
  Napi::Value Close(const Napi::CallbackInfo &info);
53
53
  Napi::Value Unsubscribe(const Napi::CallbackInfo &info);