pulsar-client 1.6.2 → 1.8.0-rc.1
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 +85 -0
- package/.github/workflows/ci-build-release-napi.yml +213 -0
- package/.github/workflows/ci-pr-validation.yml +233 -0
- package/README.md +91 -68
- package/binding.gyp +48 -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/{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 +271 -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 +16 -13
- package/pkg/linux/Dockerfile_linux_glibc +35 -0
- package/pkg/linux/Dockerfile_linux_musl +32 -0
- package/pkg/linux/build-napi-inside-docker.sh +31 -0
- package/pkg/linux/download-cpp-client.sh +65 -0
- package/pkg/load_test.js +34 -0
- package/pkg/mac/build-cpp-deps-lib.sh +186 -0
- package/pkg/mac/build-cpp-lib.sh +48 -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 +26 -0
- package/tests/conf/standalone.conf +6 -0
- package/tests/consumer.test.js +2 -2
- package/tests/docker-load-test.sh +35 -0
- package/tests/end_to_end.test.js +214 -2
- package/tests/load-test.sh +43 -0
- package/tests/producer.test.js +2 -2
- package/{run-unit-tests.sh → tests/run-unit-tests.sh} +6 -15
- package/pulsar-version.txt +0 -1
package/src/Reader.cc
CHANGED
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
#include "Message.h"
|
|
21
21
|
#include "Reader.h"
|
|
22
22
|
#include "ReaderConfig.h"
|
|
23
|
+
#include "MessageId.h"
|
|
24
|
+
#include "ThreadSafeDeferred.h"
|
|
23
25
|
#include <pulsar/c/result.h>
|
|
24
26
|
#include <pulsar/c/reader.h>
|
|
25
27
|
#include <atomic>
|
|
@@ -35,6 +37,8 @@ void Reader::Init(Napi::Env env, Napi::Object exports) {
|
|
|
35
37
|
InstanceMethod("readNext", &Reader::ReadNext),
|
|
36
38
|
InstanceMethod("hasNext", &Reader::HasNext),
|
|
37
39
|
InstanceMethod("isConnected", &Reader::IsConnected),
|
|
40
|
+
InstanceMethod("seek", &Reader::Seek),
|
|
41
|
+
InstanceMethod("seekTimestamp", &Reader::SeekTimestamp),
|
|
38
42
|
InstanceMethod("close", &Reader::Close),
|
|
39
43
|
});
|
|
40
44
|
|
|
@@ -43,10 +47,11 @@ void Reader::Init(Napi::Env env, Napi::Object exports) {
|
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
struct ReaderListenerProxyData {
|
|
46
|
-
pulsar_message_t
|
|
50
|
+
std::shared_ptr<pulsar_message_t> cMessage;
|
|
47
51
|
Reader *reader;
|
|
48
52
|
|
|
49
|
-
ReaderListenerProxyData(pulsar_message_t
|
|
53
|
+
ReaderListenerProxyData(std::shared_ptr<pulsar_message_t> cMessage, Reader *reader)
|
|
54
|
+
: cMessage(cMessage), reader(reader) {}
|
|
50
55
|
};
|
|
51
56
|
|
|
52
57
|
void ReaderListenerProxy(Napi::Env env, Napi::Function jsCallback, ReaderListenerProxyData *data) {
|
|
@@ -57,7 +62,8 @@ void ReaderListenerProxy(Napi::Env env, Napi::Function jsCallback, ReaderListene
|
|
|
57
62
|
jsCallback.Call({msg, reader->Value()});
|
|
58
63
|
}
|
|
59
64
|
|
|
60
|
-
void ReaderListener(pulsar_reader_t *
|
|
65
|
+
void ReaderListener(pulsar_reader_t *rawReader, pulsar_message_t *rawMessage, void *ctx) {
|
|
66
|
+
std::shared_ptr<pulsar_message_t> cMessage(rawMessage, pulsar_message_free);
|
|
61
67
|
ReaderListenerCallback *readerListenerCallback = (ReaderListenerCallback *)ctx;
|
|
62
68
|
Reader *reader = (Reader *)readerListenerCallback->reader;
|
|
63
69
|
if (readerListenerCallback->callback.Acquire() != napi_ok) {
|
|
@@ -68,101 +74,85 @@ void ReaderListener(pulsar_reader_t *cReader, pulsar_message_t *cMessage, void *
|
|
|
68
74
|
readerListenerCallback->callback.Release();
|
|
69
75
|
}
|
|
70
76
|
|
|
71
|
-
void Reader::SetCReader(std::shared_ptr<
|
|
77
|
+
void Reader::SetCReader(std::shared_ptr<pulsar_reader_t> cReader) { this->cReader = cReader; }
|
|
72
78
|
void Reader::SetListenerCallback(ReaderListenerCallback *listener) {
|
|
73
|
-
if (listener) {
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
if (this->listener != nullptr) {
|
|
80
|
+
// It is only safe to set the listener once for the lifecycle of the Reader
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
77
83
|
|
|
78
|
-
|
|
84
|
+
if (listener != nullptr) {
|
|
79
85
|
listener->reader = this;
|
|
86
|
+
// If a reader listener is set, the Reader instance is kept alive even if it goes out of scope in JS code.
|
|
87
|
+
this->Ref();
|
|
88
|
+
this->listener = listener;
|
|
80
89
|
}
|
|
81
|
-
|
|
82
|
-
this->listener = listener;
|
|
83
90
|
}
|
|
84
91
|
|
|
85
92
|
Reader::Reader(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Reader>(info), listener(nullptr) {}
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
:
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
SetError(msg);
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
if (this->readerConfig->GetCStartMessageId() == nullptr) {
|
|
106
|
-
std::string msg(
|
|
107
|
-
"StartMessageId is required and must be specified as a MessageId object when creating reader");
|
|
108
|
-
SetError(msg);
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
pulsar_client_create_reader_async(this->cClient, topic.c_str(), this->readerConfig->GetCStartMessageId(),
|
|
113
|
-
this->readerConfig->GetCReaderConfig(),
|
|
114
|
-
&ReaderNewInstanceWorker::createReaderCallback, (void *)this);
|
|
115
|
-
|
|
116
|
-
while (!done) {
|
|
117
|
-
std::this_thread::yield();
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
void OnOK() {
|
|
121
|
-
Napi::Object obj = Reader::constructor.New({});
|
|
122
|
-
Reader *reader = Reader::Unwrap(obj);
|
|
123
|
-
reader->SetCReader(this->readerWrapper);
|
|
124
|
-
reader->SetListenerCallback(this->listener);
|
|
125
|
-
this->deferred.Resolve(obj);
|
|
126
|
-
}
|
|
127
|
-
void OnError(const Napi::Error &e) { this->deferred.Reject(Napi::Error::New(Env(), e.Message()).Value()); }
|
|
94
|
+
struct ReaderNewInstanceContext {
|
|
95
|
+
ReaderNewInstanceContext(std::shared_ptr<ThreadSafeDeferred> deferred,
|
|
96
|
+
std::shared_ptr<pulsar_client_t> cClient,
|
|
97
|
+
std::shared_ptr<ReaderConfig> readerConfig)
|
|
98
|
+
: deferred(deferred), cClient(cClient), readerConfig(readerConfig){};
|
|
99
|
+
std::shared_ptr<ThreadSafeDeferred> deferred;
|
|
100
|
+
std::shared_ptr<pulsar_client_t> cClient;
|
|
101
|
+
std::shared_ptr<ReaderConfig> readerConfig;
|
|
102
|
+
|
|
103
|
+
static void createReaderCallback(pulsar_result result, pulsar_reader_t *rawReader, void *ctx) {
|
|
104
|
+
auto instanceContext = static_cast<ReaderNewInstanceContext *>(ctx);
|
|
105
|
+
auto deferred = instanceContext->deferred;
|
|
106
|
+
auto cClient = instanceContext->cClient;
|
|
107
|
+
auto readerConfig = instanceContext->readerConfig;
|
|
108
|
+
delete instanceContext;
|
|
128
109
|
|
|
129
|
-
private:
|
|
130
|
-
Napi::Promise::Deferred deferred;
|
|
131
|
-
pulsar_client_t *cClient;
|
|
132
|
-
pulsar_reader_t *cReader;
|
|
133
|
-
ReaderConfig *readerConfig;
|
|
134
|
-
ReaderListenerCallback *listener;
|
|
135
|
-
std::shared_ptr<CReaderWrapper> readerWrapper;
|
|
136
|
-
std::atomic<bool> done;
|
|
137
|
-
static void createReaderCallback(pulsar_result result, pulsar_reader_t *reader, void *ctx) {
|
|
138
|
-
ReaderNewInstanceWorker *worker = (ReaderNewInstanceWorker *)ctx;
|
|
139
110
|
if (result != pulsar_result_Ok) {
|
|
140
|
-
|
|
141
|
-
} else {
|
|
142
|
-
worker->readerWrapper->cReader = reader;
|
|
143
|
-
worker->listener = worker->readerConfig->GetListenerCallback();
|
|
111
|
+
return deferred->Reject(std::string("Failed to create reader: ") + pulsar_result_str(result));
|
|
144
112
|
}
|
|
145
113
|
|
|
146
|
-
|
|
147
|
-
|
|
114
|
+
auto cReader = std::shared_ptr<pulsar_reader_t>(rawReader, pulsar_reader_free);
|
|
115
|
+
|
|
116
|
+
deferred->Resolve([cReader, readerConfig](const Napi::Env env) {
|
|
117
|
+
Napi::Object obj = Reader::constructor.New({});
|
|
118
|
+
Reader *reader = Reader::Unwrap(obj);
|
|
119
|
+
reader->SetCReader(cReader);
|
|
120
|
+
reader->SetListenerCallback(readerConfig->GetListenerCallback());
|
|
121
|
+
return obj;
|
|
122
|
+
});
|
|
148
123
|
}
|
|
149
124
|
};
|
|
150
125
|
|
|
151
|
-
Napi::Value Reader::NewInstance(const Napi::CallbackInfo &info, pulsar_client_t
|
|
152
|
-
|
|
126
|
+
Napi::Value Reader::NewInstance(const Napi::CallbackInfo &info, std::shared_ptr<pulsar_client_t> cClient) {
|
|
127
|
+
auto deferred = ThreadSafeDeferred::New(info.Env());
|
|
153
128
|
Napi::Object config = info[0].As<Napi::Object>();
|
|
154
129
|
|
|
155
|
-
|
|
130
|
+
auto readerConfig = std::make_shared<ReaderConfig>(config, &ReaderListener);
|
|
156
131
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
132
|
+
const std::string &topic = readerConfig->GetTopic();
|
|
133
|
+
if (topic.empty()) {
|
|
134
|
+
deferred->Reject(std::string("Topic is required and must be specified as a string when creating reader"));
|
|
135
|
+
return deferred->Promise();
|
|
136
|
+
}
|
|
137
|
+
if (readerConfig->GetCStartMessageId().get() == nullptr) {
|
|
138
|
+
deferred->Reject(std::string(
|
|
139
|
+
"StartMessageId is required and must be specified as a MessageId object when creating reader"));
|
|
140
|
+
return deferred->Promise();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
auto ctx = new ReaderNewInstanceContext(deferred, cClient, readerConfig);
|
|
144
|
+
|
|
145
|
+
pulsar_client_create_reader_async(cClient.get(), topic.c_str(), readerConfig->GetCStartMessageId().get(),
|
|
146
|
+
readerConfig->GetCReaderConfig().get(),
|
|
147
|
+
&ReaderNewInstanceContext::createReaderCallback, ctx);
|
|
148
|
+
|
|
149
|
+
return deferred->Promise();
|
|
161
150
|
}
|
|
162
151
|
|
|
152
|
+
// We still need a read worker because the c api is missing the equivalent async definition
|
|
163
153
|
class ReaderReadNextWorker : public Napi::AsyncWorker {
|
|
164
154
|
public:
|
|
165
|
-
ReaderReadNextWorker(const Napi::Promise::Deferred &deferred, pulsar_reader_t
|
|
155
|
+
ReaderReadNextWorker(const Napi::Promise::Deferred &deferred, std::shared_ptr<pulsar_reader_t> cReader,
|
|
166
156
|
int64_t timeout = -1)
|
|
167
157
|
: AsyncWorker(Napi::Function::New(deferred.Promise().Env(), [](const Napi::CallbackInfo &info) {})),
|
|
168
158
|
deferred(deferred),
|
|
@@ -171,14 +161,16 @@ class ReaderReadNextWorker : public Napi::AsyncWorker {
|
|
|
171
161
|
~ReaderReadNextWorker() {}
|
|
172
162
|
void Execute() {
|
|
173
163
|
pulsar_result result;
|
|
164
|
+
pulsar_message_t *rawMessage;
|
|
174
165
|
if (timeout > 0) {
|
|
175
|
-
result = pulsar_reader_read_next_with_timeout(this->cReader, &
|
|
166
|
+
result = pulsar_reader_read_next_with_timeout(this->cReader.get(), &rawMessage, timeout);
|
|
176
167
|
} else {
|
|
177
|
-
result = pulsar_reader_read_next(this->cReader, &
|
|
168
|
+
result = pulsar_reader_read_next(this->cReader.get(), &rawMessage);
|
|
178
169
|
}
|
|
179
170
|
if (result != pulsar_result_Ok) {
|
|
180
|
-
SetError(std::string("Failed to
|
|
171
|
+
SetError(std::string("Failed to receive message: ") + pulsar_result_str(result));
|
|
181
172
|
}
|
|
173
|
+
this->cMessage = std::shared_ptr<pulsar_message_t>(rawMessage, pulsar_message_free);
|
|
182
174
|
}
|
|
183
175
|
void OnOK() {
|
|
184
176
|
Napi::Object obj = Message::NewInstance({}, this->cMessage);
|
|
@@ -188,20 +180,19 @@ class ReaderReadNextWorker : public Napi::AsyncWorker {
|
|
|
188
180
|
|
|
189
181
|
private:
|
|
190
182
|
Napi::Promise::Deferred deferred;
|
|
191
|
-
pulsar_reader_t
|
|
192
|
-
pulsar_message_t
|
|
183
|
+
std::shared_ptr<pulsar_reader_t> cReader;
|
|
184
|
+
std::shared_ptr<pulsar_message_t> cMessage;
|
|
193
185
|
int64_t timeout;
|
|
194
186
|
};
|
|
195
187
|
|
|
196
188
|
Napi::Value Reader::ReadNext(const Napi::CallbackInfo &info) {
|
|
197
189
|
Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(info.Env());
|
|
198
190
|
if (info[0].IsUndefined()) {
|
|
199
|
-
ReaderReadNextWorker *wk = new ReaderReadNextWorker(deferred, this->
|
|
191
|
+
ReaderReadNextWorker *wk = new ReaderReadNextWorker(deferred, this->cReader);
|
|
200
192
|
wk->Queue();
|
|
201
193
|
} else {
|
|
202
194
|
Napi::Number timeout = info[0].As<Napi::Object>().ToNumber();
|
|
203
|
-
ReaderReadNextWorker *wk =
|
|
204
|
-
new ReaderReadNextWorker(deferred, this->wrapper->cReader, timeout.Int64Value());
|
|
195
|
+
ReaderReadNextWorker *wk = new ReaderReadNextWorker(deferred, this->cReader, timeout.Int64Value());
|
|
205
196
|
wk->Queue();
|
|
206
197
|
}
|
|
207
198
|
return deferred.Promise();
|
|
@@ -209,7 +200,7 @@ Napi::Value Reader::ReadNext(const Napi::CallbackInfo &info) {
|
|
|
209
200
|
|
|
210
201
|
Napi::Value Reader::HasNext(const Napi::CallbackInfo &info) {
|
|
211
202
|
int value = 0;
|
|
212
|
-
pulsar_result result = pulsar_reader_has_message_available(this->
|
|
203
|
+
pulsar_result result = pulsar_reader_has_message_available(this->cReader.get(), &value);
|
|
213
204
|
if (result != pulsar_result_Ok) {
|
|
214
205
|
Napi::Error::New(info.Env(), "Failed to check if next message is available").ThrowAsJavaScriptException();
|
|
215
206
|
return Napi::Boolean::New(info.Env(), false);
|
|
@@ -222,57 +213,85 @@ Napi::Value Reader::HasNext(const Napi::CallbackInfo &info) {
|
|
|
222
213
|
|
|
223
214
|
Napi::Value Reader::IsConnected(const Napi::CallbackInfo &info) {
|
|
224
215
|
Napi::Env env = info.Env();
|
|
225
|
-
return Napi::Boolean::New(env, pulsar_reader_is_connected(this->
|
|
216
|
+
return Napi::Boolean::New(env, pulsar_reader_is_connected(this->cReader.get()));
|
|
226
217
|
}
|
|
227
218
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
219
|
+
Napi::Value Reader::Seek(const Napi::CallbackInfo &info) {
|
|
220
|
+
auto obj = info[0].As<Napi::Object>();
|
|
221
|
+
auto *msgId = MessageId::Unwrap(obj);
|
|
222
|
+
auto deferred = ThreadSafeDeferred::New(Env());
|
|
223
|
+
auto ctx = new ExtDeferredContext(deferred);
|
|
224
|
+
|
|
225
|
+
pulsar_reader_seek_async(
|
|
226
|
+
this->cReader.get(), msgId->GetCMessageId().get(),
|
|
227
|
+
[](pulsar_result result, void *ctx) {
|
|
228
|
+
auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
|
|
229
|
+
auto deferred = deferredContext->deferred;
|
|
230
|
+
delete deferredContext;
|
|
231
|
+
|
|
232
|
+
if (result != pulsar_result_Ok) {
|
|
233
|
+
deferred->Reject(std::string("Failed to seek message by id: ") + pulsar_result_str(result));
|
|
234
|
+
} else {
|
|
235
|
+
deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
ctx);
|
|
239
|
+
|
|
240
|
+
return deferred->Promise();
|
|
241
|
+
}
|
|
248
242
|
|
|
249
|
-
|
|
250
|
-
Napi::
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
243
|
+
Napi::Value Reader::SeekTimestamp(const Napi::CallbackInfo &info) {
|
|
244
|
+
Napi::Number timestamp = info[0].As<Napi::Object>().ToNumber();
|
|
245
|
+
auto deferred = ThreadSafeDeferred::New(Env());
|
|
246
|
+
auto ctx = new ExtDeferredContext(deferred);
|
|
247
|
+
|
|
248
|
+
pulsar_reader_seek_by_timestamp_async(
|
|
249
|
+
this->cReader.get(), timestamp.Int64Value(),
|
|
250
|
+
[](pulsar_result result, void *ctx) {
|
|
251
|
+
auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
|
|
252
|
+
auto deferred = deferredContext->deferred;
|
|
253
|
+
delete deferredContext;
|
|
254
|
+
|
|
255
|
+
if (result != pulsar_result_Ok) {
|
|
256
|
+
deferred->Reject(std::string("Failed to seek message by timestamp: ") + pulsar_result_str(result));
|
|
257
|
+
} else {
|
|
258
|
+
deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
ctx);
|
|
262
|
+
|
|
263
|
+
return deferred->Promise();
|
|
264
|
+
}
|
|
254
265
|
|
|
255
266
|
Napi::Value Reader::Close(const Napi::CallbackInfo &info) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
267
|
+
auto deferred = ThreadSafeDeferred::New(Env());
|
|
268
|
+
auto ctx = new ExtDeferredContext(deferred);
|
|
269
|
+
this->Cleanup();
|
|
270
|
+
|
|
271
|
+
pulsar_reader_close_async(
|
|
272
|
+
this->cReader.get(),
|
|
273
|
+
[](pulsar_result result, void *ctx) {
|
|
274
|
+
auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
|
|
275
|
+
auto deferred = deferredContext->deferred;
|
|
276
|
+
delete deferredContext;
|
|
277
|
+
|
|
278
|
+
if (result != pulsar_result_Ok) {
|
|
279
|
+
deferred->Reject(std::string("Failed to close reader: ") + pulsar_result_str(result));
|
|
280
|
+
} else {
|
|
281
|
+
deferred->Resolve(THREADSAFE_DEFERRED_RESOLVER(env.Null()));
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
ctx);
|
|
285
|
+
|
|
286
|
+
return deferred->Promise();
|
|
260
287
|
}
|
|
261
288
|
|
|
262
289
|
void Reader::Cleanup() {
|
|
263
|
-
if (this->listener) {
|
|
264
|
-
this->
|
|
290
|
+
if (this->listener != nullptr) {
|
|
291
|
+
this->listener->callback.Release();
|
|
292
|
+
this->Unref();
|
|
293
|
+
this->listener = nullptr;
|
|
265
294
|
}
|
|
266
295
|
}
|
|
267
296
|
|
|
268
|
-
|
|
269
|
-
this->Unref();
|
|
270
|
-
this->listener->callback.Release();
|
|
271
|
-
this->listener = nullptr;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
Reader::~Reader() {
|
|
275
|
-
if (this->listener) {
|
|
276
|
-
this->CleanupListener();
|
|
277
|
-
}
|
|
278
|
-
}
|
|
297
|
+
Reader::~Reader() { this->Cleanup(); }
|
package/src/Reader.h
CHANGED
|
@@ -27,21 +27,23 @@
|
|
|
27
27
|
class Reader : public Napi::ObjectWrap<Reader> {
|
|
28
28
|
public:
|
|
29
29
|
static void Init(Napi::Env env, Napi::Object exports);
|
|
30
|
-
static Napi::Value NewInstance(const Napi::CallbackInfo &info, pulsar_client_t
|
|
30
|
+
static Napi::Value NewInstance(const Napi::CallbackInfo &info, std::shared_ptr<pulsar_client_t> cClient);
|
|
31
31
|
static Napi::FunctionReference constructor;
|
|
32
32
|
Reader(const Napi::CallbackInfo &info);
|
|
33
33
|
~Reader();
|
|
34
|
-
void SetCReader(std::shared_ptr<
|
|
34
|
+
void SetCReader(std::shared_ptr<pulsar_reader_t> cReader);
|
|
35
35
|
void SetListenerCallback(ReaderListenerCallback *listener);
|
|
36
36
|
void Cleanup();
|
|
37
37
|
|
|
38
38
|
private:
|
|
39
|
-
std::shared_ptr<
|
|
39
|
+
std::shared_ptr<pulsar_reader_t> cReader;
|
|
40
40
|
ReaderListenerCallback *listener;
|
|
41
41
|
|
|
42
42
|
Napi::Value ReadNext(const Napi::CallbackInfo &info);
|
|
43
43
|
Napi::Value HasNext(const Napi::CallbackInfo &info);
|
|
44
44
|
Napi::Value IsConnected(const Napi::CallbackInfo &info);
|
|
45
|
+
Napi::Value Seek(const Napi::CallbackInfo &info);
|
|
46
|
+
Napi::Value SeekTimestamp(const Napi::CallbackInfo &info);
|
|
45
47
|
Napi::Value Close(const Napi::CallbackInfo &info);
|
|
46
48
|
void CleanupListener();
|
|
47
49
|
};
|
package/src/ReaderConfig.cc
CHANGED
|
@@ -31,10 +31,10 @@ static const std::string CFG_LISTENER = "listener";
|
|
|
31
31
|
|
|
32
32
|
void FinalizeListenerCallback(Napi::Env env, ReaderListenerCallback *cb, void *) { delete cb; }
|
|
33
33
|
|
|
34
|
-
ReaderConfig::ReaderConfig(const Napi::Object &readerConfig,
|
|
35
|
-
pulsar_reader_listener readerListener)
|
|
34
|
+
ReaderConfig::ReaderConfig(const Napi::Object &readerConfig, pulsar_reader_listener readerListener)
|
|
36
35
|
: topic(""), cStartMessageId(NULL), listener(nullptr) {
|
|
37
|
-
this->cReaderConfig = pulsar_reader_configuration_create()
|
|
36
|
+
this->cReaderConfig = std::shared_ptr<pulsar_reader_configuration_t>(pulsar_reader_configuration_create(),
|
|
37
|
+
pulsar_reader_configuration_free);
|
|
38
38
|
|
|
39
39
|
if (readerConfig.Has(CFG_TOPIC) && readerConfig.Get(CFG_TOPIC).IsString()) {
|
|
40
40
|
this->topic = readerConfig.Get(CFG_TOPIC).ToString().Utf8Value();
|
|
@@ -48,14 +48,14 @@ ReaderConfig::ReaderConfig(const Napi::Object &readerConfig, std::shared_ptr<CRe
|
|
|
48
48
|
if (readerConfig.Has(CFG_RECV_QUEUE) && readerConfig.Get(CFG_RECV_QUEUE).IsNumber()) {
|
|
49
49
|
int32_t receiverQueueSize = readerConfig.Get(CFG_RECV_QUEUE).ToNumber().Int32Value();
|
|
50
50
|
if (receiverQueueSize >= 0) {
|
|
51
|
-
pulsar_reader_configuration_set_receiver_queue_size(this->cReaderConfig, receiverQueueSize);
|
|
51
|
+
pulsar_reader_configuration_set_receiver_queue_size(this->cReaderConfig.get(), receiverQueueSize);
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
if (readerConfig.Has(CFG_READER_NAME) && readerConfig.Get(CFG_READER_NAME).IsString()) {
|
|
56
56
|
std::string readerName = readerConfig.Get(CFG_READER_NAME).ToString().Utf8Value();
|
|
57
57
|
if (!readerName.empty())
|
|
58
|
-
pulsar_reader_configuration_set_reader_name(this->cReaderConfig, readerName.c_str());
|
|
58
|
+
pulsar_reader_configuration_set_reader_name(this->cReaderConfig.get(), readerName.c_str());
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
if (readerConfig.Has(CFG_SUBSCRIPTION_ROLE_PREFIX) &&
|
|
@@ -63,13 +63,13 @@ ReaderConfig::ReaderConfig(const Napi::Object &readerConfig, std::shared_ptr<CRe
|
|
|
63
63
|
std::string subscriptionRolePrefix =
|
|
64
64
|
readerConfig.Get(CFG_SUBSCRIPTION_ROLE_PREFIX).ToString().Utf8Value();
|
|
65
65
|
if (!subscriptionRolePrefix.empty())
|
|
66
|
-
pulsar_reader_configuration_set_reader_name(this->cReaderConfig, subscriptionRolePrefix.c_str());
|
|
66
|
+
pulsar_reader_configuration_set_reader_name(this->cReaderConfig.get(), subscriptionRolePrefix.c_str());
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
if (readerConfig.Has(CFG_READ_COMPACTED) && readerConfig.Get(CFG_READ_COMPACTED).IsBoolean()) {
|
|
70
70
|
bool readCompacted = readerConfig.Get(CFG_READ_COMPACTED).ToBoolean();
|
|
71
71
|
if (readCompacted) {
|
|
72
|
-
pulsar_reader_configuration_set_read_compacted(this->cReaderConfig, 1);
|
|
72
|
+
pulsar_reader_configuration_set_read_compacted(this->cReaderConfig.get(), 1);
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -79,33 +79,27 @@ ReaderConfig::ReaderConfig(const Napi::Object &readerConfig, std::shared_ptr<CRe
|
|
|
79
79
|
readerConfig.Env(), readerConfig.Get(CFG_LISTENER).As<Napi::Function>(), "Reader Listener Callback",
|
|
80
80
|
1, 1, (void *)NULL, FinalizeListenerCallback, listener);
|
|
81
81
|
this->listener->callback = std::move(callback);
|
|
82
|
-
pulsar_reader_configuration_set_reader_listener(this->cReaderConfig, readerListener,
|
|
82
|
+
pulsar_reader_configuration_set_reader_listener(this->cReaderConfig.get(), readerListener,
|
|
83
|
+
this->listener);
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
ReaderConfig::~ReaderConfig() {
|
|
87
|
-
|
|
88
|
-
if (this->listener) {
|
|
88
|
+
if (this->listener != nullptr) {
|
|
89
89
|
this->listener->callback.Release();
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
pulsar_reader_configuration_t
|
|
93
|
+
std::shared_ptr<pulsar_reader_configuration_t> ReaderConfig::GetCReaderConfig() {
|
|
94
|
+
return this->cReaderConfig;
|
|
95
|
+
}
|
|
94
96
|
|
|
95
97
|
std::string ReaderConfig::GetTopic() { return this->topic; }
|
|
96
98
|
|
|
97
|
-
pulsar_message_id_t
|
|
99
|
+
std::shared_ptr<pulsar_message_id_t> ReaderConfig::GetCStartMessageId() { return this->cStartMessageId; }
|
|
98
100
|
|
|
99
101
|
ReaderListenerCallback *ReaderConfig::GetListenerCallback() {
|
|
100
102
|
ReaderListenerCallback *cb = this->listener;
|
|
101
103
|
this->listener = nullptr;
|
|
102
104
|
return cb;
|
|
103
105
|
}
|
|
104
|
-
|
|
105
|
-
CReaderWrapper::CReaderWrapper() : cReader(nullptr) {}
|
|
106
|
-
|
|
107
|
-
CReaderWrapper::~CReaderWrapper() {
|
|
108
|
-
if (this->cReader) {
|
|
109
|
-
pulsar_reader_free(this->cReader);
|
|
110
|
-
}
|
|
111
|
-
}
|
package/src/ReaderConfig.h
CHANGED
|
@@ -28,18 +28,17 @@
|
|
|
28
28
|
|
|
29
29
|
class ReaderConfig {
|
|
30
30
|
public:
|
|
31
|
-
ReaderConfig(const Napi::Object &readerConfig,
|
|
32
|
-
pulsar_reader_listener readerListener);
|
|
31
|
+
ReaderConfig(const Napi::Object &readerConfig, pulsar_reader_listener readerListener);
|
|
33
32
|
~ReaderConfig();
|
|
34
|
-
pulsar_reader_configuration_t
|
|
35
|
-
pulsar_message_id_t
|
|
33
|
+
std::shared_ptr<pulsar_reader_configuration_t> GetCReaderConfig();
|
|
34
|
+
std::shared_ptr<pulsar_message_id_t> GetCStartMessageId();
|
|
36
35
|
std::string GetTopic();
|
|
37
36
|
ReaderListenerCallback *GetListenerCallback();
|
|
38
37
|
|
|
39
38
|
private:
|
|
40
39
|
std::string topic;
|
|
41
|
-
pulsar_message_id_t
|
|
42
|
-
pulsar_reader_configuration_t
|
|
40
|
+
std::shared_ptr<pulsar_message_id_t> cStartMessageId;
|
|
41
|
+
std::shared_ptr<pulsar_reader_configuration_t> cReaderConfig;
|
|
43
42
|
ReaderListenerCallback *listener;
|
|
44
43
|
};
|
|
45
44
|
|
package/src/ReaderListener.h
CHANGED
|
@@ -21,19 +21,14 @@
|
|
|
21
21
|
#define READER_LISTENER_H
|
|
22
22
|
|
|
23
23
|
#include <napi.h>
|
|
24
|
-
#include <pulsar/c/client.h>
|
|
25
|
-
|
|
26
|
-
struct CReaderWrapper {
|
|
27
|
-
pulsar_reader_t *cReader;
|
|
28
|
-
CReaderWrapper();
|
|
29
|
-
~CReaderWrapper();
|
|
30
|
-
};
|
|
31
24
|
|
|
32
25
|
struct ReaderListenerCallback {
|
|
33
26
|
Napi::ThreadSafeFunction callback;
|
|
34
27
|
|
|
35
28
|
// Using reader as void* since the ReaderListenerCallback is shared between Config and Reader.
|
|
36
29
|
void *reader;
|
|
30
|
+
|
|
31
|
+
ReaderListenerCallback() : reader(nullptr) {}
|
|
37
32
|
};
|
|
38
33
|
|
|
39
34
|
#endif
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
+
* or more contributor license agreements. See the NOTICE file
|
|
4
|
+
* distributed with this work for additional information
|
|
5
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
6
|
+
* to you under the Apache License, Version 2.0 (the
|
|
7
|
+
* "License"); you may not use this file except in compliance
|
|
8
|
+
* with the License. You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing,
|
|
13
|
+
* software distributed under the License is distributed on an
|
|
14
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
15
|
+
* KIND, either express or implied. See the License for the
|
|
16
|
+
* specific language governing permissions and limitations
|
|
17
|
+
* under the License.
|
|
18
|
+
*/
|
|
19
|
+
#include "SchemaInfo.h"
|
|
20
|
+
#include <map>
|
|
21
|
+
|
|
22
|
+
static const std::string CFG_SCHEMA_TYPE = "schemaType";
|
|
23
|
+
static const std::string CFG_NAME = "name";
|
|
24
|
+
static const std::string CFG_SCHEMA = "schema";
|
|
25
|
+
static const std::string CFG_PROPS = "properties";
|
|
26
|
+
|
|
27
|
+
static const std::map<std::string, pulsar_schema_type> SCHEMA_TYPE = {{"None", pulsar_None},
|
|
28
|
+
{"String", pulsar_String},
|
|
29
|
+
{"Json", pulsar_Json},
|
|
30
|
+
{"Protobuf", pulsar_Protobuf},
|
|
31
|
+
{"Avro", pulsar_Avro},
|
|
32
|
+
{"Boolean", pulsar_Boolean},
|
|
33
|
+
{"Int8", pulsar_Int8},
|
|
34
|
+
{"Int16", pulsar_Int16},
|
|
35
|
+
{"Int32", pulsar_Int32},
|
|
36
|
+
{"Int64", pulsar_Int64},
|
|
37
|
+
{"Float32", pulsar_Float32},
|
|
38
|
+
{"Float64", pulsar_Float64},
|
|
39
|
+
{"KeyValue", pulsar_KeyValue},
|
|
40
|
+
{"Bytes", pulsar_Bytes},
|
|
41
|
+
{"AutoConsume", pulsar_AutoConsume},
|
|
42
|
+
{"AutoPublish", pulsar_AutoPublish}};
|
|
43
|
+
|
|
44
|
+
SchemaInfo::SchemaInfo(const Napi::Object &schemaInfo) : cSchemaType(pulsar_Bytes), name("BYTES"), schema() {
|
|
45
|
+
this->cProperties = pulsar_string_map_create();
|
|
46
|
+
if (schemaInfo.Has(CFG_SCHEMA_TYPE) && schemaInfo.Get(CFG_SCHEMA_TYPE).IsString()) {
|
|
47
|
+
this->name = schemaInfo.Get(CFG_SCHEMA_TYPE).ToString().Utf8Value();
|
|
48
|
+
this->cSchemaType = SCHEMA_TYPE.at(schemaInfo.Get(CFG_SCHEMA_TYPE).ToString().Utf8Value());
|
|
49
|
+
}
|
|
50
|
+
if (schemaInfo.Has(CFG_NAME) && schemaInfo.Get(CFG_NAME).IsString()) {
|
|
51
|
+
this->name = schemaInfo.Get(CFG_NAME).ToString().Utf8Value();
|
|
52
|
+
}
|
|
53
|
+
if (schemaInfo.Has(CFG_SCHEMA) && schemaInfo.Get(CFG_SCHEMA).IsString()) {
|
|
54
|
+
this->schema = schemaInfo.Get(CFG_SCHEMA).ToString().Utf8Value();
|
|
55
|
+
}
|
|
56
|
+
if (schemaInfo.Has(CFG_PROPS) && schemaInfo.Get(CFG_PROPS).IsObject()) {
|
|
57
|
+
Napi::Object propObj = schemaInfo.Get(CFG_PROPS).ToObject();
|
|
58
|
+
Napi::Array arr = propObj.GetPropertyNames();
|
|
59
|
+
int size = arr.Length();
|
|
60
|
+
for (int i = 0; i < size; i++) {
|
|
61
|
+
Napi::String key = arr.Get(i).ToString();
|
|
62
|
+
Napi::String value = propObj.Get(key).ToString();
|
|
63
|
+
pulsar_string_map_put(this->cProperties, key.Utf8Value().c_str(), value.Utf8Value().c_str());
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void SchemaInfo::SetProducerSchema(std::shared_ptr<pulsar_producer_configuration_t> cProducerConfiguration) {
|
|
69
|
+
pulsar_producer_configuration_set_schema_info(cProducerConfiguration.get(), this->cSchemaType,
|
|
70
|
+
this->name.c_str(), this->schema.c_str(), this->cProperties);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
void SchemaInfo::SetConsumerSchema(std::shared_ptr<pulsar_consumer_configuration_t> cConsumerConfiguration) {
|
|
74
|
+
pulsar_consumer_configuration_set_schema_info(cConsumerConfiguration.get(), this->cSchemaType,
|
|
75
|
+
this->name.c_str(), this->schema.c_str(), this->cProperties);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
SchemaInfo::~SchemaInfo() { pulsar_string_map_free(this->cProperties); }
|
package/src/SchemaInfo.h
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
+
* or more contributor license agreements. See the NOTICE file
|
|
4
|
+
* distributed with this work for additional information
|
|
5
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
6
|
+
* to you under the Apache License, Version 2.0 (the
|
|
7
|
+
* "License"); you may not use this file except in compliance
|
|
8
|
+
* with the License. You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing,
|
|
13
|
+
* software distributed under the License is distributed on an
|
|
14
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
15
|
+
* KIND, either express or implied. See the License for the
|
|
16
|
+
* specific language governing permissions and limitations
|
|
17
|
+
* under the License.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
#ifndef SCHEMA_INFO_H
|
|
21
|
+
#define SCHEMA_INFO_H
|
|
22
|
+
|
|
23
|
+
#include <napi.h>
|
|
24
|
+
#include <pulsar/c/producer_configuration.h>
|
|
25
|
+
#include <pulsar/c/consumer_configuration.h>
|
|
26
|
+
|
|
27
|
+
class SchemaInfo {
|
|
28
|
+
public:
|
|
29
|
+
SchemaInfo(const Napi::Object &schemaInfo);
|
|
30
|
+
~SchemaInfo();
|
|
31
|
+
void SetProducerSchema(std::shared_ptr<pulsar_producer_configuration_t> cProducerConfiguration);
|
|
32
|
+
void SetConsumerSchema(std::shared_ptr<pulsar_consumer_configuration_t> cConsumerConfiguration);
|
|
33
|
+
|
|
34
|
+
private:
|
|
35
|
+
pulsar_schema_type cSchemaType;
|
|
36
|
+
std::string name;
|
|
37
|
+
std::string schema;
|
|
38
|
+
pulsar_string_map_t *cProperties;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
#endif
|