pulsar-client 1.8.2 → 1.9.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.
@@ -237,3 +237,70 @@ jobs:
237
237
  - name: Package Node binaries lib
238
238
  run: |
239
239
  npx node-pre-gyp package --target_arch=${{ env.TARGET }}
240
+
241
+ macos-napi-homebrew:
242
+ name: Build NAPI macos with CPP lib installed by Homebrew
243
+ runs-on: macos-latest
244
+ timeout-minutes: 3000
245
+ strategy:
246
+ fail-fast: false
247
+ steps:
248
+ - uses: actions/checkout@v3
249
+ - name: Use Node.js 18
250
+ uses: actions/setup-node@v3
251
+ with:
252
+ node-version: 18
253
+ cache: 'npm'
254
+ - name: Install CPP lib
255
+ run: |
256
+ export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=true
257
+ brew update
258
+ brew install libpulsar
259
+ - name: Build Node binaries lib
260
+ run: |
261
+ npm install --ignore-scripts
262
+ npx node-pre-gyp configure
263
+ npx node-pre-gyp build
264
+ - name: Test loading Node binaries lib
265
+ run: |
266
+ node pkg/load_test.js
267
+ - name: Package Node binaries lib
268
+ run: |
269
+ npx node-pre-gyp package
270
+
271
+ linux-napi-apt:
272
+ name: Build NAPI linux with CPP lib installed by APT
273
+ runs-on: ubuntu-22.04
274
+ timeout-minutes: 3000
275
+ strategy:
276
+ fail-fast: false
277
+ steps:
278
+ - uses: actions/checkout@v3
279
+ - name: Use Node.js 18
280
+ uses: actions/setup-node@v3
281
+ with:
282
+ node-version: 18
283
+ cache: 'npm'
284
+ - name: Install CPP lib
285
+ run: |
286
+ source pulsar-client-cpp.txt
287
+ UNAME_ARCH=$(uname -m)
288
+ if [ $UNAME_ARCH == 'aarch64' ]; then
289
+ PLATFORM='arm64'
290
+ else
291
+ PLATFORM='x86_64'
292
+ fi
293
+ curl -s -L -O ${CPP_CLIENT_BASE_URL}/deb-${PLATFORM}/apache-pulsar-client.deb
294
+ curl -s -L -O ${CPP_CLIENT_BASE_URL}/deb-${PLATFORM}/apache-pulsar-client-dev.deb
295
+ sudo -E apt -y install ./apache-pulsar-client.deb ./apache-pulsar-client-dev.deb
296
+ - name: Build Node binaries lib
297
+ run: |
298
+ npm install --ignore-scripts
299
+ npx node-pre-gyp configure
300
+ npx node-pre-gyp build
301
+ - name: Test loading Node binaries lib
302
+ run: |
303
+ node pkg/load_test.js
304
+ - name: Package Node binaries lib
305
+ run: |
306
+ npx node-pre-gyp package
package/README.md CHANGED
@@ -21,7 +21,7 @@
21
21
 
22
22
  # Pulsar Node.js client library
23
23
 
24
- The Pulsar Node.js client can be used to create Pulsar producers and consumers in Node.js.
24
+ The Pulsar Node.js client can be used to create Pulsar producers and consumers in Node.js. For the supported Pulsar features, see [Client Feature Matrix](https://pulsar.apache.org/client-feature-matrix/).
25
25
 
26
26
  This library works only in Node.js 10.x or later because it uses the
27
27
  [node-addon-api](https://github.com/nodejs/node-addon-api) module to wrap the C++ library.
@@ -73,7 +73,7 @@ const Pulsar = require('pulsar-client');
73
73
  data: Buffer.from("hello")
74
74
  });
75
75
 
76
- // Receive the message
76
+ // Receive the message
77
77
  const msg = await consumer.receive();
78
78
  console.log(msg.getData().toString());
79
79
  consumer.acknowledge(msg);
@@ -96,7 +96,7 @@ You can see more examples in the [examples](./examples) directory. However, sinc
96
96
 
97
97
  > **Note**
98
98
  >
