kafka-crab-js 0.0.3 → 0.0.9
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/Cargo.toml +13 -5
- package/example/sample.mjs +12 -8
- package/index.d.ts +9 -8
- package/index.js +1 -2
- package/package.json +13 -4
- package/src/kafka/kafka_client.rs +15 -18
- package/src/kafka/kafka_consumer.rs +8 -6
package/Cargo.toml
CHANGED
|
@@ -8,16 +8,24 @@ crate-type = ["cdylib"]
|
|
|
8
8
|
|
|
9
9
|
[dependencies]
|
|
10
10
|
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
|
|
11
|
-
napi = { version = "2.13", default-features = false, features = [
|
|
11
|
+
napi = { version = "2.13", default-features = false, features = [
|
|
12
|
+
"napi4",
|
|
13
|
+
"tokio_rt",
|
|
14
|
+
] }
|
|
12
15
|
napi-derive = "2.13"
|
|
13
16
|
|
|
14
|
-
anyhow = { version= "1.0", features = ["backtrace"]}
|
|
17
|
+
anyhow = { version = "1.0", features = ["backtrace"] }
|
|
15
18
|
|
|
16
|
-
rdkafka = { version = "0.32", features = [
|
|
19
|
+
rdkafka = { version = "0.32", features = [
|
|
20
|
+
"libz-static",
|
|
21
|
+
"cmake-build",
|
|
22
|
+
"tokio",
|
|
23
|
+
"ssl-vendored",
|
|
24
|
+
] }
|
|
17
25
|
tokio = { version = "1", features = ["full"] }
|
|
18
26
|
|
|
19
|
-
tracing
|
|
20
|
-
tracing-subscriber = "0.3"
|
|
27
|
+
tracing = "0.1"
|
|
28
|
+
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
|
|
21
29
|
|
|
22
30
|
[build-dependencies]
|
|
23
31
|
napi-build = "2.0.1"
|
package/example/sample.mjs
CHANGED
|
@@ -3,14 +3,17 @@ import timersPromises from 'node:timers/promises';
|
|
|
3
3
|
import {Buffer} from 'node:buffer';
|
|
4
4
|
import {ConsumerResult, KafkaClient, KafkaCommitMode, PartitionPosition} from '../index.js';
|
|
5
5
|
|
|
6
|
-
const kafkaClient = new KafkaClient(
|
|
6
|
+
const kafkaClient = new KafkaClient({
|
|
7
|
+
brokers: 'localhost:29092',
|
|
8
|
+
clientId: 'my-id',
|
|
9
|
+
enableAnsiLogger: false});
|
|
7
10
|
const topic = 'my-js-topic';
|
|
8
11
|
|
|
9
12
|
let counter = 0;
|
|
10
13
|
|
|
11
14
|
async function process(message) {
|
|
12
15
|
await timersPromises.setTimeout(1);
|
|
13
|
-
return 'message received: ' + message;
|
|
16
|
+
return 'message received: ' + JSON.stringify(message);
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
const consumer = kafkaClient.createConsumer({
|
|
@@ -27,7 +30,7 @@ console.time('consumer');
|
|
|
27
30
|
|
|
28
31
|
consumer.startConsumer(async (error, value) => {
|
|
29
32
|
if (error) {
|
|
30
|
-
console.error('Consumer error', error);
|
|
33
|
+
console.error('Js Consumer error', error);
|
|
31
34
|
return;
|
|
32
35
|
}
|
|
33
36
|
|
|
@@ -36,19 +39,20 @@ consumer.startConsumer(async (error, value) => {
|
|
|
36
39
|
counter++;
|
|
37
40
|
if (counter >= 0) {
|
|
38
41
|
console.timeEnd('consumer');
|
|
39
|
-
console.log('Counter:', counter, 'Content:', JSON.stringify(content));
|
|
42
|
+
console.log('Js Counter:', counter, 'Content:', JSON.stringify(content));
|
|
40
43
|
console.time('consumer');
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
if (message._id === '3') {
|
|
44
|
-
console.error('Error on process message, let\'s retry',
|
|
47
|
+
console.error('Js Error on process message, let\'s retry', JSON.stringify(content));
|
|
45
48
|
return ConsumerResult.Retry;
|
|
46
49
|
}
|
|
47
50
|
|
|
51
|
+
|
|
48
52
|
return ConsumerResult.Ok;
|
|
49
53
|
});
|
|
50
54
|
|
|
51
|
-
const producer = kafkaClient.createProducer({topic, configuration: {'message.timeout.ms': '
|
|
55
|
+
const producer = kafkaClient.createProducer({topic, configuration: {'message.timeout.ms': '5000'}});
|
|
52
56
|
console.log('Sending message');
|
|
53
57
|
|
|
54
58
|
for (let i = 0; i < 5; i++) {
|
|
@@ -61,9 +65,9 @@ for (let i = 0; i < 5; i++) {
|
|
|
61
65
|
headers: {key: Buffer.from('value1')},
|
|
62
66
|
},
|
|
63
67
|
);
|
|
64
|
-
console.log(result);
|
|
68
|
+
console.log("Js message sent. Offset: ", result);
|
|
65
69
|
await timersPromises.setTimeout(1200);
|
|
66
70
|
} catch (error) {
|
|
67
|
-
console.error('Error on send', error);
|
|
71
|
+
console.error('Js Error on send', error);
|
|
68
72
|
}
|
|
69
73
|
}
|
package/index.d.ts
CHANGED
|
@@ -9,6 +9,13 @@ export const enum SecurityProtocol {
|
|
|
9
9
|
SaslPlaintext = 'SaslPlaintext',
|
|
10
10
|
SaslSsl = 'SaslSsl'
|
|
11
11
|
}
|
|
12
|
+
export interface KafkaConfiguration {
|
|
13
|
+
brokers: string
|
|
14
|
+
clientId: string
|
|
15
|
+
securityProtocol?: SecurityProtocol
|
|
16
|
+
configuration?: Record<string, string>
|
|
17
|
+
enableAnsiLogger?: boolean
|
|
18
|
+
}
|
|
12
19
|
export interface ConsumerConfiguration {
|
|
13
20
|
topic: string
|
|
14
21
|
groupId: string
|
|
@@ -70,20 +77,14 @@ export const enum ConsumerResult {
|
|
|
70
77
|
Ok = 'Ok',
|
|
71
78
|
Retry = 'Retry'
|
|
72
79
|
}
|
|
73
|
-
export class KafkaConfiguration {
|
|
74
|
-
brokers: string
|
|
75
|
-
clientId: string
|
|
76
|
-
securityProtocol?: SecurityProtocol
|
|
77
|
-
configuration?: Record<string, string>
|
|
78
|
-
}
|
|
79
80
|
export class KafkaClient {
|
|
80
81
|
readonly kafkaConfiguration: KafkaConfiguration
|
|
81
|
-
constructor(
|
|
82
|
+
constructor(kafkaConfiguration: KafkaConfiguration)
|
|
82
83
|
createProducer(producerConfiguration: ProducerConfiguration): KafkaProducer
|
|
83
84
|
createConsumer(consumerConfiguration: ConsumerConfiguration): KafkaConsumer
|
|
84
85
|
}
|
|
85
86
|
export class KafkaConsumer {
|
|
86
|
-
startConsumer(callback: (err: Error | null, result: Buffer) => Promise<ConsumerResult>): Promise<void>
|
|
87
|
+
startConsumer(callback: (err: Error | null, result: Buffer) => Promise<ConsumerResult | undefined>): Promise<void>
|
|
87
88
|
}
|
|
88
89
|
export class KafkaProducer {
|
|
89
90
|
send(message: MessageModel): Promise<OwnedDelivery>
|
package/index.js
CHANGED
|
@@ -252,10 +252,9 @@ if (!nativeBinding) {
|
|
|
252
252
|
throw new Error(`Failed to load native binding`)
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
const { SecurityProtocol,
|
|
255
|
+
const { SecurityProtocol, KafkaClient, KafkaConsumer, KafkaProducer, AutoOffsetReset, KafkaCommitMode, PartitionPosition, ConsumerResult } = nativeBinding
|
|
256
256
|
|
|
257
257
|
module.exports.SecurityProtocol = SecurityProtocol
|
|
258
|
-
module.exports.KafkaConfiguration = KafkaConfiguration
|
|
259
258
|
module.exports.KafkaClient = KafkaClient
|
|
260
259
|
module.exports.KafkaConsumer = KafkaConsumer
|
|
261
260
|
module.exports.KafkaProducer = KafkaProducer
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kafka-crab-js",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "index.d.ts",
|
|
6
6
|
"napi": {
|
|
@@ -15,6 +15,15 @@
|
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"license": "MIT",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"kafka",
|
|
20
|
+
"napi-rs",
|
|
21
|
+
"librdkafka",
|
|
22
|
+
"typescript",
|
|
23
|
+
"rust"
|
|
24
|
+
],
|
|
25
|
+
"author": "inaiat@gmail.com",
|
|
26
|
+
"homepage": "https://github.com/inaiat/kafka-crab-js.git",
|
|
18
27
|
"devDependencies": {
|
|
19
28
|
"@napi-rs/cli": "^2.16.1",
|
|
20
29
|
"ava": "^5.3.1",
|
|
@@ -41,8 +50,8 @@
|
|
|
41
50
|
},
|
|
42
51
|
"packageManager": "yarn@3.6.0",
|
|
43
52
|
"optionalDependencies": {
|
|
44
|
-
"kafka-crab-js-darwin-arm64": "0.0.
|
|
45
|
-
"kafka-crab-js-darwin-x64": "0.0.
|
|
46
|
-
"kafka-crab-js-linux-x64-gnu": "0.0.
|
|
53
|
+
"kafka-crab-js-darwin-arm64": "0.0.9",
|
|
54
|
+
"kafka-crab-js-darwin-x64": "0.0.9",
|
|
55
|
+
"kafka-crab-js-linux-x64-gnu": "0.0.9"
|
|
47
56
|
}
|
|
48
57
|
}
|
|
@@ -55,12 +55,13 @@ impl fmt::Display for SecurityProtocol {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
#[derive(Clone, Debug)]
|
|
58
|
-
#[napi]
|
|
58
|
+
#[napi(object)]
|
|
59
59
|
pub struct KafkaConfiguration {
|
|
60
60
|
pub brokers: String,
|
|
61
61
|
pub client_id: String,
|
|
62
62
|
pub security_protocol: Option<SecurityProtocol>,
|
|
63
63
|
pub configuration: Option<HashMap<String, String>>,
|
|
64
|
+
pub enable_ansi_logger: Option<bool>,
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
#[derive(Clone, Debug)]
|
|
@@ -74,23 +75,18 @@ pub struct KafkaClient {
|
|
|
74
75
|
#[napi]
|
|
75
76
|
impl KafkaClient {
|
|
76
77
|
#[napi(constructor)]
|
|
77
|
-
pub fn new(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
match tracing_subscriber::fmt::try_init() {
|
|
78
|
+
pub fn new(kafka_configuration: KafkaConfiguration) -> Self {
|
|
79
|
+
match tracing_subscriber::fmt()
|
|
80
|
+
.with_ansi(kafka_configuration.enable_ansi_logger.unwrap_or(false))
|
|
81
|
+
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
|
|
82
|
+
.try_init()
|
|
83
|
+
{
|
|
84
84
|
Ok(_) => {}
|
|
85
|
-
Err(e) =>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
client_id,
|
|
91
|
-
security_protocol,
|
|
92
|
-
configuration,
|
|
93
|
-
})
|
|
85
|
+
Err(e) => {
|
|
86
|
+
eprintln!("Failed to initialize tracing: {:?}", e);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
KafkaClient::with_kafka_configuration(kafka_configuration)
|
|
94
90
|
}
|
|
95
91
|
|
|
96
92
|
pub fn get_client_config(&self) -> &ClientConfig {
|
|
@@ -103,11 +99,12 @@ impl KafkaClient {
|
|
|
103
99
|
security_protocol,
|
|
104
100
|
client_id,
|
|
105
101
|
configuration,
|
|
102
|
+
..
|
|
106
103
|
} = kafka_configuration.clone();
|
|
107
104
|
|
|
108
105
|
let mut rdkafka_client_config = ClientConfig::new();
|
|
109
106
|
|
|
110
|
-
rdkafka_client_config.set_log_level(RDKafkaLogLevel::
|
|
107
|
+
rdkafka_client_config.set_log_level(RDKafkaLogLevel::Debug);
|
|
111
108
|
rdkafka_client_config.set("bootstrap.servers", brokers);
|
|
112
109
|
rdkafka_client_config.set("client.id", client_id);
|
|
113
110
|
if let Some(security_protocol) = security_protocol {
|
|
@@ -92,7 +92,9 @@ impl KafkaConsumer {
|
|
|
92
92
|
})
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
#[napi(
|
|
95
|
+
#[napi(
|
|
96
|
+
ts_args_type = "callback: (err: Error | null, result: Buffer) => Promise<ConsumerResult | undefined>"
|
|
97
|
+
)]
|
|
96
98
|
pub async fn start_consumer(&self, func: ThreadsafeFunction<Buffer>) -> Result<()> {
|
|
97
99
|
let ConsumerConfiguration {
|
|
98
100
|
commit_mode,
|
|
@@ -304,22 +306,22 @@ async fn process_message(
|
|
|
304
306
|
match message.payload_view::<[u8]>() {
|
|
305
307
|
None => Ok(None),
|
|
306
308
|
Some(Ok(payload)) => match func
|
|
307
|
-
.call_async::<Promise<ConsumerResult
|
|
309
|
+
.call_async::<Promise<Option<ConsumerResult>>>(Ok(payload.into()))
|
|
308
310
|
.await
|
|
309
311
|
{
|
|
310
312
|
Ok(js_result) => match js_result.await {
|
|
311
313
|
Ok(value) => match value {
|
|
312
|
-
ConsumerResult::Ok => {
|
|
314
|
+
None | Some(ConsumerResult::Ok) => {
|
|
313
315
|
if let Some(commit_mode) = commit_mode {
|
|
314
316
|
match stream_consumer.commit_message(message, *commit_mode) {
|
|
315
|
-
Ok(_) => Ok(Some(
|
|
317
|
+
Ok(_) => Ok(Some(ConsumerResult::Ok)),
|
|
316
318
|
Err(e) => Err(anyhow::Error::new(e)),
|
|
317
319
|
}
|
|
318
320
|
} else {
|
|
319
|
-
Ok(Some(
|
|
321
|
+
Ok(Some(ConsumerResult::Ok))
|
|
320
322
|
}
|
|
321
323
|
}
|
|
322
|
-
ConsumerResult::Retry => Ok(Some(
|
|
324
|
+
Some(ConsumerResult::Retry) => Ok(Some(ConsumerResult::Retry)),
|
|
323
325
|
},
|
|
324
326
|
Err(e) => Err(anyhow::Error::new(e)),
|
|
325
327
|
},
|