pulsar-client 1.6.2 → 1.8.0-rc1
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/.asf.yaml +8 -1
- package/.github/PULL_REQUEST_TEMPLATE.md +65 -0
- package/.github/workflows/ci-build-release-napi.yml +195 -0
- package/.github/workflows/ci-pr-validation.yml +225 -0
- package/README.md +87 -68
- package/binding.gyp +41 -39
- package/{pulsar-test-service-stop.sh → build-support/dep-version.py} +4 -6
- package/build-support/download-release-artifacts.py +74 -0
- package/build-support/generate-source-archive.sh +28 -0
- package/build-support/install-cpp-client.sh +66 -0
- package/{pulsar-test-service-start.sh → build-support/pulsar-test-container-start.sh} +11 -21
- package/build-support/pulsar-test-service-start.sh +37 -0
- package/build-support/pulsar-test-service-stop.sh +32 -0
- package/{.github/workflows/nodejs.yml → build-support/sign-files.sh} +13 -12
- package/build-support/stage-release.sh +44 -0
- package/dependencies.yaml +28 -0
- package/docs/release-process.md +242 -0
- package/examples/consumer.js +1 -1
- package/examples/consumer_listener.js +1 -1
- package/examples/consumer_tls_auth.js +1 -1
- package/examples/custom_logger.js +60 -0
- package/examples/encryption-consumer.js +1 -1
- package/examples/encryption-producer.js +1 -1
- package/examples/producer.js +1 -1
- package/examples/producer_tls_auth.js +1 -1
- package/examples/reader.js +1 -1
- package/examples/reader_listener.js +1 -1
- package/index.d.ts +12 -4
- package/index.js +2 -1
- package/package.json +14 -12
- package/pkg/build-napi-inside-docker.sh +31 -0
- package/pkg/linux_glibc/Dockerfile +33 -0
- package/pkg/linux_musl/Dockerfile +32 -0
- package/pkg/load_test.js +30 -0
- package/pkg/mac/build-cpp-deps-lib.sh +186 -0
- package/pkg/mac/build-cpp-lib.sh +51 -0
- package/{docker-tests.sh → pkg/mac/common.sh} +13 -13
- package/pkg/windows/download-cpp-client.bat +12 -0
- package/pulsar-client-cpp.txt +2 -0
- package/src/AuthenticationAthenz.js +1 -1
- package/src/AuthenticationOauth2.js +1 -1
- package/src/AuthenticationTls.js +1 -1
- package/src/AuthenticationToken.js +1 -1
- package/src/Client.cc +84 -58
- package/src/Client.h +6 -4
- package/src/Consumer.cc +331 -234
- package/src/Consumer.h +11 -9
- package/src/ConsumerConfig.cc +54 -32
- package/src/ConsumerConfig.h +5 -6
- package/src/Message.cc +26 -29
- package/src/Message.h +4 -4
- package/src/MessageId.cc +19 -22
- package/src/MessageId.h +5 -6
- package/src/MessageListener.h +3 -8
- package/src/Producer.cc +116 -133
- package/src/Producer.h +3 -3
- package/src/ProducerConfig.cc +39 -22
- package/src/ProducerConfig.h +2 -2
- package/src/Reader.cc +147 -128
- package/src/Reader.h +5 -3
- package/src/ReaderConfig.cc +14 -20
- package/src/ReaderConfig.h +5 -6
- package/src/ReaderListener.h +2 -7
- package/src/SchemaInfo.cc +78 -0
- package/src/SchemaInfo.h +41 -0
- package/src/ThreadSafeDeferred.cc +98 -0
- package/src/ThreadSafeDeferred.h +85 -0
- package/src/pulsar-binding.js +8 -0
- package/tests/conf/standalone.conf +6 -0
- package/tests/consumer.test.js +2 -2
- package/tests/end_to_end.test.js +214 -2
- package/tests/producer.test.js +2 -2
- package/{run-unit-tests.sh → tests/run-unit-tests.sh} +5 -14
- package/pulsar-version.txt +0 -1
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>
|
|
@@ -40,6 +41,8 @@ void Consumer::Init(Napi::Env env, Napi::Object exports) {
|
|
|
40
41
|
InstanceMethod("negativeAcknowledgeId", &Consumer::NegativeAcknowledgeId),
|
|
41
42
|
InstanceMethod("acknowledgeCumulative", &Consumer::AcknowledgeCumulative),
|
|
42
43
|
InstanceMethod("acknowledgeCumulativeId", &Consumer::AcknowledgeCumulativeId),
|
|
44
|
+
InstanceMethod("seek", &Consumer::Seek),
|
|
45
|
+
InstanceMethod("seekTimestamp", &Consumer::SeekTimestamp),
|
|
43
46
|
InstanceMethod("isConnected", &Consumer::IsConnected),
|
|
44
47
|
InstanceMethod("close", &Consumer::Close),
|
|
45
48
|
InstanceMethod("unsubscribe", &Consumer::Unsubscribe),
|
|
@@ -50,10 +53,10 @@ void Consumer::Init(Napi::Env env, Napi::Object exports) {
|
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
struct MessageListenerProxyData {
|
|
53
|
-
pulsar_message_t
|
|
56
|
+
std::shared_ptr<pulsar_message_t> cMessage;
|
|
54
57
|
Consumer *consumer;
|
|
55
58
|
|
|
56
|
-
MessageListenerProxyData(pulsar_message_t
|
|
59
|
+
MessageListenerProxyData(std::shared_ptr<pulsar_message_t> cMessage, Consumer *consumer)
|
|
57
60
|
: cMessage(cMessage), consumer(consumer) {}
|
|
58
61
|
};
|
|
59
62
|
|
|
@@ -62,11 +65,16 @@ void MessageListenerProxy(Napi::Env env, Napi::Function jsCallback, MessageListe
|
|
|
62
65
|
Consumer *consumer = data->consumer;
|
|
63
66
|
delete data;
|
|
64
67
|
|
|
65
|
-
|
|
68
|
+
// `consumer` might be null in certain cases, segmentation fault might happend without this null check. We
|
|
69
|
+
// need to handle this rare case in future.
|
|
70
|
+
if (consumer) {
|
|
71
|
+
jsCallback.Call({msg, consumer->Value()});
|
|
72
|
+
}
|
|
66
73
|
}
|
|
67
74
|
|
|
68
|
-
void MessageListener(pulsar_consumer_t *
|
|
69
|
-
|
|
75
|
+
void MessageListener(pulsar_consumer_t *rawConsumer, pulsar_message_t *rawMessage, void *ctx) {
|
|
76
|
+
std::shared_ptr<pulsar_message_t> cMessage(rawMessage, pulsar_message_free);
|
|
77
|
+
MessageListenerCallback *listenerCallback = (MessageListenerCallback *)ctx;
|
|
70
78
|
|
|
71
79
|
Consumer *consumer = (Consumer *)listenerCallback->consumer;
|
|
72
80
|
|
|
@@ -79,144 +87,131 @@ void MessageListener(pulsar_consumer_t *cConsumer, pulsar_message_t *cMessage, v
|
|
|
79
87
|
listenerCallback->callback.Release();
|
|
80
88
|
}
|
|
81
89
|
|
|
82
|
-
void Consumer::SetCConsumer(std::shared_ptr<
|
|
83
|
-
void Consumer::SetListenerCallback(
|
|
84
|
-
if (listener) {
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
void Consumer::SetCConsumer(std::shared_ptr<pulsar_consumer_t> cConsumer) { this->cConsumer = cConsumer; }
|
|
91
|
+
void Consumer::SetListenerCallback(MessageListenerCallback *listener) {
|
|
92
|
+
if (this->listener != nullptr) {
|
|
93
|
+
// It is only safe to set the listener once for the lifecycle of the Consumer
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
88
96
|
|
|
89
|
-
|
|
97
|
+
if (listener != nullptr) {
|
|
90
98
|
listener->consumer = this;
|
|
99
|
+
// If a consumer listener is set, the Consumer instance is kept alive even if it goes out of scope in JS
|
|
100
|
+
// code.
|
|
101
|
+
this->Ref();
|
|
102
|
+
this->listener = listener;
|
|
91
103
|
}
|
|
92
|
-
|
|
93
|
-
this->listener = listener;
|
|
94
104
|
}
|
|
95
105
|
|
|
96
106
|
Consumer::Consumer(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Consumer>(info), listener(nullptr) {}
|
|
97
107
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
}
|
|
108
|
+
struct ConsumerNewInstanceContext {
|
|
109
|
+
ConsumerNewInstanceContext(std::shared_ptr<ThreadSafeDeferred> deferred,
|
|
110
|
+
std::shared_ptr<pulsar_client_t> cClient,
|
|
111
|
+
std::shared_ptr<ConsumerConfig> consumerConfig)
|
|
112
|
+
: deferred(deferred), cClient(cClient), consumerConfig(consumerConfig){};
|
|
113
|
+
std::shared_ptr<ThreadSafeDeferred> deferred;
|
|
114
|
+
std::shared_ptr<pulsar_client_t> cClient;
|
|
115
|
+
std::shared_ptr<ConsumerConfig> consumerConfig;
|
|
116
|
+
|
|
117
|
+
static void subscribeCallback(pulsar_result result, pulsar_consumer_t *rawConsumer, void *ctx) {
|
|
118
|
+
auto instanceContext = static_cast<ConsumerNewInstanceContext *>(ctx);
|
|
119
|
+
auto deferred = instanceContext->deferred;
|
|
120
|
+
auto cClient = instanceContext->cClient;
|
|
121
|
+
auto consumerConfig = instanceContext->consumerConfig;
|
|
122
|
+
delete instanceContext;
|
|
137
123
|
|
|
138
|
-
|
|
139
|
-
|
|
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();
|
|
124
|
+
if (result != pulsar_result_Ok) {
|
|
125
|
+
return deferred->Reject(std::string("Failed to create consumer: ") + pulsar_result_str(result));
|
|
159
126
|
}
|
|
160
|
-
}
|
|
161
|
-
void OnOK() {
|
|
162
|
-
Napi::Object obj = Consumer::constructor.New({});
|
|
163
|
-
Consumer *consumer = Consumer::Unwrap(obj);
|
|
164
127
|
|
|
165
|
-
|
|
166
|
-
|
|
128
|
+
auto cConsumer = std::shared_ptr<pulsar_consumer_t>(rawConsumer, pulsar_consumer_free);
|
|
129
|
+
auto listener = consumerConfig->GetListenerCallback();
|
|
167
130
|
|
|
168
|
-
if (
|
|
169
|
-
// resume to
|
|
170
|
-
|
|
131
|
+
if (listener) {
|
|
132
|
+
// pause, will resume in OnOK, to prevent MessageListener get a nullptr of consumer
|
|
133
|
+
pulsar_consumer_pause_message_listener(cConsumer.get());
|
|
171
134
|
}
|
|
172
135
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
136
|
+
deferred->Resolve([cConsumer, consumerConfig, listener](const Napi::Env env) {
|
|
137
|
+
Napi::Object obj = Consumer::constructor.New({});
|
|
138
|
+
Consumer *consumer = Consumer::Unwrap(obj);
|
|
176
139
|
|
|
177
|
-
|
|
178
|
-
|
|
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();
|
|
140
|
+
consumer->SetCConsumer(cConsumer);
|
|
141
|
+
consumer->SetListenerCallback(listener);
|
|
192
142
|
|
|
193
|
-
if (
|
|
194
|
-
//
|
|
195
|
-
|
|
143
|
+
if (listener) {
|
|
144
|
+
// resume to enable MessageListener function callback
|
|
145
|
+
resume_message_listener(cConsumer.get());
|
|
196
146
|
}
|
|
197
|
-
}
|
|
198
147
|
|
|
199
|
-
|
|
200
|
-
|
|
148
|
+
return obj;
|
|
149
|
+
});
|
|
201
150
|
}
|
|
202
151
|
};
|
|
203
152
|
|
|
204
|
-
Napi::Value Consumer::NewInstance(const Napi::CallbackInfo &info, pulsar_client_t
|
|
205
|
-
|
|
206
|
-
|
|
153
|
+
Napi::Value Consumer::NewInstance(const Napi::CallbackInfo &info, std::shared_ptr<pulsar_client_t> cClient) {
|
|
154
|
+
auto deferred = ThreadSafeDeferred::New(info.Env());
|
|
155
|
+
auto config = info[0].As<Napi::Object>();
|
|
156
|
+
std::shared_ptr<ConsumerConfig> consumerConfig = std::make_shared<ConsumerConfig>(config, &MessageListener);
|
|
157
|
+
|
|
158
|
+
const std::string &topic = consumerConfig->GetTopic();
|
|
159
|
+
const std::vector<std::string> &topics = consumerConfig->GetTopics();
|
|
160
|
+
const std::string &topicsPattern = consumerConfig->GetTopicsPattern();
|
|
161
|
+
if (topic.empty() && topics.size() == 0 && topicsPattern.empty()) {
|
|
162
|
+
deferred->Reject(
|
|
163
|
+
std::string("Topic, topics or topicsPattern is required and must be specified as a string when "
|
|
164
|
+
"creating consumer"));
|
|
165
|
+
return deferred->Promise();
|
|
166
|
+
}
|
|
167
|
+
const std::string &subscription = consumerConfig->GetSubscription();
|
|
168
|
+
if (subscription.empty()) {
|
|
169
|
+
deferred->Reject(
|
|
170
|
+
std::string("Subscription is required and must be specified as a string when creating consumer"));
|
|
171
|
+
return deferred->Promise();
|
|
172
|
+
}
|
|
173
|
+
int32_t ackTimeoutMs = consumerConfig->GetAckTimeoutMs();
|
|
174
|
+
if (ackTimeoutMs != 0 && ackTimeoutMs < MIN_ACK_TIMEOUT_MILLIS) {
|
|
175
|
+
std::string msg("Ack timeout should be 0 or greater than or equal to " +
|
|
176
|
+
std::to_string(MIN_ACK_TIMEOUT_MILLIS));
|
|
177
|
+
deferred->Reject(msg);
|
|
178
|
+
return deferred->Promise();
|
|
179
|
+
}
|
|
180
|
+
int32_t nAckRedeliverTimeoutMs = consumerConfig->GetNAckRedeliverTimeoutMs();
|
|
181
|
+
if (nAckRedeliverTimeoutMs < 0) {
|
|
182
|
+
std::string msg("NAck timeout should be greater than or equal to zero");
|
|
183
|
+
deferred->Reject(msg);
|
|
184
|
+
return deferred->Promise();
|
|
185
|
+
}
|
|
207
186
|
|
|
208
|
-
|
|
187
|
+
auto ctx = new ConsumerNewInstanceContext(deferred, cClient, consumerConfig);
|
|
188
|
+
|
|
189
|
+
if (!topicsPattern.empty()) {
|
|
190
|
+
pulsar_client_subscribe_pattern_async(cClient.get(), topicsPattern.c_str(), subscription.c_str(),
|
|
191
|
+
consumerConfig->GetCConsumerConfig().get(),
|
|
192
|
+
&ConsumerNewInstanceContext::subscribeCallback, ctx);
|
|
193
|
+
} else if (topics.size() > 0) {
|
|
194
|
+
const char **cTopics = new const char *[topics.size()];
|
|
195
|
+
for (size_t i = 0; i < topics.size(); i++) {
|
|
196
|
+
cTopics[i] = topics[i].c_str();
|
|
197
|
+
}
|
|
198
|
+
pulsar_client_subscribe_multi_topics_async(cClient.get(), cTopics, topics.size(), subscription.c_str(),
|
|
199
|
+
consumerConfig->GetCConsumerConfig().get(),
|
|
200
|
+
&ConsumerNewInstanceContext::subscribeCallback, ctx);
|
|
201
|
+
delete[] cTopics;
|
|
202
|
+
} else {
|
|
203
|
+
pulsar_client_subscribe_async(cClient.get(), topic.c_str(), subscription.c_str(),
|
|
204
|
+
consumerConfig->GetCConsumerConfig().get(),
|
|
205
|
+
&ConsumerNewInstanceContext::subscribeCallback, ctx);
|
|
206
|
+
}
|
|
209
207
|
|
|
210
|
-
|
|
211
|
-
ConsumerNewInstanceWorker *wk =
|
|
212
|
-
new ConsumerNewInstanceWorker(deferred, cClient, consumerConfig, consumerWrapper);
|
|
213
|
-
wk->Queue();
|
|
214
|
-
return deferred.Promise();
|
|
208
|
+
return deferred->Promise();
|
|
215
209
|
}
|
|
216
210
|
|
|
211
|
+
// We still need a receive worker because the c api is missing the equivalent async definition
|
|
217
212
|
class ConsumerReceiveWorker : public Napi::AsyncWorker {
|
|
218
213
|
public:
|
|
219
|
-
ConsumerReceiveWorker(const Napi::Promise::Deferred &deferred, pulsar_consumer_t
|
|
214
|
+
ConsumerReceiveWorker(const Napi::Promise::Deferred &deferred, std::shared_ptr<pulsar_consumer_t> cConsumer,
|
|
220
215
|
int64_t timeout = -1)
|
|
221
216
|
: AsyncWorker(Napi::Function::New(deferred.Promise().Env(), [](const Napi::CallbackInfo &info) {})),
|
|
222
217
|
deferred(deferred),
|
|
@@ -225,14 +220,17 @@ class ConsumerReceiveWorker : public Napi::AsyncWorker {
|
|
|
225
220
|
~ConsumerReceiveWorker() {}
|
|
226
221
|
void Execute() {
|
|
227
222
|
pulsar_result result;
|
|
223
|
+
pulsar_message_t *rawMessage;
|
|
228
224
|
if (timeout > 0) {
|
|
229
|
-
result = pulsar_consumer_receive_with_timeout(this->cConsumer, &
|
|
225
|
+
result = pulsar_consumer_receive_with_timeout(this->cConsumer.get(), &rawMessage, timeout);
|
|
230
226
|
} else {
|
|
231
|
-
result = pulsar_consumer_receive(this->cConsumer, &
|
|
227
|
+
result = pulsar_consumer_receive(this->cConsumer.get(), &rawMessage);
|
|
232
228
|
}
|
|
233
229
|
|
|
234
230
|
if (result != pulsar_result_Ok) {
|
|
235
|
-
SetError(std::string("Failed to
|
|
231
|
+
SetError(std::string("Failed to receive message: ") + pulsar_result_str(result));
|
|
232
|
+
} else {
|
|
233
|
+
this->cMessage = std::shared_ptr<pulsar_message_t>(rawMessage, pulsar_message_free);
|
|
236
234
|
}
|
|
237
235
|
}
|
|
238
236
|
void OnOK() {
|
|
@@ -243,160 +241,259 @@ class ConsumerReceiveWorker : public Napi::AsyncWorker {
|
|
|
243
241
|
|
|
244
242
|
private:
|
|
245
243
|
Napi::Promise::Deferred deferred;
|
|
246
|
-
pulsar_consumer_t
|
|
247
|
-
pulsar_message_t
|
|
244
|
+
std::shared_ptr<pulsar_consumer_t> cConsumer;
|
|
245
|
+
std::shared_ptr<pulsar_message_t> cMessage;
|
|
248
246
|
int64_t timeout;
|
|
249
247
|
};
|
|
250
248
|
|
|
251
249
|
Napi::Value Consumer::Receive(const Napi::CallbackInfo &info) {
|
|
252
|
-
Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
|
|
253
250
|
if (info[0].IsUndefined()) {
|
|
254
|
-
|
|
255
|
-
|
|
251
|
+
auto deferred = ThreadSafeDeferred::New(Env());
|
|
252
|
+
auto ctx = new ExtDeferredContext(deferred);
|
|
253
|
+
pulsar_consumer_receive_async(
|
|
254
|
+
this->cConsumer.get(),
|
|
255
|
+
[](pulsar_result result, pulsar_message_t *rawMessage, void *ctx) {
|
|
256
|
+
auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
|
|
257
|
+
auto deferred = deferredContext->deferred;
|
|
258
|
+
delete deferredContext;
|
|
259
|
+
|
|
260
|
+
if (result != pulsar_result_Ok) {
|
|
261
|
+
deferred->Reject(std::string("Failed to receive message: ") + pulsar_result_str(result));
|
|
262
|
+
} else {
|
|
263
|
+
deferred->Resolve([rawMessage](const Napi::Env env) {
|
|
264
|
+
Napi::Object obj = Message::NewInstance(
|
|
265
|
+
{}, std::shared_ptr<pulsar_message_t>(rawMessage, pulsar_message_free));
|
|
266
|
+
return obj;
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
ctx);
|
|
271
|
+
return deferred->Promise();
|
|
256
272
|
} else {
|
|
273
|
+
Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
|
|
257
274
|
Napi::Number timeout = info[0].As<Napi::Object>().ToNumber();
|
|
258
|
-
ConsumerReceiveWorker *wk =
|
|
259
|
-
new ConsumerReceiveWorker(deferred, this->wrapper->cConsumer, timeout.Int64Value());
|
|
275
|
+
ConsumerReceiveWorker *wk = new ConsumerReceiveWorker(deferred, this->cConsumer, timeout.Int64Value());
|
|
260
276
|
wk->Queue();
|
|
277
|
+
return deferred.Promise();
|
|
261
278
|
}
|
|
262
|
-
return deferred.Promise();
|
|
263
279
|
}
|
|
264
280
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
281
|
+
Napi::Value Consumer::Acknowledge(const Napi::CallbackInfo &info) {
|
|
282
|
+
auto obj = info[0].As<Napi::Object>();
|
|
283
|
+
auto msg = Message::Unwrap(obj);
|
|
284
|
+
auto deferred = ThreadSafeDeferred::New(Env());
|
|
285
|
+
auto ctx = new ExtDeferredContext(deferred);
|
|
286
|
+
|
|
287
|
+
pulsar_consumer_acknowledge_async(
|
|
288
|
+
this->cConsumer.get(), msg->GetCMessage().get(),
|
|
289
|
+
[](pulsar_result result, void *ctx) {
|
|
290
|
+
auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
|
|
291
|
+
auto deferred = deferredContext->deferred;
|
|
292
|
+
delete deferredContext;
|
|
293
|
+
|
|
294
|
+
if (result != pulsar_result_Ok) {
|
|
295
|
+
deferred->Reject(std::string("Failed to acknowledge: ") + pulsar_result_str(result));
|
|
296
|
+
} else {
|
|
297
|
+
deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
ctx);
|
|
301
|
+
|
|
302
|
+
return deferred->Promise();
|
|
269
303
|
}
|
|
270
304
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
305
|
+
Napi::Value Consumer::AcknowledgeId(const Napi::CallbackInfo &info) {
|
|
306
|
+
auto obj = info[0].As<Napi::Object>();
|
|
307
|
+
auto *msgId = MessageId::Unwrap(obj);
|
|
308
|
+
auto deferred = ThreadSafeDeferred::New(Env());
|
|
309
|
+
auto ctx = new ExtDeferredContext(deferred);
|
|
310
|
+
|
|
311
|
+
pulsar_consumer_acknowledge_async_id(
|
|
312
|
+
this->cConsumer.get(), msgId->GetCMessageId().get(),
|
|
313
|
+
[](pulsar_result result, void *ctx) {
|
|
314
|
+
auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
|
|
315
|
+
auto deferred = deferredContext->deferred;
|
|
316
|
+
delete deferredContext;
|
|
317
|
+
|
|
318
|
+
if (result != pulsar_result_Ok) {
|
|
319
|
+
deferred->Reject(std::string("Failed to acknowledge id: ") + pulsar_result_str(result));
|
|
320
|
+
} else {
|
|
321
|
+
deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
ctx);
|
|
325
|
+
|
|
326
|
+
return deferred->Promise();
|
|
275
327
|
}
|
|
276
328
|
|
|
277
329
|
void Consumer::NegativeAcknowledge(const Napi::CallbackInfo &info) {
|
|
278
330
|
Napi::Object obj = info[0].As<Napi::Object>();
|
|
279
331
|
Message *msg = Message::Unwrap(obj);
|
|
280
|
-
|
|
332
|
+
std::shared_ptr<pulsar_message_t> cMessage = msg->GetCMessage();
|
|
333
|
+
pulsar_consumer_negative_acknowledge(this->cConsumer.get(), cMessage.get());
|
|
281
334
|
}
|
|
282
335
|
|
|
283
336
|
void Consumer::NegativeAcknowledgeId(const Napi::CallbackInfo &info) {
|
|
284
337
|
Napi::Object obj = info[0].As<Napi::Object>();
|
|
285
338
|
MessageId *msgId = MessageId::Unwrap(obj);
|
|
286
|
-
|
|
339
|
+
std::shared_ptr<pulsar_message_id_t> cMessageId = msgId->GetCMessageId();
|
|
340
|
+
pulsar_consumer_negative_acknowledge_id(this->cConsumer.get(), cMessageId.get());
|
|
287
341
|
}
|
|
288
342
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
343
|
+
Napi::Value Consumer::AcknowledgeCumulative(const Napi::CallbackInfo &info) {
|
|
344
|
+
auto obj = info[0].As<Napi::Object>();
|
|
345
|
+
auto *msg = Message::Unwrap(obj);
|
|
346
|
+
auto deferred = ThreadSafeDeferred::New(Env());
|
|
347
|
+
auto ctx = new ExtDeferredContext(deferred);
|
|
348
|
+
|
|
349
|
+
pulsar_consumer_acknowledge_cumulative_async(
|
|
350
|
+
this->cConsumer.get(), msg->GetCMessage().get(),
|
|
351
|
+
[](pulsar_result result, void *ctx) {
|
|
352
|
+
auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
|
|
353
|
+
auto deferred = deferredContext->deferred;
|
|
354
|
+
delete deferredContext;
|
|
355
|
+
|
|
356
|
+
if (result != pulsar_result_Ok) {
|
|
357
|
+
deferred->Reject(std::string("Failed to acknowledge cumulatively: ") + pulsar_result_str(result));
|
|
358
|
+
} else {
|
|
359
|
+
deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
ctx);
|
|
363
|
+
|
|
364
|
+
return deferred->Promise();
|
|
293
365
|
}
|
|
294
366
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
367
|
+
Napi::Value Consumer::AcknowledgeCumulativeId(const Napi::CallbackInfo &info) {
|
|
368
|
+
auto obj = info[0].As<Napi::Object>();
|
|
369
|
+
auto *msgId = MessageId::Unwrap(obj);
|
|
370
|
+
auto deferred = ThreadSafeDeferred::New(Env());
|
|
371
|
+
auto ctx = new ExtDeferredContext(deferred);
|
|
372
|
+
|
|
373
|
+
pulsar_consumer_acknowledge_cumulative_async_id(
|
|
374
|
+
this->cConsumer.get(), msgId->GetCMessageId().get(),
|
|
375
|
+
[](pulsar_result result, void *ctx) {
|
|
376
|
+
auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
|
|
377
|
+
auto deferred = deferredContext->deferred;
|
|
378
|
+
delete deferredContext;
|
|
379
|
+
|
|
380
|
+
if (result != pulsar_result_Ok) {
|
|
381
|
+
deferred->Reject(std::string("Failed to acknowledge cumulatively by id: ") +
|
|
382
|
+
pulsar_result_str(result));
|
|
383
|
+
} else {
|
|
384
|
+
deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
ctx);
|
|
388
|
+
|
|
389
|
+
return deferred->Promise();
|
|
300
390
|
}
|
|
301
391
|
|
|
302
|
-
Napi::Value Consumer::
|
|
303
|
-
|
|
304
|
-
|
|
392
|
+
Napi::Value Consumer::Seek(const Napi::CallbackInfo &info) {
|
|
393
|
+
auto obj = info[0].As<Napi::Object>();
|
|
394
|
+
auto *msgId = MessageId::Unwrap(obj);
|
|
395
|
+
auto deferred = ThreadSafeDeferred::New(Env());
|
|
396
|
+
auto ctx = new ExtDeferredContext(deferred);
|
|
397
|
+
|
|
398
|
+
pulsar_consumer_seek_async(
|
|
399
|
+
this->cConsumer.get(), msgId->GetCMessageId().get(),
|
|
400
|
+
[](pulsar_result result, void *ctx) {
|
|
401
|
+
auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
|
|
402
|
+
auto deferred = deferredContext->deferred;
|
|
403
|
+
delete deferredContext;
|
|
404
|
+
|
|
405
|
+
if (result != pulsar_result_Ok) {
|
|
406
|
+
deferred->Reject(std::string("Failed to seek message by id: ") + pulsar_result_str(result));
|
|
407
|
+
} else {
|
|
408
|
+
deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
ctx);
|
|
412
|
+
|
|
413
|
+
return deferred->Promise();
|
|
305
414
|
}
|
|
306
415
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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
|
-
}
|
|
416
|
+
Napi::Value Consumer::SeekTimestamp(const Napi::CallbackInfo &info) {
|
|
417
|
+
Napi::Number timestamp = info[0].As<Napi::Object>().ToNumber();
|
|
418
|
+
auto deferred = ThreadSafeDeferred::New(Env());
|
|
419
|
+
auto ctx = new ExtDeferredContext(deferred);
|
|
420
|
+
|
|
421
|
+
pulsar_consumer_seek_by_timestamp_async(
|
|
422
|
+
this->cConsumer.get(), timestamp.Int64Value(),
|
|
423
|
+
[](pulsar_result result, void *ctx) {
|
|
424
|
+
auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
|
|
425
|
+
auto deferred = deferredContext->deferred;
|
|
426
|
+
delete deferredContext;
|
|
427
|
+
|
|
428
|
+
if (result != pulsar_result_Ok) {
|
|
429
|
+
deferred->Reject(std::string("Failed to seek message by timestamp: ") + pulsar_result_str(result));
|
|
430
|
+
} else {
|
|
431
|
+
deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
ctx);
|
|
435
|
+
|
|
436
|
+
return deferred->Promise();
|
|
437
|
+
}
|
|
364
438
|
|
|
365
|
-
|
|
366
|
-
Napi::
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
};
|
|
439
|
+
Napi::Value Consumer::IsConnected(const Napi::CallbackInfo &info) {
|
|
440
|
+
Napi::Env env = info.Env();
|
|
441
|
+
return Napi::Boolean::New(env, pulsar_consumer_is_connected(this->cConsumer.get()));
|
|
442
|
+
}
|
|
370
443
|
|
|
371
444
|
void Consumer::Cleanup() {
|
|
372
|
-
if (this->listener) {
|
|
373
|
-
this->
|
|
445
|
+
if (this->listener != nullptr) {
|
|
446
|
+
pulsar_consumer_pause_message_listener(this->cConsumer.get());
|
|
447
|
+
this->listener->callback.Release();
|
|
448
|
+
this->listener = nullptr;
|
|
449
|
+
this->Unref();
|
|
374
450
|
}
|
|
375
451
|
}
|
|
376
452
|
|
|
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
453
|
Napi::Value Consumer::Close(const Napi::CallbackInfo &info) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
454
|
+
auto deferred = ThreadSafeDeferred::New(Env());
|
|
455
|
+
auto ctx = new ExtDeferredContext(deferred);
|
|
456
|
+
this->Cleanup();
|
|
457
|
+
|
|
458
|
+
pulsar_consumer_close_async(
|
|
459
|
+
this->cConsumer.get(),
|
|
460
|
+
[](pulsar_result result, void *ctx) {
|
|
461
|
+
auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
|
|
462
|
+
auto deferred = deferredContext->deferred;
|
|
463
|
+
delete deferredContext;
|
|
464
|
+
|
|
465
|
+
if (result != pulsar_result_Ok) {
|
|
466
|
+
deferred->Reject(std::string("Failed to close consumer: ") + pulsar_result_str(result));
|
|
467
|
+
} else {
|
|
468
|
+
deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
|
|
469
|
+
}
|
|
470
|
+
},
|
|
471
|
+
ctx);
|
|
472
|
+
|
|
473
|
+
return deferred->Promise();
|
|
389
474
|
}
|
|
390
475
|
|
|
391
476
|
Napi::Value Consumer::Unsubscribe(const Napi::CallbackInfo &info) {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
477
|
+
auto deferred = ThreadSafeDeferred::New(Env());
|
|
478
|
+
auto ctx = new ExtDeferredContext(deferred);
|
|
479
|
+
|
|
480
|
+
pulsar_consumer_pause_message_listener(this->cConsumer.get());
|
|
481
|
+
pulsar_consumer_unsubscribe_async(
|
|
482
|
+
this->cConsumer.get(),
|
|
483
|
+
[](pulsar_result result, void *ctx) {
|
|
484
|
+
auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
|
|
485
|
+
auto deferred = deferredContext->deferred;
|
|
486
|
+
delete deferredContext;
|
|
487
|
+
|
|
488
|
+
if (result != pulsar_result_Ok) {
|
|
489
|
+
deferred->Reject(std::string("Failed to unsubscribe consumer: ") + pulsar_result_str(result));
|
|
490
|
+
} else {
|
|
491
|
+
deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
|
|
492
|
+
}
|
|
493
|
+
},
|
|
494
|
+
ctx);
|
|
495
|
+
|
|
496
|
+
return deferred->Promise();
|
|
396
497
|
}
|
|
397
498
|
|
|
398
|
-
Consumer::~Consumer() {
|
|
399
|
-
if (this->listener) {
|
|
400
|
-
this->CleanupListener();
|
|
401
|
-
}
|
|
402
|
-
}
|
|
499
|
+
Consumer::~Consumer() { this->Cleanup(); }
|