99
- > Build from source code requires the Node.js version greater than 16.18
99
+ > Building from source code requires a Node.js version greater than 16.18.
100
100
 
101
101
  First, clone the repository.
102
102
 
@@ -134,6 +134,10 @@ npm install
134
134
 
135
135
  To verify it has been installed successfully, you can run an example like:
136
136
 
137
+ > **Note**
138
+ >
139
+ > A running Pulsar server is required. The example uses `pulsar://localhost:6650` to connect to the server.
140
+
137
141
  ```shell
138
142
  node examples/producer
139
143
  ```
@@ -155,9 +159,15 @@ Sent message: my-message-9
155
159
 
156
160
  ## Documentation
157
161
 
158
- * Please see https://pulsar.apache.org/docs/client-libraries-node/ for more details about the Pulsar Node.js client.
162
+ For more details about Pulsar Node.js clients, see [Pulsar docs](https://pulsar.apache.org/docs/client-libraries-node/).
163
+
164
+ ### Contribute
165
+
166
+ Contributions are welcomed and greatly appreciated.
167
+
168
+ If your contribution adds Pulsar features for Node.js clients, you need to update both the [Pulsar docs](https://pulsar.apache.org/docs/client-libraries/) and the [Client Feature Matrix](https://pulsar.apache.org/client-feature-matrix/). See [Contribution Guide](https://pulsar.apache.org/contribute/site-intro/#pages) for more details.
159
169
 
160
- You can generate the API docs by:
170
+ ### Generate API docs
161
171
 
162
172
  ```shell
163
173
  npm install
package/binding.gyp CHANGED
@@ -57,11 +57,25 @@
57
57
  "dependencies": [
58
58
  "<!@(node -p \"require('node-addon-api').gyp\")"
59
59
  ],
60
- "include_dirs": [
61
- "pkg/mac/build-pulsar/install/include"
62
- ],
63
- "libraries": [
64
- "../pkg/mac/build-pulsar/install/lib/libpulsarwithdeps.a"
60
+ "conditions": [
61
+ ['"<!(test -e <(module_root_dir)/pkg/mac/build-pulsar/install && echo true || echo false)"=="true"', {
62
+ "include_dirs": [
63
+ "<(module_root_dir)/pkg/mac/build-pulsar/install/include"
64
+ ],
65
+ "libraries": [
66
+ "<(module_root_dir)/pkg/mac/build-pulsar/install/lib/libpulsarwithdeps.a"
67
+ ]
68
+ }, {
69
+ "include_dirs": [
70
+ "<!(brew --prefix)/include"
71
+ ],
72
+ "library_dirs": [
73
+ "<!(brew --prefix)/lib"
74
+ ],
75
+ "libraries": [
76
+ "-lpulsar"
77
+ ]
78
+ }]
65
79
  ],
66
80
  }],
67
81
  ['OS=="win"', {
@@ -75,10 +89,10 @@
75
89
  },
76
90
  },
77
91
  "include_dirs": [
78
- "pkg\\windows\\pulsar-cpp\\include",
92
+ "<(module_root_dir)\\pkg\\windows\\pulsar-cpp\\include"
79
93
  ],
80
94
  "libraries": [
81
- "..\\pkg\\windows\\pulsar-cpp\\lib\\pulsarWithDeps.lib"
95
+ "<(module_root_dir)\\pkg\\windows\\pulsar-cpp\\lib\\pulsarWithDeps.lib"
82
96
  ],
83
97
  "dependencies": [
84
98
  "<!(node -p \"require('node-addon-api').gyp\")"
@@ -91,11 +105,19 @@
91
105
  "dependencies": [
92
106
  "<!@(node -p \"require('node-addon-api').gyp\")"
93
107
  ],
94
- "include_dirs": [
95
- "pkg/linux/pulsar-cpp/include"
96
- ],
97
- "libraries": [
98
- "../pkg/linux/pulsar-cpp/lib/libpulsarwithdeps.a"
108
+ "conditions": [
109
+ ['"<!(test -e <(module_root_dir)/pkg/linux/pulsar-cpp && echo true || echo false)"=="true"', {
110
+ "include_dirs": [
111
+ "<(module_root_dir)/pkg/linux/pulsar-cpp/include"
112
+ ],
113
+ "libraries": [
114
+ "<(module_root_dir)/pkg/linux/pulsar-cpp/lib/libpulsarwithdeps.a"
115
+ ]
116
+ }, {
117
+ "libraries": [
118
+ "-lpulsar"
119
+ ]
120
+ }]
99
121
  ],
100
122
  }]
101
123
  ]
@@ -25,7 +25,7 @@ cd $SRC_DIR
25
25
 
26
26
  build-support/pulsar-test-service-stop.sh
27
27
 
28
- CONTAINER_ID=$(docker run -i -p 8080:8080 -p 6650:6650 -p 8443:8443 -p 6651:6651 --rm --detach apachepulsar/pulsar:2.10.2 sleep 3600)
28
+ CONTAINER_ID=$(docker run -i -p 8080:8080 -p 6650:6650 -p 8443:8443 -p 6651:6651 --rm --detach apachepulsar/pulsar:latest sleep 3600)
29
29
 
30
30
  echo $CONTAINER_ID >.tests-container-id.txt
31
31
 
@@ -34,6 +34,17 @@ The steps for releasing are as follows:
34
34
  9. Add release notes
35
35
  10. Announce the release
36
36
 
37
+ ## Versioning
38
+ Bump up the version number as follows.
39
+
40
+ * Major version (e.g. 1.8.0 => 2.0.0)
41
+ * Changes that break backward compatibility
42
+ * Minor version (e.g. 1.8.0 => 1.9.0)
43
+ * Backward compatible new features
44
+ * Patch version (e.g. 1.8.0 => 1.8.1)
45
+ * Backward compatible bug fixes
46
+ * C++ Client upgrade (even though there are no new commits in the Nodejs client)
47
+
37
48
  ## Requirements
38
49
  If you haven't already done it, [create and publish the GPG key](https://pulsar.apache.org/contribute/releasing/create-gpg-keys) to sign the release artifacts.
39
50
 
@@ -0,0 +1,44 @@
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
+ const Pulsar = require('../');
21
+
22
+ (async () => {
23
+ // Create a client
24
+ const client = new Pulsar.Client({
25
+ serviceUrl: 'pulsar://localhost:6650',
26
+ operationTimeoutSeconds: 30
27
+ });
28
+
29
+ // Create a reader
30
+ const reader = await client.createReader({
31
+ topic: 'persistent://public/default/my-topic',
32
+ startMessageId: Pulsar.MessageId.earliest(),
33
+ privateKeyPath: './certificate/private-key.client-rsa.pem'
34
+ });
35
+
36
+ // Receive messages
37
+ for (let i = 0; i < 10; i += 1) {
38
+ const msg = await reader.readNext();
39
+ console.log(msg.getData().toString());
40
+ }
41
+
42
+ await reader.close();
43
+ await client.close();
44
+ })();
package/index.d.ts CHANGED
@@ -39,6 +39,7 @@ export class Client {
39
39
  createProducer(config: ProducerConfig): Promise<Producer>;
40
40
  subscribe(config: ConsumerConfig): Promise<Consumer>;
41
41
  createReader(config: ReaderConfig): Promise<Reader>;
42
+ getPartitionsForTopic(topic: string): Promise<string[]>;
42
43
  close(): Promise<null>;
43
44
  }
44
45
 
@@ -61,6 +62,8 @@ export interface ProducerConfig {
61
62
  encryptionKey?: string;
62
63
  cryptoFailureAction?: ProducerCryptoFailureAction;
63
64
  chunkingEnabled?: boolean;
65
+ schema?: SchemaInfo;
66
+ accessMode?: ProducerAccessMode;
64
67
  }
65
68
 
66
69
  export class Producer {
@@ -91,6 +94,10 @@ export interface ConsumerConfig {
91
94
  cryptoFailureAction?: ConsumerCryptoFailureAction;
92
95
  maxPendingChunkedMessage?: number;
93
96
  autoAckOldestChunkedMessageOnQueueFull?: number;
97
+ schema?: SchemaInfo;
98
+ batchIndexAckEnabled?: boolean;
99
+ regexSubscriptionMode?: RegexSubscriptionMode;
100
+ deadLetterPolicy?: DeadLetterPolicy;
94
101
  }
95
102
 
96
103
  export class Consumer {
@@ -116,6 +123,8 @@ export interface ReaderConfig {
116
123
  subscriptionRolePrefix?: string;
117
124
  readCompacted?: boolean;
118
125
  listener?: (message: Message, reader: Reader) => void;
126
+ privateKeyPath?: string;
127
+ cryptoFailureAction?: ConsumerCryptoFailureAction;
119
128
  }
120
129
 
121
130
  export class Reader {
@@ -159,6 +168,19 @@ export class MessageId {
159
168
  toString(): string;
160
169
  }
161
170
 
171
+ export interface SchemaInfo {
172
+ schemaType: SchemaType;
173
+ name?: string;
174
+ schema?: string;
175
+ properties?: Record<string, string>;
176
+ }
177
+
178
+ export interface DeadLetterPolicy {
179
+ deadLetterTopic: string;
180
+ maxRedeliverCount?: number;
181
+ initialSubscriptionName?: string;
182
+ }
183
+
162
184
  export class AuthenticationTls {
163
185
  constructor(params: { certificatePath: string, privateKeyPath: string });
164
186
  }
@@ -236,3 +258,32 @@ export type ConsumerCryptoFailureAction =
236
258
  'FAIL' |
237
259
  'DISCARD' |
238
260
  'CONSUME';
261
+
262
+ export type RegexSubscriptionMode =
263
+ 'PersistentOnly' |
264
+ 'NonPersistentOnly' |
265
+ 'AllTopics';
266
+
267
+ export type SchemaType =
268
+ 'None' |
269
+ 'String' |
270
+ 'Json' |
271
+ 'Protobuf' |
272
+ 'Avro' |
273
+ 'Boolean' |
274
+ 'Int8' |
275
+ 'Int16' |
276
+ 'Int32' |
277
+ 'Int64' |
278
+ 'Float32' |
279
+ 'Float64' |
280
+ 'KeyValue' |
281
+ 'Bytes' |
282
+ 'AutoConsume' |
283
+ 'AutoPublish';
284
+
285
+ export type ProducerAccessMode =
286
+ 'Shared' |
287
+ 'Exclusive' |
288
+ 'WaitForExclusive' |
289
+ 'ExclusiveWithFencing';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pulsar-client",
3
- "version": "1.8.2",
3
+ "version": "1.9.0",
4
4
  "description": "Pulsar Node.js client",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -77,7 +77,7 @@ const Pulsar = require('../index.js');
77
77
  const numOfMessages = commander.messages;
78
78
  for (let i = 0; i < commander.iteration; i += 1) {
79
79
  const histogram = hdr.build({
80
- bitBucketSize: 0,
80
+ bitBucketSize: 64,
81
81
  highestTrackableValue: 120000 * 1000,
82
82
  numberOfSignificantValueDigits: 5,
83
83
  });
@@ -104,7 +104,7 @@ const Pulsar = require('../index.js');
104
104
  console.log('Throughput produced: %f msg/s --- %f Mbit/s --- Latency: mean: %f ms - med: %f - 95pct: %f - 99pct: %f - 99.9pct: %f - 99.99pct: %f - Max: %f',
105
105
  rate.toFixed(3),
106
106
  throuhputMbit.toFixed(3),
107
- histogram.getMean(),
107
+ histogram.mean,
108
108
  histogram.getValueAtPercentile(50),
109
109
  histogram.getValueAtPercentile(95),
110
110
  histogram.getValueAtPercentile(99),
@@ -1,2 +1,2 @@
1
- CPP_CLIENT_BASE_URL=https://archive.apache.org/dist/pulsar/pulsar-client-cpp-3.1.2
2
- CPP_CLIENT_VERSION=3.1.2
1
+ CPP_CLIENT_BASE_URL=https://archive.apache.org/dist/pulsar/pulsar-client-cpp-3.2.0
2
+ CPP_CLIENT_VERSION=3.2.0
package/src/Client.cc CHANGED
@@ -79,6 +79,7 @@ Napi::Object Client::Init(Napi::Env env, Napi::Object exports) {
79
79
  {StaticMethod("setLogHandler", &Client::SetLogHandler),
80
80
  InstanceMethod("createProducer", &Client::CreateProducer),
81
81
  InstanceMethod("subscribe", &Client::Subscribe), InstanceMethod("createReader", &Client::CreateReader),
82
+ InstanceMethod("getPartitionsForTopic", &Client::GetPartitionsForTopic),
82
83
  InstanceMethod("close", &Client::Close)});
83
84
 
84
85
  constructor = Napi::Persistent(func);
@@ -206,6 +207,41 @@ Napi::Value Client::CreateReader(const Napi::CallbackInfo &info) {
206
207
  return Reader::NewInstance(info, this->cClient);
207
208
  }
208
209
 
210
+ Napi::Value Client::GetPartitionsForTopic(const Napi::CallbackInfo &info) {
211
+ Napi::String topicString = info[0].As<Napi::String>();
212
+ std::string topic = topicString.Utf8Value();
213
+ auto deferred = ThreadSafeDeferred::New(Env());
214
+ auto ctx = new ExtDeferredContext(deferred);
215
+
216
+ pulsar_client_get_topic_partitions_async(
217
+ this->cClient.get(), topic.c_str(),
218
+ [](pulsar_result result, pulsar_string_list_t *topicList, void *ctx) {
219
+ auto deferredContext = static_cast<ExtDeferredContext *>(ctx);
220
+ auto deferred = deferredContext->deferred;
221
+ delete deferredContext;
222
+
223
+ if (result == pulsar_result_Ok && topicList != nullptr) {
224
+ deferred->Resolve([topicList](const Napi::Env env) {
225
+ int listSize = pulsar_string_list_size(topicList);
226
+ Napi::Array jsArray = Napi::Array::New(env, listSize);
227
+
228
+ for (int i = 0; i < listSize; i++) {
229
+ const char *str = pulsar_string_list_get(topicList, i);
230
+ jsArray.Set(i, Napi::String::New(env, str));
231
+ }
232
+
233
+ return jsArray;
234
+ });
235
+ } else {
236
+ deferred->Reject(std::string("Failed to GetPartitionsForTopic: ") + pulsar_result_str(result));
237
+ }
238
+ },
239
+
240
+ ctx);
241
+
242
+ return deferred->Promise();
243
+ }
244
+
209
245
  void LogMessageProxy(Napi::Env env, Napi::Function jsCallback, struct LogMessage *logMessage) {
210
246
  Napi::Number logLevel = Napi::Number::New(env, static_cast<double>(logMessage->level));
211
247
  Napi::String file = Napi::String::New(env, logMessage->file);
package/src/Client.h CHANGED
@@ -42,6 +42,9 @@ class Client : public Napi::ObjectWrap<Client> {
42
42
  static Napi::Object Init(Napi::Env env, Napi::Object exports);
43
43
  static void SetLogHandler(const Napi::CallbackInfo &info);
44
44
 
45
+ static void LogMessage(pulsar_logger_level_t level, const char *file, int line, const char *message,
46
+ void *ctx);
47
+
45
48
  Client(const Napi::CallbackInfo &info);
46
49
  ~Client();
47
50
 
@@ -51,11 +54,10 @@ class Client : public Napi::ObjectWrap<Client> {
51
54
  std::shared_ptr<pulsar_client_t> cClient;
52
55
  std::shared_ptr<pulsar_client_configuration_t> cClientConfig;
53
56
 
54
- static void LogMessage(pulsar_logger_level_t level, const char *file, int line, const char *message,
55
- void *ctx);
56
57
  Napi::Value CreateProducer(const Napi::CallbackInfo &info);
57
58
  Napi::Value Subscribe(const Napi::CallbackInfo &info);
58
59
  Napi::Value CreateReader(const Napi::CallbackInfo &info);
60
+ Napi::Value GetPartitionsForTopic(const Napi::CallbackInfo &info);
59
61
  Napi::Value Close(const Napi::CallbackInfo &info);
60
62
  };
61
63
 
package/src/Client.js CHANGED
@@ -44,6 +44,10 @@ class Client {
44
44
  return this.client.createReader(params);
45
45
  }
46
46
 
47
+ getPartitionsForTopic(params) {
48
+ return this.client.getPartitionsForTopic(params);
49
+ }
50
+
47
51
  close() {
48
52
  this.client.close();
49
53
  }
package/src/Consumer.cc CHANGED
@@ -22,10 +22,12 @@
22
22
  #include "Message.h"
23
23
  #include "MessageId.h"
24
24
  #include "ThreadSafeDeferred.h"
25
+ #include "LogUtils.h"
25
26
  #include <pulsar/c/result.h>
26
27
  #include <atomic>
27
28
  #include <thread>
28
29
  #include <future>
30
+ #include <sstream>
29
31
 
30
32
  Napi::FunctionReference Consumer::constructor;
31
33
 
@@ -63,6 +65,13 @@ struct MessageListenerProxyData {
63
65
  : cMessage(cMessage), consumer(consumer), callback(callback) {}
64
66
  };
65
67
 
68
+ inline void logMessageListenerError(Consumer *consumer, const char *err) {
69
+ std::ostringstream ss;
70
+ ss << "[" << consumer->GetTopic() << "][" << consumer->GetSubscriptionName()
71
+ << "] Message listener error in processing message: " << err;
72
+ LOG_ERROR(ss.str().c_str());
73
+ }
74
+
66
75
  void MessageListenerProxy(Napi::Env env, Napi::Function jsCallback, MessageListenerProxyData *data) {
67
76
  Napi::Object msg = Message::NewInstance({}, data->cMessage);
68
77
  Consumer *consumer = data->consumer;
@@ -70,17 +79,28 @@ void MessageListenerProxy(Napi::Env env, Napi::Function jsCallback, MessageListe
70
79
  // `consumer` might be null in certain cases, segmentation fault might happend without this null check. We
71
80
  // need to handle this rare case in future.
72
81
  if (consumer) {
73
- Napi::Value ret = jsCallback.Call({msg, consumer->Value()});
82
+ Napi::Value ret;
83
+ try {
84
+ ret = jsCallback.Call({msg, consumer->Value()});
85
+ } catch (std::exception &exception) {
86
+ logMessageListenerError(consumer, exception.what());
87
+ }
88
+
74
89
  if (ret.IsPromise()) {
75
90
  Napi::Promise promise = ret.As<Napi::Promise>();
76
- Napi::Value thenValue = promise.Get("then");
77
- if (thenValue.IsFunction()) {
78
- Napi::Function then = thenValue.As<Napi::Function>();
79
- Napi::Function callback =
80
- Napi::Function::New(env, [data](const Napi::CallbackInfo &info) { data->callback(); });
81
- then.Call(promise, {callback});
82
- return;
83
- }
91
+ Napi::Function catchFunc = promise.Get("catch").As<Napi::Function>();
92
+
93
+ ret = catchFunc.Call(promise, {Napi::Function::New(env, [consumer](const Napi::CallbackInfo &info) {
94
+ Napi::Error error = info[0].As<Napi::Error>();
95
+ logMessageListenerError(consumer, error.what());
96
+ })});
97
+
98
+ promise = ret.As<Napi::Promise>();
99
+ Napi::Function finallyFunc = promise.Get("finally").As<Napi::Function>();
100
+
101
+ finallyFunc.Call(
102
+ promise, {Napi::Function::New(env, [data](const Napi::CallbackInfo &info) { data->callback(); })});
103
+ return;
84
104
  }
85
105
  }
86
106
  data->callback();
@@ -227,6 +247,12 @@ Napi::Value Consumer::NewInstance(const Napi::CallbackInfo &info, std::shared_pt
227
247
  return deferred->Promise();
228
248
  }
229
249
 
250
+ std::string Consumer::GetTopic() { return {pulsar_consumer_get_topic(this->cConsumer.get())}; }
251
+
252
+ std::string Consumer::GetSubscriptionName() {
253
+ return {pulsar_consumer_get_subscription_name(this->cConsumer.get())};
254
+ }
255
+
230
256
  // We still need a receive worker because the c api is missing the equivalent async definition
231
257
  class ConsumerReceiveWorker : public Napi::AsyncWorker {
232
258
  public:
package/src/Consumer.h CHANGED
@@ -36,6 +36,8 @@ class Consumer : public Napi::ObjectWrap<Consumer> {
36
36
  void SetListenerCallback(MessageListenerCallback *listener);
37
37
  void Cleanup();
38
38
  void CleanupListener();
39
+ std::string GetTopic();
40
+ std::string GetSubscriptionName();
39
41
 
40
42
  private:
41
43
  std::shared_ptr<pulsar_consumer_t> cConsumer;
@@ -31,6 +31,7 @@ static const std::string CFG_TOPICS_PATTERN = "topicsPattern";
31
31
  static const std::string CFG_SUBSCRIPTION = "subscription";
32
32
  static const std::string CFG_SUBSCRIPTION_TYPE = "subscriptionType";
33
33
  static const std::string CFG_INIT_POSITION = "subscriptionInitialPosition";
34
+ static const std::string CFG_REGEX_SUBSCRIPTION_MODE = "regexSubscriptionMode";
34
35
  static const std::string CFG_ACK_TIMEOUT = "ackTimeoutMs";
35
36
  static const std::string CFG_NACK_REDELIVER_TIMEOUT = "nAckRedeliverTimeoutMs";
36
37
  static const std::string CFG_RECV_QUEUE = "receiverQueueSize";
@@ -45,6 +46,11 @@ static const std::string CFG_CRYPTO_FAILURE_ACTION = "cryptoFailureAction";
45
46
  static const std::string CFG_MAX_PENDING_CHUNKED_MESSAGE = "maxPendingChunkedMessage";
46
47
  static const std::string CFG_AUTO_ACK_OLDEST_CHUNKED_MESSAGE_ON_QUEUE_FULL =
47
48
  "autoAckOldestChunkedMessageOnQueueFull";
49
+ static const std::string CFG_BATCH_INDEX_ACK_ENABLED = "batchIndexAckEnabled";
50
+ static const std::string CFG_DEAD_LETTER_POLICY = "deadLetterPolicy";
51
+ static const std::string CFG_DLQ_POLICY_TOPIC = "deadLetterTopic";
52
+ static const std::string CFG_DLQ_POLICY_MAX_REDELIVER_COUNT = "maxRedeliverCount";
53
+ static const std::string CFG_DLQ_POLICY_INIT_SUB_NAME = "initialSubscriptionName";
48
54
 
49
55
  static const std::map<std::string, pulsar_consumer_type> SUBSCRIPTION_TYPE = {
50
56
  {"Exclusive", pulsar_ConsumerExclusive},
@@ -52,6 +58,11 @@ static const std::map<std::string, pulsar_consumer_type> SUBSCRIPTION_TYPE = {
52
58
  {"KeyShared", pulsar_ConsumerKeyShared},
53
59
  {"Failover", pulsar_ConsumerFailover}};
54
60
 
61
+ static const std::map<std::string, pulsar_consumer_regex_subscription_mode> REGEX_SUBSCRIPTION_MODE = {
62
+ {"PersistentOnly", pulsar_consumer_regex_sub_mode_PersistentOnly},
63
+ {"NonPersistentOnly", pulsar_consumer_regex_sub_mode_NonPersistentOnly},
64
+ {"AllTopics", pulsar_consumer_regex_sub_mode_AllTopics}};
65
+
55
66
  static const std::map<std::string, initial_position> INIT_POSITION = {
56
67
  {"Latest", initial_position_latest}, {"Earliest", initial_position_earliest}};
57
68
 
@@ -110,6 +121,16 @@ ConsumerConfig::ConsumerConfig(const Napi::Object &consumerConfig, pulsar_messag
110
121
  }
111
122
  }
112
123
 
124
+ if (consumerConfig.Has(CFG_REGEX_SUBSCRIPTION_MODE) &&
125
+ consumerConfig.Get(CFG_REGEX_SUBSCRIPTION_MODE).IsString()) {
126
+ std::string regexSubscriptionMode =
127
+ consumerConfig.Get(CFG_REGEX_SUBSCRIPTION_MODE).ToString().Utf8Value();
128
+ if (REGEX_SUBSCRIPTION_MODE.count(regexSubscriptionMode)) {
129
+ pulsar_consumer_configuration_set_regex_subscription_mode(
130
+ this->cConsumerConfig.get(), REGEX_SUBSCRIPTION_MODE.at(regexSubscriptionMode));
131
+ }
132
+ }
133
+
113
134
  if (consumerConfig.Has(CFG_CONSUMER_NAME) && consumerConfig.Get(CFG_CONSUMER_NAME).IsString()) {
114
135
  std::string consumerName = consumerConfig.Get(CFG_CONSUMER_NAME).ToString().Utf8Value();
115
136
  if (!consumerName.empty())
@@ -215,6 +236,35 @@ ConsumerConfig::ConsumerConfig(const Napi::Object &consumerConfig, pulsar_messag
215
236
  pulsar_consumer_configuration_set_auto_ack_oldest_chunked_message_on_queue_full(
216
237
  this->cConsumerConfig.get(), autoAckOldestChunkedMessageOnQueueFull);
217
238
  }
239
+
240
+ if (consumerConfig.Has(CFG_BATCH_INDEX_ACK_ENABLED) &&
241
+ consumerConfig.Get(CFG_BATCH_INDEX_ACK_ENABLED).IsBoolean()) {
242
+ bool batchIndexAckEnabled = consumerConfig.Get(CFG_BATCH_INDEX_ACK_ENABLED).ToBoolean();
243
+ pulsar_consumer_configuration_set_batch_index_ack_enabled(this->cConsumerConfig.get(),
244
+ batchIndexAckEnabled);
245
+ }
246
+
247
+ if (consumerConfig.Has(CFG_DEAD_LETTER_POLICY) && consumerConfig.Get(CFG_DEAD_LETTER_POLICY).IsObject()) {
248
+ pulsar_consumer_config_dead_letter_policy_t dlq_policy{};
249
+ Napi::Object dlqPolicyObject = consumerConfig.Get(CFG_DEAD_LETTER_POLICY).ToObject();
250
+ std::string dlq_topic_str;
251
+ std::string init_subscription_name;
252
+ if (dlqPolicyObject.Has(CFG_DLQ_POLICY_TOPIC) && dlqPolicyObject.Get(CFG_DLQ_POLICY_TOPIC).IsString()) {
253
+ dlq_topic_str = dlqPolicyObject.Get(CFG_DLQ_POLICY_TOPIC).ToString().Utf8Value();
254
+ dlq_policy.dead_letter_topic = dlq_topic_str.c_str();
255
+ }
256
+ if (dlqPolicyObject.Has(CFG_DLQ_POLICY_MAX_REDELIVER_COUNT) &&
257
+ dlqPolicyObject.Get(CFG_DLQ_POLICY_MAX_REDELIVER_COUNT).IsNumber()) {
258
+ dlq_policy.max_redeliver_count =
259
+ dlqPolicyObject.Get(CFG_DLQ_POLICY_MAX_REDELIVER_COUNT).ToNumber().Int32Value();
260
+ }
261
+ if (dlqPolicyObject.Has(CFG_DLQ_POLICY_INIT_SUB_NAME) &&
262
+ dlqPolicyObject.Get(CFG_DLQ_POLICY_INIT_SUB_NAME).IsString()) {
263
+ init_subscription_name = dlqPolicyObject.Get(CFG_DLQ_POLICY_INIT_SUB_NAME).ToString().Utf8Value();
264
+ dlq_policy.initial_subscription_name = init_subscription_name.c_str();
265
+ }
266
+ pulsar_consumer_configuration_set_dlq_policy(this->cConsumerConfig.get(), &dlq_policy);
267
+ }
218
268
  }
219
269
 
220
270
  ConsumerConfig::~ConsumerConfig() {