@platformatic/kafka 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +270 -0
- package/dist/apis/admin/alter-client-quotas.d.ts +33 -0
- package/dist/apis/admin/alter-client-quotas.js +64 -0
- package/dist/apis/admin/alter-configs.d.ts +26 -0
- package/dist/apis/admin/alter-configs.js +57 -0
- package/dist/apis/admin/alter-partition-reassignments.d.ts +30 -0
- package/dist/apis/admin/alter-partition-reassignments.js +68 -0
- package/dist/apis/admin/alter-partition.d.ts +39 -0
- package/dist/apis/admin/alter-partition.js +87 -0
- package/dist/apis/admin/alter-replica-log-dirs.d.ts +26 -0
- package/dist/apis/admin/alter-replica-log-dirs.js +55 -0
- package/dist/apis/admin/alter-user-scram-credentials.d.ts +27 -0
- package/dist/apis/admin/alter-user-scram-credentials.js +60 -0
- package/dist/apis/admin/consumer-group-describe.d.ts +41 -0
- package/dist/apis/admin/consumer-group-describe.js +103 -0
- package/dist/apis/admin/create-acls.d.ts +24 -0
- package/dist/apis/admin/create-acls.js +55 -0
- package/dist/apis/admin/create-delegation-token.d.ts +24 -0
- package/dist/apis/admin/create-delegation-token.js +54 -0
- package/dist/apis/admin/create-partitions.d.ts +24 -0
- package/dist/apis/admin/create-partitions.js +54 -0
- package/dist/apis/admin/create-topics.d.ts +42 -0
- package/dist/apis/admin/create-topics.js +86 -0
- package/dist/apis/admin/delete-acls.d.ts +36 -0
- package/dist/apis/admin/delete-acls.js +82 -0
- package/dist/apis/admin/delete-groups.d.ts +14 -0
- package/dist/apis/admin/delete-groups.js +40 -0
- package/dist/apis/admin/delete-records.d.ts +27 -0
- package/dist/apis/admin/delete-records.js +59 -0
- package/dist/apis/admin/delete-topics.d.ts +21 -0
- package/dist/apis/admin/delete-topics.js +50 -0
- package/dist/apis/admin/describe-acls.d.ts +25 -0
- package/dist/apis/admin/describe-acls.js +66 -0
- package/dist/apis/admin/describe-client-quotas.d.ts +30 -0
- package/dist/apis/admin/describe-client-quotas.js +57 -0
- package/dist/apis/admin/describe-cluster.d.ts +23 -0
- package/dist/apis/admin/describe-cluster.js +50 -0
- package/dist/apis/admin/describe-configs.d.ts +38 -0
- package/dist/apis/admin/describe-configs.js +85 -0
- package/dist/apis/admin/describe-delegation-token.d.ts +31 -0
- package/dist/apis/admin/describe-delegation-token.js +62 -0
- package/dist/apis/admin/describe-groups.d.ts +28 -0
- package/dist/apis/admin/describe-groups.js +67 -0
- package/dist/apis/admin/describe-log-dirs.d.ts +32 -0
- package/dist/apis/admin/describe-log-dirs.js +75 -0
- package/dist/apis/admin/describe-producers.d.ts +33 -0
- package/dist/apis/admin/describe-producers.js +70 -0
- package/dist/apis/admin/describe-quorum.d.ts +50 -0
- package/dist/apis/admin/describe-quorum.js +116 -0
- package/dist/apis/admin/describe-topic-partitions.d.ts +42 -0
- package/dist/apis/admin/describe-topic-partitions.js +94 -0
- package/dist/apis/admin/describe-transactions.d.ts +24 -0
- package/dist/apis/admin/describe-transactions.js +59 -0
- package/dist/apis/admin/describe-user-scram-credentials.d.ts +26 -0
- package/dist/apis/admin/describe-user-scram-credentials.js +62 -0
- package/dist/apis/admin/envelope.d.ts +10 -0
- package/dist/apis/admin/envelope.js +32 -0
- package/dist/apis/admin/expire-delegation-token.d.ts +11 -0
- package/dist/apis/admin/expire-delegation-token.js +29 -0
- package/dist/apis/admin/incremental-alter-configs.d.ts +27 -0
- package/dist/apis/admin/incremental-alter-configs.js +58 -0
- package/dist/apis/admin/index.d.ts +37 -0
- package/dist/apis/admin/index.js +37 -0
- package/dist/apis/admin/list-groups.d.ts +18 -0
- package/dist/apis/admin/list-groups.js +43 -0
- package/dist/apis/admin/list-partition-reassignments.d.ts +27 -0
- package/dist/apis/admin/list-partition-reassignments.js +56 -0
- package/dist/apis/admin/list-transactions.d.ts +18 -0
- package/dist/apis/admin/list-transactions.js +45 -0
- package/dist/apis/admin/offset-delete.d.ts +26 -0
- package/dist/apis/admin/offset-delete.js +59 -0
- package/dist/apis/admin/renew-delegation-token.d.ts +11 -0
- package/dist/apis/admin/renew-delegation-token.js +29 -0
- package/dist/apis/admin/unregister-broker.d.ts +12 -0
- package/dist/apis/admin/unregister-broker.js +28 -0
- package/dist/apis/admin/update-features.d.ts +23 -0
- package/dist/apis/admin/update-features.js +60 -0
- package/dist/apis/consumer/consumer-group-heartbeat.d.ts +27 -0
- package/dist/apis/consumer/consumer-group-heartbeat.js +70 -0
- package/dist/apis/consumer/fetch.d.ts +46 -0
- package/dist/apis/consumer/fetch.js +121 -0
- package/dist/apis/consumer/heartbeat.d.ts +11 -0
- package/dist/apis/consumer/heartbeat.js +34 -0
- package/dist/apis/consumer/index.d.ts +9 -0
- package/dist/apis/consumer/index.js +9 -0
- package/dist/apis/consumer/join-group.d.ts +27 -0
- package/dist/apis/consumer/join-group.js +71 -0
- package/dist/apis/consumer/leave-group.d.ts +22 -0
- package/dist/apis/consumer/leave-group.js +57 -0
- package/dist/apis/consumer/list-offsets.d.ts +30 -0
- package/dist/apis/consumer/list-offsets.js +68 -0
- package/dist/apis/consumer/offset-commit.d.ts +29 -0
- package/dist/apis/consumer/offset-commit.js +68 -0
- package/dist/apis/consumer/offset-fetch.d.ts +37 -0
- package/dist/apis/consumer/offset-fetch.js +81 -0
- package/dist/apis/consumer/sync-group.d.ts +18 -0
- package/dist/apis/consumer/sync-group.js +49 -0
- package/dist/apis/definitions.d.ts +16 -0
- package/dist/apis/definitions.js +12 -0
- package/dist/apis/enumerations.d.ts +114 -0
- package/dist/apis/enumerations.js +78 -0
- package/dist/apis/index.d.ts +8 -0
- package/dist/apis/index.js +10 -0
- package/dist/apis/metadata/api-versions.d.ts +17 -0
- package/dist/apis/metadata/api-versions.js +41 -0
- package/dist/apis/metadata/find-coordinator.d.ts +19 -0
- package/dist/apis/metadata/find-coordinator.js +50 -0
- package/dist/apis/metadata/index.d.ts +3 -0
- package/dist/apis/metadata/index.js +3 -0
- package/dist/apis/metadata/metadata.d.ts +37 -0
- package/dist/apis/metadata/metadata.js +92 -0
- package/dist/apis/producer/add-offsets-to-txn.d.ts +10 -0
- package/dist/apis/producer/add-offsets-to-txn.js +34 -0
- package/dist/apis/producer/add-partitions-to-txn.d.ts +34 -0
- package/dist/apis/producer/add-partitions-to-txn.js +79 -0
- package/dist/apis/producer/end-txn.d.ts +10 -0
- package/dist/apis/producer/end-txn.js +34 -0
- package/dist/apis/producer/index.d.ts +6 -0
- package/dist/apis/producer/index.js +6 -0
- package/dist/apis/producer/init-producer-id.d.ts +21 -0
- package/dist/apis/producer/init-producer-id.js +38 -0
- package/dist/apis/producer/produce.d.ts +29 -0
- package/dist/apis/producer/produce.js +104 -0
- package/dist/apis/producer/txn-offset-commit.d.ts +29 -0
- package/dist/apis/producer/txn-offset-commit.js +77 -0
- package/dist/apis/security/index.d.ts +2 -0
- package/dist/apis/security/index.js +2 -0
- package/dist/apis/security/sasl-authenticate.d.ts +15 -0
- package/dist/apis/security/sasl-authenticate.js +30 -0
- package/dist/apis/security/sasl-handshake.d.ts +10 -0
- package/dist/apis/security/sasl-handshake.js +28 -0
- package/dist/apis/telemetry/get-telemetry-subscriptions.d.ts +18 -0
- package/dist/apis/telemetry/get-telemetry-subscriptions.js +46 -0
- package/dist/apis/telemetry/index.d.ts +3 -0
- package/dist/apis/telemetry/index.js +3 -0
- package/dist/apis/telemetry/list-client-metrics-resources.d.ts +14 -0
- package/dist/apis/telemetry/list-client-metrics-resources.js +32 -0
- package/dist/apis/telemetry/push-telemetry.d.ts +10 -0
- package/dist/apis/telemetry/push-telemetry.js +36 -0
- package/dist/clients/admin/admin.d.ts +18 -0
- package/dist/clients/admin/admin.js +322 -0
- package/dist/clients/admin/index.d.ts +3 -0
- package/dist/clients/admin/index.js +3 -0
- package/dist/clients/admin/options.d.ts +135 -0
- package/dist/clients/admin/options.js +81 -0
- package/dist/clients/admin/types.d.ts +56 -0
- package/dist/clients/admin/types.js +1 -0
- package/dist/clients/base/base.d.ts +48 -0
- package/dist/clients/base/base.js +242 -0
- package/dist/clients/base/index.d.ts +3 -0
- package/dist/clients/base/index.js +3 -0
- package/dist/clients/base/options.d.ts +115 -0
- package/dist/clients/base/options.js +59 -0
- package/dist/clients/base/types.d.ts +38 -0
- package/dist/clients/base/types.js +1 -0
- package/dist/clients/callbacks.d.ts +8 -0
- package/dist/clients/callbacks.js +42 -0
- package/dist/clients/consumer/consumer.d.ts +33 -0
- package/dist/clients/consumer/consumer.js +767 -0
- package/dist/clients/consumer/index.d.ts +5 -0
- package/dist/clients/consumer/index.js +5 -0
- package/dist/clients/consumer/messages-stream.d.ts +56 -0
- package/dist/clients/consumer/messages-stream.js +404 -0
- package/dist/clients/consumer/options.d.ts +521 -0
- package/dist/clients/consumer/options.js +177 -0
- package/dist/clients/consumer/topics-map.d.ts +8 -0
- package/dist/clients/consumer/topics-map.js +48 -0
- package/dist/clients/consumer/types.d.ts +74 -0
- package/dist/clients/consumer/types.js +11 -0
- package/dist/clients/index.d.ts +6 -0
- package/dist/clients/index.js +6 -0
- package/dist/clients/producer/index.d.ts +3 -0
- package/dist/clients/producer/index.js +3 -0
- package/dist/clients/producer/options.d.ts +122 -0
- package/dist/clients/producer/options.js +47 -0
- package/dist/clients/producer/producer.d.ts +13 -0
- package/dist/clients/producer/producer.js +272 -0
- package/dist/clients/producer/types.d.ts +29 -0
- package/dist/clients/producer/types.js +1 -0
- package/dist/clients/serde.d.ts +40 -0
- package/dist/clients/serde.js +49 -0
- package/dist/errors.d.ts +67 -0
- package/dist/errors.js +160 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +10 -0
- package/dist/network/connection-pool.d.ts +11 -0
- package/dist/network/connection-pool.js +101 -0
- package/dist/network/connection.d.ts +49 -0
- package/dist/network/connection.js +319 -0
- package/dist/network/index.d.ts +2 -0
- package/dist/network/index.js +2 -0
- package/dist/protocol/apis.d.ts +2 -0
- package/dist/protocol/apis.js +191 -0
- package/dist/protocol/compression.d.ts +70 -0
- package/dist/protocol/compression.js +114 -0
- package/dist/protocol/crc32c.d.ts +2 -0
- package/dist/protocol/crc32c.js +83 -0
- package/dist/protocol/definitions.d.ts +12 -0
- package/dist/protocol/definitions.js +11 -0
- package/dist/protocol/dynamic-buffer.d.ts +65 -0
- package/dist/protocol/dynamic-buffer.js +557 -0
- package/dist/protocol/errors.d.ts +8 -0
- package/dist/protocol/errors.js +908 -0
- package/dist/protocol/index.d.ts +14 -0
- package/dist/protocol/index.js +14 -0
- package/dist/protocol/murmur2.d.ts +1 -0
- package/dist/protocol/murmur2.js +55 -0
- package/dist/protocol/reader.d.ts +58 -0
- package/dist/protocol/reader.js +296 -0
- package/dist/protocol/records.d.ts +110 -0
- package/dist/protocol/records.js +149 -0
- package/dist/protocol/sasl/plain.d.ts +3 -0
- package/dist/protocol/sasl/plain.js +3 -0
- package/dist/protocol/sasl/scram-sha.d.ts +28 -0
- package/dist/protocol/sasl/scram-sha.js +104 -0
- package/dist/protocol/varint.d.ts +12 -0
- package/dist/protocol/varint.js +36 -0
- package/dist/protocol/writer.d.ts +48 -0
- package/dist/protocol/writer.js +223 -0
- package/dist/utils.d.ts +20 -0
- package/dist/utils.js +127 -0
- package/package.json +75 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import fastq from 'fastq';
|
|
2
|
+
import EventEmitter from 'node:events';
|
|
3
|
+
import { createConnection } from 'node:net';
|
|
4
|
+
import { connect as createTLSConnection } from 'node:tls';
|
|
5
|
+
import { createPromisifiedCallback, kCallbackPromise } from "../clients/callbacks.js";
|
|
6
|
+
import { NetworkError, TimeoutError, UnexpectedCorrelationIdError } from "../errors.js";
|
|
7
|
+
import { protocolAPIsById } from "../protocol/apis.js";
|
|
8
|
+
import { EMPTY_OR_SINGLE_COMPACT_LENGTH_SIZE, INT32_SIZE } from "../protocol/definitions.js";
|
|
9
|
+
import { DynamicBuffer } from "../protocol/dynamic-buffer.js";
|
|
10
|
+
import { Reader } from "../protocol/reader.js";
|
|
11
|
+
import { Writer } from "../protocol/writer.js";
|
|
12
|
+
import { loggers } from "../utils.js";
|
|
13
|
+
export const ConnectionStatuses = {
|
|
14
|
+
NONE: 'none',
|
|
15
|
+
CONNECTING: 'connecting',
|
|
16
|
+
CONNECTED: 'connected',
|
|
17
|
+
CLOSED: 'closed',
|
|
18
|
+
CLOSING: 'closing',
|
|
19
|
+
ERROR: 'error'
|
|
20
|
+
};
|
|
21
|
+
export const defaultOptions = {
|
|
22
|
+
connectTimeout: 5000,
|
|
23
|
+
maxInflights: 5
|
|
24
|
+
};
|
|
25
|
+
const kNoResponse = Symbol('plt.kafka.noResponse');
|
|
26
|
+
/* c8 ignore next */
|
|
27
|
+
export function noResponseCallback(..._) { }
|
|
28
|
+
noResponseCallback[kNoResponse] = true;
|
|
29
|
+
export class Connection extends EventEmitter {
|
|
30
|
+
#options;
|
|
31
|
+
#status;
|
|
32
|
+
#clientId;
|
|
33
|
+
// @ts-ignore This is used just for debugging
|
|
34
|
+
#ownerId;
|
|
35
|
+
#correlationId;
|
|
36
|
+
#nextMessage;
|
|
37
|
+
#afterDrainRequests;
|
|
38
|
+
#requestsQueue;
|
|
39
|
+
#inflightRequests;
|
|
40
|
+
#responseBuffer;
|
|
41
|
+
#responseReader;
|
|
42
|
+
#socket;
|
|
43
|
+
#socketMustBeDrained;
|
|
44
|
+
constructor(clientId, options = {}) {
|
|
45
|
+
super();
|
|
46
|
+
this.setMaxListeners(0);
|
|
47
|
+
this.#options = Object.assign({}, defaultOptions, options);
|
|
48
|
+
this.#status = ConnectionStatuses.NONE;
|
|
49
|
+
this.#clientId = clientId;
|
|
50
|
+
this.#ownerId = options.ownerId;
|
|
51
|
+
this.#correlationId = 0;
|
|
52
|
+
this.#nextMessage = 0;
|
|
53
|
+
this.#afterDrainRequests = [];
|
|
54
|
+
this.#requestsQueue = fastq((op, cb) => op(cb), this.#options.maxInflights);
|
|
55
|
+
this.#inflightRequests = new Map();
|
|
56
|
+
this.#responseBuffer = new DynamicBuffer();
|
|
57
|
+
this.#responseReader = new Reader(this.#responseBuffer);
|
|
58
|
+
this.#socketMustBeDrained = false;
|
|
59
|
+
}
|
|
60
|
+
get status() {
|
|
61
|
+
return this.#status;
|
|
62
|
+
}
|
|
63
|
+
get socket() {
|
|
64
|
+
return this.#socket;
|
|
65
|
+
}
|
|
66
|
+
connect(host, port, callback) {
|
|
67
|
+
if (!callback) {
|
|
68
|
+
callback = createPromisifiedCallback();
|
|
69
|
+
}
|
|
70
|
+
if (this.#status === ConnectionStatuses.CONNECTED) {
|
|
71
|
+
callback(null);
|
|
72
|
+
return callback[kCallbackPromise];
|
|
73
|
+
}
|
|
74
|
+
this.ready(callback);
|
|
75
|
+
if (this.#status === ConnectionStatuses.CONNECTING) {
|
|
76
|
+
return callback[kCallbackPromise];
|
|
77
|
+
}
|
|
78
|
+
this.#status = ConnectionStatuses.CONNECTING;
|
|
79
|
+
const connectionOptions = {
|
|
80
|
+
timeout: this.#options.connectTimeout
|
|
81
|
+
};
|
|
82
|
+
const connectionTimeoutHandler = () => {
|
|
83
|
+
const error = new TimeoutError(`Connection to ${host}:${port} timed out.`);
|
|
84
|
+
this.#socket.destroy();
|
|
85
|
+
this.#status = ConnectionStatuses.ERROR;
|
|
86
|
+
this.emit('timeout', error);
|
|
87
|
+
this.emit('error', error);
|
|
88
|
+
};
|
|
89
|
+
const connectionErrorHandler = (e) => {
|
|
90
|
+
const error = new NetworkError(`Connection to ${host}:${port} failed.`, { cause: e });
|
|
91
|
+
this.#status = ConnectionStatuses.ERROR;
|
|
92
|
+
this.emit('error', error);
|
|
93
|
+
};
|
|
94
|
+
this.emit('connecting');
|
|
95
|
+
/* c8 ignore next 3 */
|
|
96
|
+
this.#socket = this.#options.tls
|
|
97
|
+
? createTLSConnection(port, host, { ...this.#options.tls, ...connectionOptions })
|
|
98
|
+
: createConnection({ ...connectionOptions, port, host });
|
|
99
|
+
this.#socket.setNoDelay(true);
|
|
100
|
+
this.#socket.once('connect', () => {
|
|
101
|
+
this.#socket.removeListener('timeout', connectionTimeoutHandler);
|
|
102
|
+
this.#socket.removeListener('error', connectionErrorHandler);
|
|
103
|
+
this.#socket.on('error', this.#onError.bind(this));
|
|
104
|
+
this.#socket.on('data', this.#onData.bind(this));
|
|
105
|
+
this.#socket.on('drain', this.#onDrain.bind(this));
|
|
106
|
+
this.#socket.on('close', this.#onClose.bind(this));
|
|
107
|
+
this.#socket.setTimeout(0);
|
|
108
|
+
this.#status = ConnectionStatuses.CONNECTED;
|
|
109
|
+
this.emit('connect');
|
|
110
|
+
});
|
|
111
|
+
this.#socket.once('timeout', connectionTimeoutHandler);
|
|
112
|
+
this.#socket.once('error', connectionErrorHandler);
|
|
113
|
+
return callback[kCallbackPromise];
|
|
114
|
+
}
|
|
115
|
+
ready(callback) {
|
|
116
|
+
if (!callback) {
|
|
117
|
+
callback = createPromisifiedCallback();
|
|
118
|
+
}
|
|
119
|
+
const onConnect = () => {
|
|
120
|
+
this.removeListener('error', onError);
|
|
121
|
+
callback(null);
|
|
122
|
+
};
|
|
123
|
+
const onError = (error) => {
|
|
124
|
+
this.removeListener('connect', onConnect);
|
|
125
|
+
callback(error);
|
|
126
|
+
};
|
|
127
|
+
this.once('connect', onConnect);
|
|
128
|
+
this.once('error', onError);
|
|
129
|
+
this.emit('ready');
|
|
130
|
+
return callback[kCallbackPromise];
|
|
131
|
+
}
|
|
132
|
+
close(callback) {
|
|
133
|
+
if (!callback) {
|
|
134
|
+
callback = createPromisifiedCallback();
|
|
135
|
+
}
|
|
136
|
+
if (this.#status === ConnectionStatuses.CLOSED ||
|
|
137
|
+
this.#status === ConnectionStatuses.ERROR ||
|
|
138
|
+
this.#status === ConnectionStatuses.NONE) {
|
|
139
|
+
callback(null);
|
|
140
|
+
return callback[kCallbackPromise];
|
|
141
|
+
}
|
|
142
|
+
else if (this.#status === ConnectionStatuses.CLOSING) {
|
|
143
|
+
this.once('close', () => {
|
|
144
|
+
callback(null);
|
|
145
|
+
});
|
|
146
|
+
return callback[kCallbackPromise];
|
|
147
|
+
}
|
|
148
|
+
// Ignore all disconnection errors
|
|
149
|
+
this.#socket.removeAllListeners('error');
|
|
150
|
+
this.#socket.once('error', () => { });
|
|
151
|
+
this.#socket.once('close', () => {
|
|
152
|
+
this.#status = ConnectionStatuses.CLOSED;
|
|
153
|
+
this.emit('close');
|
|
154
|
+
callback(null);
|
|
155
|
+
});
|
|
156
|
+
this.#status = ConnectionStatuses.CLOSING;
|
|
157
|
+
this.emit('closing');
|
|
158
|
+
this.#socket.end();
|
|
159
|
+
return callback[kCallbackPromise];
|
|
160
|
+
}
|
|
161
|
+
send(apiKey, apiVersion, payload, responseParser, hasRequestHeaderTaggedFields, hasResponseHeaderTaggedFields, callback) {
|
|
162
|
+
this.#requestsQueue.push(fastQueueCallback => {
|
|
163
|
+
const correlationId = ++this.#correlationId;
|
|
164
|
+
const request = {
|
|
165
|
+
correlationId,
|
|
166
|
+
apiKey,
|
|
167
|
+
apiVersion,
|
|
168
|
+
hasRequestHeaderTaggedFields,
|
|
169
|
+
hasResponseHeaderTaggedFields,
|
|
170
|
+
parser: responseParser,
|
|
171
|
+
payload,
|
|
172
|
+
callback: fastQueueCallback
|
|
173
|
+
};
|
|
174
|
+
if (this.#socketMustBeDrained) {
|
|
175
|
+
this.#afterDrainRequests.push(request);
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
return this.#sendRequest(request);
|
|
179
|
+
}, callback);
|
|
180
|
+
}
|
|
181
|
+
/*
|
|
182
|
+
Request => Size [Request Header v2] [payload]
|
|
183
|
+
Request Header v2 => request_api_key request_api_version correlation_id client_id TAG_BUFFER
|
|
184
|
+
request_api_key => INT16
|
|
185
|
+
request_api_version => INT16
|
|
186
|
+
correlation_id => INT32
|
|
187
|
+
client_id => NULLABLE_STRING
|
|
188
|
+
*/
|
|
189
|
+
#sendRequest(request) {
|
|
190
|
+
if (this.#status !== ConnectionStatuses.CONNECTED) {
|
|
191
|
+
request.callback(new NetworkError('Connection closed'), undefined);
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
let canWrite = true;
|
|
195
|
+
const { correlationId, apiKey, apiVersion, payload: payloadFn, hasRequestHeaderTaggedFields } = request;
|
|
196
|
+
const writer = Writer.create()
|
|
197
|
+
.appendInt16(apiKey)
|
|
198
|
+
.appendInt16(apiVersion)
|
|
199
|
+
.appendInt32(correlationId)
|
|
200
|
+
.appendString(this.#clientId, false);
|
|
201
|
+
if (hasRequestHeaderTaggedFields) {
|
|
202
|
+
writer.appendTaggedFields();
|
|
203
|
+
}
|
|
204
|
+
const payload = payloadFn();
|
|
205
|
+
writer.appendFrom(payload);
|
|
206
|
+
writer.prependLength();
|
|
207
|
+
// Write the header
|
|
208
|
+
this.#socket.cork();
|
|
209
|
+
if (!payload.context.noResponse) {
|
|
210
|
+
this.#inflightRequests.set(correlationId, request);
|
|
211
|
+
}
|
|
212
|
+
/* c8 ignore next */
|
|
213
|
+
loggers.protocol({ apiKey: protocolAPIsById[apiKey], correlationId, request }, 'Sending request.');
|
|
214
|
+
for (const buf of writer.buffers) {
|
|
215
|
+
if (!this.#socket.write(buf)) {
|
|
216
|
+
canWrite = false;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (!canWrite) {
|
|
220
|
+
this.#socketMustBeDrained = true;
|
|
221
|
+
}
|
|
222
|
+
this.#socket.uncork();
|
|
223
|
+
if (payload.context.noResponse) {
|
|
224
|
+
request.callback(null, canWrite);
|
|
225
|
+
}
|
|
226
|
+
// debugDump(Date.now() % 100000, 'send', { owner: this.#ownerId, apiKey: protocolAPIsById[apiKey], correlationId })
|
|
227
|
+
return canWrite;
|
|
228
|
+
}
|
|
229
|
+
/*
|
|
230
|
+
Response Header v1 => correlation_id TAG_BUFFER
|
|
231
|
+
correlation_id => INT32
|
|
232
|
+
*/
|
|
233
|
+
#onData(chunk) {
|
|
234
|
+
this.#responseBuffer.append(chunk);
|
|
235
|
+
// There is at least one message size to add
|
|
236
|
+
// Note that here the initial position is always 0
|
|
237
|
+
while (this.#responseBuffer.length > INT32_SIZE) {
|
|
238
|
+
if (this.#nextMessage < 1) {
|
|
239
|
+
this.#nextMessage = this.#responseReader.readInt32();
|
|
240
|
+
}
|
|
241
|
+
// Less data than the message size, wait for more data
|
|
242
|
+
if (this.#nextMessage > this.#responseBuffer.length - INT32_SIZE) {
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
// Read the correlationId and get the handler
|
|
246
|
+
const correlationId = this.#responseReader.readInt32();
|
|
247
|
+
const request = this.#inflightRequests.get(correlationId);
|
|
248
|
+
if (!request) {
|
|
249
|
+
this.emit('error', new UnexpectedCorrelationIdError(`Received unexpected response with correlation_id=${correlationId}`, {
|
|
250
|
+
raw: this.#responseReader.buffer.slice(0, this.#nextMessage + INT32_SIZE)
|
|
251
|
+
}));
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
this.#inflightRequests.delete(correlationId);
|
|
255
|
+
const { apiKey, apiVersion, hasResponseHeaderTaggedFields, parser, callback } = request;
|
|
256
|
+
let deserialized;
|
|
257
|
+
let responseError = null;
|
|
258
|
+
try {
|
|
259
|
+
// Due to inconsistency in the wire protocol, the tag buffer in the header might have to be handled by the APIs
|
|
260
|
+
// For example: https://github.com/apache/kafka/blob/84caaa6e9da06435411510a81fa321d4f99c351f/clients/src/main/resources/common/message/ApiVersionsResponse.json#L24
|
|
261
|
+
if (hasResponseHeaderTaggedFields) {
|
|
262
|
+
this.#responseReader.skip(EMPTY_OR_SINGLE_COMPACT_LENGTH_SIZE);
|
|
263
|
+
}
|
|
264
|
+
deserialized = parser(correlationId, apiKey, apiVersion, new Reader(this.#responseReader.buffer.subarray(this.#responseReader.position, this.#nextMessage + INT32_SIZE)));
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
responseError = error;
|
|
268
|
+
// debugDump(Date.now() % 100000, 'received error', {
|
|
269
|
+
// owner: this.#ownerId,
|
|
270
|
+
// apiKey: protocolAPIsById[apiKey],
|
|
271
|
+
// error
|
|
272
|
+
// })
|
|
273
|
+
}
|
|
274
|
+
finally {
|
|
275
|
+
this.#responseBuffer.consume(this.#nextMessage + INT32_SIZE);
|
|
276
|
+
this.#responseReader.position = 0;
|
|
277
|
+
this.#nextMessage = -1;
|
|
278
|
+
}
|
|
279
|
+
// debugDump(Date.now() % 100000, 'receive', {
|
|
280
|
+
// owner: this.#ownerId,
|
|
281
|
+
// apiKey: protocolAPIsById[apiKey],
|
|
282
|
+
// correlationId
|
|
283
|
+
// })
|
|
284
|
+
/* c8 ignore next */
|
|
285
|
+
loggers.protocol({ apiKey: protocolAPIsById[apiKey], correlationId, request }, 'Received response.');
|
|
286
|
+
callback(responseError, deserialized);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
#onDrain() {
|
|
290
|
+
// First of all, send all the requests that were waiting for the socket to drain
|
|
291
|
+
while (this.#afterDrainRequests.length) {
|
|
292
|
+
const request = this.#afterDrainRequests.shift();
|
|
293
|
+
// If no more request or after sending the request the socket is blocked again, abort
|
|
294
|
+
if (!request || !this.#sendRequest(request)) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// Start getting requests again
|
|
299
|
+
this.#socketMustBeDrained = false;
|
|
300
|
+
this.emit('drain');
|
|
301
|
+
}
|
|
302
|
+
#onClose() {
|
|
303
|
+
this.#status = ConnectionStatuses.CLOSED;
|
|
304
|
+
this.emit('close');
|
|
305
|
+
const error = new NetworkError('Connection closed');
|
|
306
|
+
for (const request of this.#afterDrainRequests) {
|
|
307
|
+
const payload = request.payload();
|
|
308
|
+
if (!payload.context.noResponse) {
|
|
309
|
+
request.callback(error, undefined);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
for (const inflight of this.#inflightRequests.values()) {
|
|
313
|
+
inflight.callback(error, undefined);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
#onError(error) {
|
|
317
|
+
this.emit('error', new NetworkError('Connection error', { cause: error }));
|
|
318
|
+
}
|
|
319
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// This is autogenerated from the generate:apis script, do not edit manually.
|
|
2
|
+
export const protocolAPIsByName = Object.freeze({
|
|
3
|
+
AddOffsetsToTxn: 25,
|
|
4
|
+
AddPartitionsToTxn: 24,
|
|
5
|
+
AddRaftVoter: 80,
|
|
6
|
+
AllocateProducerIds: 67,
|
|
7
|
+
AlterClientQuotas: 49,
|
|
8
|
+
AlterConfigs: 33,
|
|
9
|
+
AlterPartitionReassignments: 45,
|
|
10
|
+
AlterPartition: 56,
|
|
11
|
+
AlterReplicaLogDirs: 34,
|
|
12
|
+
AlterShareGroupOffsets: 91,
|
|
13
|
+
AlterUserScramCredentials: 51,
|
|
14
|
+
ApiVersions: 18,
|
|
15
|
+
AssignReplicasToDirs: 73,
|
|
16
|
+
BeginQuorumEpoch: 53,
|
|
17
|
+
BrokerHeartbeat: 63,
|
|
18
|
+
BrokerRegistration: 62,
|
|
19
|
+
ConsumerGroupDescribe: 69,
|
|
20
|
+
ConsumerGroupHeartbeat: 68,
|
|
21
|
+
ControlledShutdown: 7,
|
|
22
|
+
ControllerRegistration: 70,
|
|
23
|
+
CreateAcls: 30,
|
|
24
|
+
CreateDelegationToken: 38,
|
|
25
|
+
CreatePartitions: 37,
|
|
26
|
+
CreateTopics: 19,
|
|
27
|
+
DeleteAcls: 31,
|
|
28
|
+
DeleteGroups: 42,
|
|
29
|
+
DeleteRecords: 21,
|
|
30
|
+
DeleteShareGroupOffsets: 92,
|
|
31
|
+
DeleteShareGroupState: 86,
|
|
32
|
+
DeleteTopics: 20,
|
|
33
|
+
DescribeAcls: 29,
|
|
34
|
+
DescribeClientQuotas: 48,
|
|
35
|
+
DescribeCluster: 60,
|
|
36
|
+
DescribeConfigs: 32,
|
|
37
|
+
DescribeDelegationToken: 41,
|
|
38
|
+
DescribeGroups: 15,
|
|
39
|
+
DescribeLogDirs: 35,
|
|
40
|
+
DescribeProducers: 61,
|
|
41
|
+
DescribeQuorum: 55,
|
|
42
|
+
DescribeShareGroupOffsets: 90,
|
|
43
|
+
DescribeTopicPartitions: 75,
|
|
44
|
+
DescribeTransactions: 65,
|
|
45
|
+
DescribeUserScramCredentials: 50,
|
|
46
|
+
ElectLeaders: 43,
|
|
47
|
+
EndQuorumEpoch: 54,
|
|
48
|
+
EndTxn: 26,
|
|
49
|
+
Envelope: 58,
|
|
50
|
+
ExpireDelegationToken: 40,
|
|
51
|
+
Fetch: 1,
|
|
52
|
+
FetchSnapshot: 59,
|
|
53
|
+
FindCoordinator: 10,
|
|
54
|
+
GetTelemetrySubscriptions: 71,
|
|
55
|
+
Heartbeat: 12,
|
|
56
|
+
IncrementalAlterConfigs: 44,
|
|
57
|
+
InitProducerId: 22,
|
|
58
|
+
InitializeShareGroupState: 83,
|
|
59
|
+
JoinGroup: 11,
|
|
60
|
+
LeaderAndIsr: 4,
|
|
61
|
+
LeaveGroup: 13,
|
|
62
|
+
ListClientMetricsResources: 74,
|
|
63
|
+
ListGroups: 16,
|
|
64
|
+
ListOffsets: 2,
|
|
65
|
+
ListPartitionReassignments: 46,
|
|
66
|
+
ListTransactions: 66,
|
|
67
|
+
Metadata: 3,
|
|
68
|
+
OffsetCommit: 8,
|
|
69
|
+
OffsetDelete: 47,
|
|
70
|
+
OffsetFetch: 9,
|
|
71
|
+
OffsetForLeaderEpoch: 23,
|
|
72
|
+
Produce: 0,
|
|
73
|
+
PushTelemetry: 72,
|
|
74
|
+
ReadShareGroupState: 84,
|
|
75
|
+
ReadShareGroupStateSummary: 87,
|
|
76
|
+
RemoveRaftVoter: 81,
|
|
77
|
+
RenewDelegationToken: 39,
|
|
78
|
+
SaslAuthenticate: 36,
|
|
79
|
+
SaslHandshake: 17,
|
|
80
|
+
ShareAcknowledge: 79,
|
|
81
|
+
ShareFetch: 78,
|
|
82
|
+
ShareGroupDescribe: 77,
|
|
83
|
+
ShareGroupHeartbeat: 76,
|
|
84
|
+
StopReplica: 5,
|
|
85
|
+
StreamsGroupDescribe: 89,
|
|
86
|
+
StreamsGroupHeartbeat: 88,
|
|
87
|
+
SyncGroup: 14,
|
|
88
|
+
TxnOffsetCommit: 28,
|
|
89
|
+
UnregisterBroker: 64,
|
|
90
|
+
UpdateFeatures: 57,
|
|
91
|
+
UpdateMetadata: 6,
|
|
92
|
+
UpdateRaftVoter: 82,
|
|
93
|
+
Vote: 52,
|
|
94
|
+
WriteShareGroupState: 85,
|
|
95
|
+
WriteTxnMarkers: 27
|
|
96
|
+
});
|
|
97
|
+
export const protocolAPIsById = Object.freeze({
|
|
98
|
+
0: 'Produce',
|
|
99
|
+
1: 'Fetch',
|
|
100
|
+
2: 'ListOffsets',
|
|
101
|
+
3: 'Metadata',
|
|
102
|
+
4: 'LeaderAndIsr',
|
|
103
|
+
5: 'StopReplica',
|
|
104
|
+
6: 'UpdateMetadata',
|
|
105
|
+
7: 'ControlledShutdown',
|
|
106
|
+
8: 'OffsetCommit',
|
|
107
|
+
9: 'OffsetFetch',
|
|
108
|
+
10: 'FindCoordinator',
|
|
109
|
+
11: 'JoinGroup',
|
|
110
|
+
12: 'Heartbeat',
|
|
111
|
+
13: 'LeaveGroup',
|
|
112
|
+
14: 'SyncGroup',
|
|
113
|
+
15: 'DescribeGroups',
|
|
114
|
+
16: 'ListGroups',
|
|
115
|
+
17: 'SaslHandshake',
|
|
116
|
+
18: 'ApiVersions',
|
|
117
|
+
19: 'CreateTopics',
|
|
118
|
+
20: 'DeleteTopics',
|
|
119
|
+
21: 'DeleteRecords',
|
|
120
|
+
22: 'InitProducerId',
|
|
121
|
+
23: 'OffsetForLeaderEpoch',
|
|
122
|
+
24: 'AddPartitionsToTxn',
|
|
123
|
+
25: 'AddOffsetsToTxn',
|
|
124
|
+
26: 'EndTxn',
|
|
125
|
+
27: 'WriteTxnMarkers',
|
|
126
|
+
28: 'TxnOffsetCommit',
|
|
127
|
+
29: 'DescribeAcls',
|
|
128
|
+
30: 'CreateAcls',
|
|
129
|
+
31: 'DeleteAcls',
|
|
130
|
+
32: 'DescribeConfigs',
|
|
131
|
+
33: 'AlterConfigs',
|
|
132
|
+
34: 'AlterReplicaLogDirs',
|
|
133
|
+
35: 'DescribeLogDirs',
|
|
134
|
+
36: 'SaslAuthenticate',
|
|
135
|
+
37: 'CreatePartitions',
|
|
136
|
+
38: 'CreateDelegationToken',
|
|
137
|
+
39: 'RenewDelegationToken',
|
|
138
|
+
40: 'ExpireDelegationToken',
|
|
139
|
+
41: 'DescribeDelegationToken',
|
|
140
|
+
42: 'DeleteGroups',
|
|
141
|
+
43: 'ElectLeaders',
|
|
142
|
+
44: 'IncrementalAlterConfigs',
|
|
143
|
+
45: 'AlterPartitionReassignments',
|
|
144
|
+
46: 'ListPartitionReassignments',
|
|
145
|
+
47: 'OffsetDelete',
|
|
146
|
+
48: 'DescribeClientQuotas',
|
|
147
|
+
49: 'AlterClientQuotas',
|
|
148
|
+
50: 'DescribeUserScramCredentials',
|
|
149
|
+
51: 'AlterUserScramCredentials',
|
|
150
|
+
52: 'Vote',
|
|
151
|
+
53: 'BeginQuorumEpoch',
|
|
152
|
+
54: 'EndQuorumEpoch',
|
|
153
|
+
55: 'DescribeQuorum',
|
|
154
|
+
56: 'AlterPartition',
|
|
155
|
+
57: 'UpdateFeatures',
|
|
156
|
+
58: 'Envelope',
|
|
157
|
+
59: 'FetchSnapshot',
|
|
158
|
+
60: 'DescribeCluster',
|
|
159
|
+
61: 'DescribeProducers',
|
|
160
|
+
62: 'BrokerRegistration',
|
|
161
|
+
63: 'BrokerHeartbeat',
|
|
162
|
+
64: 'UnregisterBroker',
|
|
163
|
+
65: 'DescribeTransactions',
|
|
164
|
+
66: 'ListTransactions',
|
|
165
|
+
67: 'AllocateProducerIds',
|
|
166
|
+
68: 'ConsumerGroupHeartbeat',
|
|
167
|
+
69: 'ConsumerGroupDescribe',
|
|
168
|
+
70: 'ControllerRegistration',
|
|
169
|
+
71: 'GetTelemetrySubscriptions',
|
|
170
|
+
72: 'PushTelemetry',
|
|
171
|
+
73: 'AssignReplicasToDirs',
|
|
172
|
+
74: 'ListClientMetricsResources',
|
|
173
|
+
75: 'DescribeTopicPartitions',
|
|
174
|
+
76: 'ShareGroupHeartbeat',
|
|
175
|
+
77: 'ShareGroupDescribe',
|
|
176
|
+
78: 'ShareFetch',
|
|
177
|
+
79: 'ShareAcknowledge',
|
|
178
|
+
80: 'AddRaftVoter',
|
|
179
|
+
81: 'RemoveRaftVoter',
|
|
180
|
+
82: 'UpdateRaftVoter',
|
|
181
|
+
83: 'InitializeShareGroupState',
|
|
182
|
+
84: 'ReadShareGroupState',
|
|
183
|
+
85: 'WriteShareGroupState',
|
|
184
|
+
86: 'DeleteShareGroupState',
|
|
185
|
+
87: 'ReadShareGroupStateSummary',
|
|
186
|
+
88: 'StreamsGroupHeartbeat',
|
|
187
|
+
89: 'StreamsGroupDescribe',
|
|
188
|
+
90: 'DescribeShareGroupOffsets',
|
|
189
|
+
91: 'AlterShareGroupOffsets',
|
|
190
|
+
92: 'DeleteShareGroupOffsets'
|
|
191
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { DynamicBuffer } from './dynamic-buffer.ts';
|
|
2
|
+
export type SyncCompressionPhase = (data: Buffer | DynamicBuffer) => Buffer;
|
|
3
|
+
export type CompressionOperation = (data: Buffer) => Buffer;
|
|
4
|
+
export interface CompressionAlgorithm {
|
|
5
|
+
compressSync: SyncCompressionPhase;
|
|
6
|
+
decompressSync: SyncCompressionPhase;
|
|
7
|
+
bitmask: number;
|
|
8
|
+
available?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare const compressionsAlgorithms: {
|
|
11
|
+
readonly none: {
|
|
12
|
+
readonly compressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
13
|
+
readonly decompressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
14
|
+
readonly bitmask: 0;
|
|
15
|
+
readonly available: true;
|
|
16
|
+
};
|
|
17
|
+
readonly gzip: {
|
|
18
|
+
readonly compressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
19
|
+
readonly decompressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
20
|
+
readonly bitmask: 1;
|
|
21
|
+
readonly available: true;
|
|
22
|
+
};
|
|
23
|
+
readonly snappy: {
|
|
24
|
+
readonly compressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
25
|
+
readonly decompressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
26
|
+
readonly bitmask: 2;
|
|
27
|
+
readonly available: true;
|
|
28
|
+
};
|
|
29
|
+
readonly lz4: {
|
|
30
|
+
readonly compressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
31
|
+
readonly decompressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
32
|
+
readonly bitmask: 3;
|
|
33
|
+
readonly available: true;
|
|
34
|
+
};
|
|
35
|
+
readonly zstd: {
|
|
36
|
+
readonly compressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
37
|
+
readonly decompressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
38
|
+
readonly bitmask: 4;
|
|
39
|
+
readonly available: boolean;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
export declare const compressionsAlgorithmsByBitmask: {
|
|
43
|
+
[k: string]: {
|
|
44
|
+
readonly compressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
45
|
+
readonly decompressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
46
|
+
readonly bitmask: 0;
|
|
47
|
+
readonly available: true;
|
|
48
|
+
} | {
|
|
49
|
+
readonly compressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
50
|
+
readonly decompressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
51
|
+
readonly bitmask: 1;
|
|
52
|
+
readonly available: true;
|
|
53
|
+
} | {
|
|
54
|
+
readonly compressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
55
|
+
readonly decompressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
56
|
+
readonly bitmask: 2;
|
|
57
|
+
readonly available: true;
|
|
58
|
+
} | {
|
|
59
|
+
readonly compressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
60
|
+
readonly decompressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
61
|
+
readonly bitmask: 3;
|
|
62
|
+
readonly available: true;
|
|
63
|
+
} | {
|
|
64
|
+
readonly compressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
65
|
+
readonly decompressSync: (data: Buffer | DynamicBuffer) => Buffer;
|
|
66
|
+
readonly bitmask: 4;
|
|
67
|
+
readonly available: boolean;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
export type CompressionAlgorithms = keyof typeof compressionsAlgorithms;
|