coakka-v2-connector-node 1.3.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/CONSUMING.md +48 -0
- package/LICENSE.md +115 -0
- package/README.md +147 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +5 -0
- package/dist/models.d.ts +119 -0
- package/dist/models.js +150 -0
- package/dist/orchestrator.d.ts +80 -0
- package/dist/orchestrator.js +260 -0
- package/dist/packaging.d.ts +4 -0
- package/dist/packaging.js +4 -0
- package/dist/protobuf.d.ts +63 -0
- package/dist/protobuf.js +323 -0
- package/dist/runtime-client.d.ts +124 -0
- package/dist/runtime-client.js +922 -0
- package/dist/runtime-ffi.d.ts +105 -0
- package/dist/runtime-ffi.js +282 -0
- package/native/.gitkeep +1 -0
- package/native/linux-aarch64/libcoakka_runtime_v2-1.3.1+bda2ef5.so +0 -0
- package/native/linux-aarch64/libcoakka_runtime_v2.so +0 -0
- package/native/linux-x86_64/libcoakka_runtime_v2-1.3.1+bda2ef5.so +0 -0
- package/native/linux-x86_64/libcoakka_runtime_v2.so +0 -0
- package/native/macos-aarch64/libcoakka_runtime_v2-1.3.1+bda2ef5.dylib +0 -0
- package/native/macos-aarch64/libcoakka_runtime_v2.dylib +0 -0
- package/native/windows-aarch64/libcoakka_runtime_v2-1.3.1+bda2ef5.dll +0 -0
- package/native/windows-aarch64/libcoakka_runtime_v2.dll +0 -0
- package/native/windows-x86_64/libcoakka_runtime_v2-1.3.1+bda2ef5.dll +0 -0
- package/native/windows-x86_64/libcoakka_runtime_v2.dll +0 -0
- package/package.json +35 -0
- package/vendor/koffi/LICENSE.txt +22 -0
- package/vendor/koffi/build/koffi/darwin_arm64/koffi.node +0 -0
- package/vendor/koffi/build/koffi/darwin_x64/koffi.node +0 -0
- package/vendor/koffi/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/vendor/koffi/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/vendor/koffi/build/koffi/freebsd_x64/koffi.node +0 -0
- package/vendor/koffi/build/koffi/linux_arm64/koffi.node +0 -0
- package/vendor/koffi/build/koffi/linux_armhf/koffi.node +0 -0
- package/vendor/koffi/build/koffi/linux_ia32/koffi.node +0 -0
- package/vendor/koffi/build/koffi/linux_loong64/koffi.node +0 -0
- package/vendor/koffi/build/koffi/linux_riscv64d/koffi.node +0 -0
- package/vendor/koffi/build/koffi/linux_x64/koffi.node +0 -0
- package/vendor/koffi/build/koffi/musl_arm64/koffi.node +0 -0
- package/vendor/koffi/build/koffi/musl_x64/koffi.node +0 -0
- package/vendor/koffi/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/vendor/koffi/build/koffi/openbsd_x64/koffi.node +0 -0
- package/vendor/koffi/build/koffi/win32_arm64/koffi.exp +0 -0
- package/vendor/koffi/build/koffi/win32_arm64/koffi.lib +0 -0
- package/vendor/koffi/build/koffi/win32_arm64/koffi.node +0 -0
- package/vendor/koffi/build/koffi/win32_ia32/koffi.exp +0 -0
- package/vendor/koffi/build/koffi/win32_ia32/koffi.lib +0 -0
- package/vendor/koffi/build/koffi/win32_ia32/koffi.node +0 -0
- package/vendor/koffi/build/koffi/win32_x64/koffi.exp +0 -0
- package/vendor/koffi/build/koffi/win32_x64/koffi.lib +0 -0
- package/vendor/koffi/build/koffi/win32_x64/koffi.node +0 -0
- package/vendor/koffi/index.d.ts +288 -0
- package/vendor/koffi/index.js +634 -0
- package/vendor/koffi/package.json +38 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { DeliveryHint, toConnectorConfig, } from "./models.js";
|
|
6
|
+
import { NodeRuntimeClient } from "./runtime-client.js";
|
|
7
|
+
import { COAKKA_V2_NATIVE_PACKAGE_VERSION } from "./packaging.js";
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const DEFAULT_LIBRARY_CANDIDATES = [
|
|
10
|
+
`libcoakka_runtime_v2-${COAKKA_V2_NATIVE_PACKAGE_VERSION}.dll`,
|
|
11
|
+
`libcoakka_runtime_v2-${COAKKA_V2_NATIVE_PACKAGE_VERSION}.dylib`,
|
|
12
|
+
`libcoakka_runtime_v2-${COAKKA_V2_NATIVE_PACKAGE_VERSION}.so`,
|
|
13
|
+
"libcoakka_runtime_v2.dll",
|
|
14
|
+
"libcoakka_runtime_v2.dylib",
|
|
15
|
+
"libcoakka_runtime_v2.so",
|
|
16
|
+
];
|
|
17
|
+
export class RuntimeLibraryResolver {
|
|
18
|
+
static envVar = "COAKKA_RUNTIME_LIB";
|
|
19
|
+
static resolve(explicitPath, candidateNames = DEFAULT_LIBRARY_CANDIDATES) {
|
|
20
|
+
if (explicitPath != null && String(explicitPath).trim() !== "") {
|
|
21
|
+
return this.requireExisting(resolve(String(explicitPath)), "explicit runtimeLibPath");
|
|
22
|
+
}
|
|
23
|
+
const configuredPath = process.env[this.envVar]?.trim();
|
|
24
|
+
if (configuredPath != null && configuredPath !== "") {
|
|
25
|
+
return this.requireExisting(resolve(configuredPath), `$${this.envVar}`);
|
|
26
|
+
}
|
|
27
|
+
const embedded = this.resolveEmbedded();
|
|
28
|
+
if (embedded != null) {
|
|
29
|
+
return embedded;
|
|
30
|
+
}
|
|
31
|
+
for (const candidate of this.searchCandidates(candidateNames)) {
|
|
32
|
+
if (existsSync(candidate)) {
|
|
33
|
+
return candidate;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
throw new Error("native runtime library was not found. " +
|
|
37
|
+
`Set ${this.envVar}, pass runtimeLibPath explicitly, or place one of ` +
|
|
38
|
+
`${candidateNames.join(", ")} under a repo-local lib/ directory or packaged native resource.`);
|
|
39
|
+
}
|
|
40
|
+
static platformId(osName = process.platform, archName = process.arch) {
|
|
41
|
+
return `${this.normalizeOs(osName)}-${this.normalizeArch(archName)}`;
|
|
42
|
+
}
|
|
43
|
+
static normalizeOs(osName) {
|
|
44
|
+
const normalized = osName.toLowerCase();
|
|
45
|
+
if (normalized === "darwin" || normalized.includes("mac")) {
|
|
46
|
+
return "macos";
|
|
47
|
+
}
|
|
48
|
+
if (normalized === "linux" || normalized.includes("linux")) {
|
|
49
|
+
return "linux";
|
|
50
|
+
}
|
|
51
|
+
if (normalized === "win32" || normalized.includes("windows")) {
|
|
52
|
+
return "windows";
|
|
53
|
+
}
|
|
54
|
+
throw new Error(`unsupported os.name=${osName}; supported platforms are macOS, Linux, and Windows`);
|
|
55
|
+
}
|
|
56
|
+
static normalizeArch(archName) {
|
|
57
|
+
const normalized = archName.toLowerCase();
|
|
58
|
+
if (normalized === "arm64" || normalized === "aarch64") {
|
|
59
|
+
return "aarch64";
|
|
60
|
+
}
|
|
61
|
+
if (normalized === "x64" || normalized === "x86_64" || normalized === "amd64") {
|
|
62
|
+
return "x86_64";
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`unsupported os.arch=${archName}; supported architectures are aarch64 and x86_64`);
|
|
65
|
+
}
|
|
66
|
+
static runtimeResourceFileNamesForCurrentPlatform(osName = process.platform) {
|
|
67
|
+
const versionedBase = `libcoakka_runtime_v2-${COAKKA_V2_NATIVE_PACKAGE_VERSION}`;
|
|
68
|
+
switch (this.normalizeOs(osName)) {
|
|
69
|
+
case "macos":
|
|
70
|
+
return [`${versionedBase}.dylib`, "libcoakka_runtime_v2.dylib", "libcoakka_runtime_v2.so"];
|
|
71
|
+
case "linux":
|
|
72
|
+
return [`${versionedBase}.so`, "libcoakka_runtime_v2.so"];
|
|
73
|
+
case "windows":
|
|
74
|
+
return [`${versionedBase}.dll`, "libcoakka_runtime_v2.dll"];
|
|
75
|
+
default:
|
|
76
|
+
throw new Error("unsupported platform");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
static resolveEmbedded() {
|
|
80
|
+
const platformId = this.platformId();
|
|
81
|
+
for (const fileName of this.runtimeResourceFileNamesForCurrentPlatform()) {
|
|
82
|
+
const resourcePath = resolve(__dirname, "..", "native", platformId, fileName);
|
|
83
|
+
if (existsSync(resourcePath)) {
|
|
84
|
+
const tempDir = mkdtempSync(resolve(tmpdir(), "coakka-runtime-node-"));
|
|
85
|
+
process.once("exit", () => rmSync(tempDir, { recursive: true, force: true }));
|
|
86
|
+
const targetPath = resolve(tempDir, fileName);
|
|
87
|
+
writeFileSync(targetPath, readFileSync(resourcePath));
|
|
88
|
+
return targetPath;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
static searchCandidates(candidateNames) {
|
|
94
|
+
const cwd = process.cwd();
|
|
95
|
+
const roots = [cwd, resolve(cwd, "lib"), resolve(cwd, "node", "lib")];
|
|
96
|
+
const candidates = [];
|
|
97
|
+
const seen = new Set();
|
|
98
|
+
for (const root of roots) {
|
|
99
|
+
for (const name of candidateNames) {
|
|
100
|
+
const candidate = root.endsWith("/lib") ? resolve(root, name) : resolve(root, "lib", name);
|
|
101
|
+
if (!seen.has(candidate)) {
|
|
102
|
+
candidates.push(candidate);
|
|
103
|
+
seen.add(candidate);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return candidates;
|
|
108
|
+
}
|
|
109
|
+
static requireExisting(path, source) {
|
|
110
|
+
if (!existsSync(path)) {
|
|
111
|
+
throw new Error(`${source} does not exist: ${path}`);
|
|
112
|
+
}
|
|
113
|
+
return path;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
class ControlApi {
|
|
117
|
+
orchestrator;
|
|
118
|
+
constructor(orchestrator) {
|
|
119
|
+
this.orchestrator = orchestrator;
|
|
120
|
+
}
|
|
121
|
+
applySnapshot(generation, routes, sourceConnector, seq = 1, overloadPolicy) {
|
|
122
|
+
this.orchestrator.applySnapshot(generation, routes, sourceConnector, seq, overloadPolicy);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
class MonitorApi {
|
|
126
|
+
orchestrator;
|
|
127
|
+
constructor(orchestrator) {
|
|
128
|
+
this.orchestrator = orchestrator;
|
|
129
|
+
}
|
|
130
|
+
isEnabled() {
|
|
131
|
+
return this.orchestrator.monitorIsEnabled();
|
|
132
|
+
}
|
|
133
|
+
snapshot(signalCount = 0) {
|
|
134
|
+
return this.orchestrator.monitorSnapshot(signalCount);
|
|
135
|
+
}
|
|
136
|
+
async awaitNext(timeoutMs = 1_000) {
|
|
137
|
+
return await this.orchestrator.awaitNextMonitor(timeoutMs);
|
|
138
|
+
}
|
|
139
|
+
async awaitAppliedGenerationAtLeast(generation, timeoutMs = 1_000) {
|
|
140
|
+
return await this.orchestrator.awaitAppliedGenerationAtLeast(generation, timeoutMs);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
export class ConnectorOrchestrator {
|
|
144
|
+
runtimeLibPath;
|
|
145
|
+
startSpec;
|
|
146
|
+
client;
|
|
147
|
+
static active = null;
|
|
148
|
+
static start(startSpec, runtimeLibPath) {
|
|
149
|
+
if (this.active != null) {
|
|
150
|
+
throw new Error("ConnectorOrchestrator already started for this Node.js process");
|
|
151
|
+
}
|
|
152
|
+
const resolvedRuntimeLibPath = RuntimeLibraryResolver.resolve(runtimeLibPath);
|
|
153
|
+
const orchestrator = new ConnectorOrchestrator(resolvedRuntimeLibPath, startSpec, new NodeRuntimeClient(resolvedRuntimeLibPath, toConnectorConfig(startSpec)));
|
|
154
|
+
this.active = orchestrator;
|
|
155
|
+
return orchestrator;
|
|
156
|
+
}
|
|
157
|
+
control;
|
|
158
|
+
monitor;
|
|
159
|
+
closed = false;
|
|
160
|
+
constructor(runtimeLibPath, startSpec, client) {
|
|
161
|
+
this.runtimeLibPath = runtimeLibPath;
|
|
162
|
+
this.startSpec = startSpec;
|
|
163
|
+
this.client = client;
|
|
164
|
+
this.control = new ControlApi(this);
|
|
165
|
+
this.monitor = new MonitorApi(this);
|
|
166
|
+
}
|
|
167
|
+
async askTyped(source, target, payload, payloadIdentity, timeoutMs = 5_000, operation = "ask", deliveryHint = DeliveryHint.ROUTER_DEFAULT, headers = {}) {
|
|
168
|
+
return await this.client.askTyped(source, target, payload, payloadIdentity, timeoutMs, operation, deliveryHint, headers);
|
|
169
|
+
}
|
|
170
|
+
async askJson(source, target, payload, payloadIdentity, timeoutMs = 5_000, operation = "ask", deliveryHint = DeliveryHint.ROUTER_DEFAULT, headers = {}) {
|
|
171
|
+
return await this.client.askJson(source, target, payload, payloadIdentity, timeoutMs, operation, deliveryHint, headers);
|
|
172
|
+
}
|
|
173
|
+
async askRaw(request, timeoutMs) {
|
|
174
|
+
return await this.client.askRaw(request, timeoutMs);
|
|
175
|
+
}
|
|
176
|
+
submitRequestTyped(source, target, payload, payloadIdentity, timeoutMs = 5_000, operation = "ask", deliveryHint = DeliveryHint.ROUTER_DEFAULT, headers = {}) {
|
|
177
|
+
return this.client.submitRequestTyped(source, target, payload, payloadIdentity, timeoutMs, operation, deliveryHint, headers);
|
|
178
|
+
}
|
|
179
|
+
submitRequestJson(source, target, payload, payloadIdentity, timeoutMs = 5_000, operation = "ask", deliveryHint = DeliveryHint.ROUTER_DEFAULT, headers = {}) {
|
|
180
|
+
return this.client.submitRequestJson(source, target, payload, payloadIdentity, timeoutMs, operation, deliveryHint, headers);
|
|
181
|
+
}
|
|
182
|
+
submitRequestRaw(request) {
|
|
183
|
+
return this.client.submitRequestRaw(request);
|
|
184
|
+
}
|
|
185
|
+
terminalEvents(options = {}) {
|
|
186
|
+
return this.client.terminalEvents(options);
|
|
187
|
+
}
|
|
188
|
+
deadletters(options = {}) {
|
|
189
|
+
return this.client.deadletters(options);
|
|
190
|
+
}
|
|
191
|
+
sendOneWayTyped(source, target, payload, payloadIdentity, deliveryHint = DeliveryHint.ROUTER_DEFAULT, headers = {}) {
|
|
192
|
+
this.client.sendOneWayTyped(source, target, payload, payloadIdentity, deliveryHint, headers);
|
|
193
|
+
}
|
|
194
|
+
sendOneWayJson(source, target, payload, payloadIdentity, deliveryHint = DeliveryHint.ROUTER_DEFAULT, headers = {}) {
|
|
195
|
+
this.client.sendOneWayJson(source, target, payload, payloadIdentity, deliveryHint, headers);
|
|
196
|
+
}
|
|
197
|
+
submitEnvelope(envelope) {
|
|
198
|
+
this.client.submitEnvelope(envelope);
|
|
199
|
+
}
|
|
200
|
+
submitTypedEnvelope(envelope) {
|
|
201
|
+
this.client.submitTypedEnvelope(envelope);
|
|
202
|
+
}
|
|
203
|
+
submitRawEnvelope(envelope) {
|
|
204
|
+
this.client.submitRawEnvelope(envelope);
|
|
205
|
+
}
|
|
206
|
+
registerHandler(target, handler, typedReplies = true) {
|
|
207
|
+
this.client.registerHandler(target, handler, typedReplies);
|
|
208
|
+
}
|
|
209
|
+
registerRawHandler(target, handler) {
|
|
210
|
+
this.client.registerRawHandler(target, handler);
|
|
211
|
+
}
|
|
212
|
+
clientStats() {
|
|
213
|
+
return this.client.snapshotStats();
|
|
214
|
+
}
|
|
215
|
+
runtimeInfo() {
|
|
216
|
+
return this.client.runtimeInfoSnapshot();
|
|
217
|
+
}
|
|
218
|
+
runtimeConfig() {
|
|
219
|
+
return this.client.runtimeConfigSnapshot();
|
|
220
|
+
}
|
|
221
|
+
health() {
|
|
222
|
+
return this.client.healthSnapshot();
|
|
223
|
+
}
|
|
224
|
+
stats() {
|
|
225
|
+
return this.client.statsSnapshot();
|
|
226
|
+
}
|
|
227
|
+
runtimeSnapshot() {
|
|
228
|
+
return this.client.runtimeSnapshot();
|
|
229
|
+
}
|
|
230
|
+
applySnapshot(generation, routes, sourceConnector = this.startSpec.systemName, seq = 1, overloadPolicy = this.startSpec.overloadPolicy) {
|
|
231
|
+
this.client.applySnapshot(generation, routes, sourceConnector, seq, overloadPolicy);
|
|
232
|
+
}
|
|
233
|
+
monitorIsEnabled() {
|
|
234
|
+
return this.client.monitorIsEnabled();
|
|
235
|
+
}
|
|
236
|
+
monitorSnapshot(signalCount = 0) {
|
|
237
|
+
return this.client.monitorSnapshot(signalCount);
|
|
238
|
+
}
|
|
239
|
+
async awaitNextMonitor(timeoutMs = 1_000) {
|
|
240
|
+
return await this.client.awaitNextMonitor(timeoutMs);
|
|
241
|
+
}
|
|
242
|
+
async awaitAppliedGenerationAtLeast(generation, timeoutMs = 1_000) {
|
|
243
|
+
return await this.client.awaitAppliedGenerationAtLeast(generation, timeoutMs);
|
|
244
|
+
}
|
|
245
|
+
close() {
|
|
246
|
+
if (this.closed) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
this.closed = true;
|
|
250
|
+
try {
|
|
251
|
+
this.client.close();
|
|
252
|
+
}
|
|
253
|
+
finally {
|
|
254
|
+
if (ConnectorOrchestrator.active === this) {
|
|
255
|
+
ConnectorOrchestrator.active = null;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
export const RuntimeHost = ConnectorOrchestrator;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export interface TransportEnvelope {
|
|
2
|
+
message_id: string;
|
|
3
|
+
correlation_id: string;
|
|
4
|
+
source: string;
|
|
5
|
+
target: string;
|
|
6
|
+
reply_to: string;
|
|
7
|
+
kind: number;
|
|
8
|
+
one_way: boolean;
|
|
9
|
+
timeout_ms: number;
|
|
10
|
+
payload: Uint8Array;
|
|
11
|
+
headers: Record<string, string>;
|
|
12
|
+
status: number;
|
|
13
|
+
error_code: string;
|
|
14
|
+
error_message: string;
|
|
15
|
+
delivery_hint: number;
|
|
16
|
+
message_type: string;
|
|
17
|
+
payload_schema_version: number;
|
|
18
|
+
payload_format: number;
|
|
19
|
+
}
|
|
20
|
+
export interface TransportDeadletter {
|
|
21
|
+
original_envelope: TransportEnvelope;
|
|
22
|
+
reason: number;
|
|
23
|
+
detail: string;
|
|
24
|
+
active_generation: number;
|
|
25
|
+
resolved_host: string;
|
|
26
|
+
resolved_port: number;
|
|
27
|
+
}
|
|
28
|
+
export interface ControlEnvelope {
|
|
29
|
+
seq: number;
|
|
30
|
+
generation: number;
|
|
31
|
+
kind: number;
|
|
32
|
+
payload_format: number;
|
|
33
|
+
payload_type: number;
|
|
34
|
+
schema_version: number;
|
|
35
|
+
payload: Uint8Array;
|
|
36
|
+
metadata: Record<string, string>;
|
|
37
|
+
}
|
|
38
|
+
export interface RouteSnapshotPayload {
|
|
39
|
+
generation: number;
|
|
40
|
+
overload_policy?: {
|
|
41
|
+
ingress_mode: number;
|
|
42
|
+
local_delivery_mode: number;
|
|
43
|
+
remote_outbound_mode: number;
|
|
44
|
+
remote_outbound_reply_reserve_slots: number;
|
|
45
|
+
};
|
|
46
|
+
routes: Array<{
|
|
47
|
+
target: string;
|
|
48
|
+
strategy: number;
|
|
49
|
+
route_key_hint: string;
|
|
50
|
+
flags: number;
|
|
51
|
+
endpoints: Array<{
|
|
52
|
+
host: string;
|
|
53
|
+
port: number;
|
|
54
|
+
weight: number;
|
|
55
|
+
flags: number;
|
|
56
|
+
}>;
|
|
57
|
+
}>;
|
|
58
|
+
}
|
|
59
|
+
export declare function encodeEnvelope(envelope: TransportEnvelope): Buffer;
|
|
60
|
+
export declare function encodeControlEnvelope(envelope: ControlEnvelope): Buffer;
|
|
61
|
+
export declare function encodeRouteSnapshotPayload(snapshot: RouteSnapshotPayload): Buffer;
|
|
62
|
+
export declare function decodeEnvelope(bytes: Uint8Array): TransportEnvelope;
|
|
63
|
+
export declare function decodeDeadletter(bytes: Uint8Array): TransportDeadletter;
|
package/dist/protobuf.js
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
const WIRE_VARINT = 0;
|
|
2
|
+
const WIRE_LENGTH_DELIMITED = 2;
|
|
3
|
+
function defaultEnvelope() {
|
|
4
|
+
return {
|
|
5
|
+
message_id: "",
|
|
6
|
+
correlation_id: "",
|
|
7
|
+
source: "",
|
|
8
|
+
target: "",
|
|
9
|
+
reply_to: "",
|
|
10
|
+
kind: 0,
|
|
11
|
+
one_way: false,
|
|
12
|
+
timeout_ms: 0,
|
|
13
|
+
payload: Buffer.alloc(0),
|
|
14
|
+
headers: {},
|
|
15
|
+
status: 0,
|
|
16
|
+
error_code: "",
|
|
17
|
+
error_message: "",
|
|
18
|
+
delivery_hint: 0,
|
|
19
|
+
message_type: "",
|
|
20
|
+
payload_schema_version: 0,
|
|
21
|
+
payload_format: 0,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function defaultDeadletter() {
|
|
25
|
+
return {
|
|
26
|
+
original_envelope: defaultEnvelope(),
|
|
27
|
+
reason: 0,
|
|
28
|
+
detail: "",
|
|
29
|
+
active_generation: 0,
|
|
30
|
+
resolved_host: "",
|
|
31
|
+
resolved_port: 0,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function encodeKey(fieldNumber, wireType) {
|
|
35
|
+
return encodeVarint((fieldNumber << 3) | wireType);
|
|
36
|
+
}
|
|
37
|
+
function encodeVarint(value) {
|
|
38
|
+
let remaining = typeof value === "bigint" ? value : BigInt(Math.max(0, Math.trunc(value)));
|
|
39
|
+
const bytes = [];
|
|
40
|
+
do {
|
|
41
|
+
let byte = Number(remaining & 0x7fn);
|
|
42
|
+
remaining >>= 7n;
|
|
43
|
+
if (remaining !== 0n) {
|
|
44
|
+
byte |= 0x80;
|
|
45
|
+
}
|
|
46
|
+
bytes.push(byte);
|
|
47
|
+
} while (remaining !== 0n);
|
|
48
|
+
return Buffer.from(bytes);
|
|
49
|
+
}
|
|
50
|
+
function encodeString(fieldNumber, value) {
|
|
51
|
+
if (value === "") {
|
|
52
|
+
return Buffer.alloc(0);
|
|
53
|
+
}
|
|
54
|
+
return encodeBytes(fieldNumber, Buffer.from(value, "utf8"));
|
|
55
|
+
}
|
|
56
|
+
function encodeBytes(fieldNumber, value) {
|
|
57
|
+
if (value.length === 0) {
|
|
58
|
+
return Buffer.alloc(0);
|
|
59
|
+
}
|
|
60
|
+
return Buffer.concat([encodeKey(fieldNumber, WIRE_LENGTH_DELIMITED), encodeVarint(value.length), Buffer.from(value)]);
|
|
61
|
+
}
|
|
62
|
+
function encodeNumber(fieldNumber, value) {
|
|
63
|
+
if (value === 0) {
|
|
64
|
+
return Buffer.alloc(0);
|
|
65
|
+
}
|
|
66
|
+
return Buffer.concat([encodeKey(fieldNumber, WIRE_VARINT), encodeVarint(value)]);
|
|
67
|
+
}
|
|
68
|
+
function encodeBool(fieldNumber, value) {
|
|
69
|
+
return value ? Buffer.concat([encodeKey(fieldNumber, WIRE_VARINT), encodeVarint(1)]) : Buffer.alloc(0);
|
|
70
|
+
}
|
|
71
|
+
function encodeMapStringString(fieldNumber, value) {
|
|
72
|
+
const entries = [];
|
|
73
|
+
for (const [key, entryValue] of Object.entries(value)) {
|
|
74
|
+
const entry = Buffer.concat([
|
|
75
|
+
encodeString(1, key),
|
|
76
|
+
encodeString(2, entryValue),
|
|
77
|
+
]);
|
|
78
|
+
entries.push(encodeBytes(fieldNumber, entry));
|
|
79
|
+
}
|
|
80
|
+
return Buffer.concat(entries);
|
|
81
|
+
}
|
|
82
|
+
function encodeEnvelopeMessage(envelope) {
|
|
83
|
+
return Buffer.concat([
|
|
84
|
+
encodeString(1, envelope.message_id),
|
|
85
|
+
encodeString(2, envelope.correlation_id),
|
|
86
|
+
encodeString(3, envelope.source),
|
|
87
|
+
encodeString(4, envelope.target),
|
|
88
|
+
encodeString(5, envelope.reply_to),
|
|
89
|
+
encodeNumber(6, envelope.kind),
|
|
90
|
+
encodeBool(7, envelope.one_way),
|
|
91
|
+
encodeNumber(8, envelope.timeout_ms),
|
|
92
|
+
encodeBytes(9, envelope.payload),
|
|
93
|
+
encodeMapStringString(10, envelope.headers),
|
|
94
|
+
encodeNumber(11, envelope.status),
|
|
95
|
+
encodeString(12, envelope.error_code),
|
|
96
|
+
encodeString(13, envelope.error_message),
|
|
97
|
+
encodeNumber(14, envelope.delivery_hint),
|
|
98
|
+
encodeString(15, envelope.message_type),
|
|
99
|
+
encodeNumber(16, envelope.payload_schema_version),
|
|
100
|
+
encodeNumber(17, envelope.payload_format),
|
|
101
|
+
]);
|
|
102
|
+
}
|
|
103
|
+
export function encodeEnvelope(envelope) {
|
|
104
|
+
return encodeEnvelopeMessage(envelope);
|
|
105
|
+
}
|
|
106
|
+
export function encodeControlEnvelope(envelope) {
|
|
107
|
+
return Buffer.concat([
|
|
108
|
+
encodeNumber(1, envelope.seq),
|
|
109
|
+
encodeNumber(2, envelope.generation),
|
|
110
|
+
encodeNumber(3, envelope.kind),
|
|
111
|
+
encodeNumber(4, envelope.payload_format),
|
|
112
|
+
encodeNumber(5, envelope.payload_type),
|
|
113
|
+
encodeNumber(6, envelope.schema_version),
|
|
114
|
+
encodeBytes(7, envelope.payload),
|
|
115
|
+
encodeMapStringString(8, envelope.metadata),
|
|
116
|
+
]);
|
|
117
|
+
}
|
|
118
|
+
export function encodeRouteSnapshotPayload(snapshot) {
|
|
119
|
+
const parts = [encodeNumber(1, snapshot.generation)];
|
|
120
|
+
for (const route of snapshot.routes) {
|
|
121
|
+
parts.push(encodeBytes(2, encodeRoute(route)));
|
|
122
|
+
}
|
|
123
|
+
if (snapshot.overload_policy != null) {
|
|
124
|
+
parts.push(encodeBytes(3, encodeOverloadPolicy(snapshot.overload_policy)));
|
|
125
|
+
}
|
|
126
|
+
return Buffer.concat(parts);
|
|
127
|
+
}
|
|
128
|
+
function encodeRoute(route) {
|
|
129
|
+
const parts = [
|
|
130
|
+
encodeString(1, route.target),
|
|
131
|
+
encodeNumber(2, route.strategy),
|
|
132
|
+
encodeString(3, route.route_key_hint),
|
|
133
|
+
encodeNumber(4, route.flags),
|
|
134
|
+
];
|
|
135
|
+
for (const endpoint of route.endpoints) {
|
|
136
|
+
parts.push(encodeBytes(5, encodeEndpoint(endpoint)));
|
|
137
|
+
}
|
|
138
|
+
return Buffer.concat(parts);
|
|
139
|
+
}
|
|
140
|
+
function encodeEndpoint(endpoint) {
|
|
141
|
+
return Buffer.concat([
|
|
142
|
+
encodeString(1, endpoint.host),
|
|
143
|
+
encodeNumber(2, endpoint.port),
|
|
144
|
+
encodeNumber(3, endpoint.weight),
|
|
145
|
+
encodeNumber(4, endpoint.flags),
|
|
146
|
+
]);
|
|
147
|
+
}
|
|
148
|
+
function encodeOverloadPolicy(policy) {
|
|
149
|
+
return Buffer.concat([
|
|
150
|
+
encodeNumber(1, policy.ingress_mode),
|
|
151
|
+
encodeNumber(2, policy.local_delivery_mode),
|
|
152
|
+
encodeNumber(3, policy.remote_outbound_mode),
|
|
153
|
+
encodeNumber(4, policy.remote_outbound_reply_reserve_slots),
|
|
154
|
+
]);
|
|
155
|
+
}
|
|
156
|
+
class Reader {
|
|
157
|
+
bytes;
|
|
158
|
+
offset = 0;
|
|
159
|
+
constructor(bytes) {
|
|
160
|
+
this.bytes = bytes;
|
|
161
|
+
}
|
|
162
|
+
done() {
|
|
163
|
+
return this.offset >= this.bytes.length;
|
|
164
|
+
}
|
|
165
|
+
readTag() {
|
|
166
|
+
const tag = this.readVarint();
|
|
167
|
+
return { fieldNumber: tag >> 3, wireType: tag & 0x7 };
|
|
168
|
+
}
|
|
169
|
+
readVarint() {
|
|
170
|
+
let shift = 0n;
|
|
171
|
+
let result = 0n;
|
|
172
|
+
while (this.offset < this.bytes.length) {
|
|
173
|
+
const byte = this.bytes[this.offset++];
|
|
174
|
+
result |= BigInt(byte & 0x7f) << shift;
|
|
175
|
+
if ((byte & 0x80) === 0) {
|
|
176
|
+
return Number(result);
|
|
177
|
+
}
|
|
178
|
+
shift += 7n;
|
|
179
|
+
}
|
|
180
|
+
throw new Error("truncated varint");
|
|
181
|
+
}
|
|
182
|
+
readBytes() {
|
|
183
|
+
const length = this.readVarint();
|
|
184
|
+
const end = this.offset + length;
|
|
185
|
+
if (length < 0 || end > this.bytes.length) {
|
|
186
|
+
throw new Error("truncated bytes");
|
|
187
|
+
}
|
|
188
|
+
const value = this.bytes.subarray(this.offset, end);
|
|
189
|
+
this.offset = end;
|
|
190
|
+
return Buffer.from(value);
|
|
191
|
+
}
|
|
192
|
+
readString() {
|
|
193
|
+
return Buffer.from(this.readBytes()).toString("utf8");
|
|
194
|
+
}
|
|
195
|
+
skip(wireType) {
|
|
196
|
+
switch (wireType) {
|
|
197
|
+
case WIRE_VARINT:
|
|
198
|
+
this.readVarint();
|
|
199
|
+
return;
|
|
200
|
+
case WIRE_LENGTH_DELIMITED:
|
|
201
|
+
this.readBytes();
|
|
202
|
+
return;
|
|
203
|
+
default:
|
|
204
|
+
throw new Error(`unsupported wire type=${wireType}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
export function decodeEnvelope(bytes) {
|
|
209
|
+
return decodeEnvelopeMessage(new Reader(bytes));
|
|
210
|
+
}
|
|
211
|
+
function decodeEnvelopeMessage(reader) {
|
|
212
|
+
const envelope = defaultEnvelope();
|
|
213
|
+
while (!reader.done()) {
|
|
214
|
+
const { fieldNumber, wireType } = reader.readTag();
|
|
215
|
+
switch (fieldNumber) {
|
|
216
|
+
case 1:
|
|
217
|
+
envelope.message_id = reader.readString();
|
|
218
|
+
break;
|
|
219
|
+
case 2:
|
|
220
|
+
envelope.correlation_id = reader.readString();
|
|
221
|
+
break;
|
|
222
|
+
case 3:
|
|
223
|
+
envelope.source = reader.readString();
|
|
224
|
+
break;
|
|
225
|
+
case 4:
|
|
226
|
+
envelope.target = reader.readString();
|
|
227
|
+
break;
|
|
228
|
+
case 5:
|
|
229
|
+
envelope.reply_to = reader.readString();
|
|
230
|
+
break;
|
|
231
|
+
case 6:
|
|
232
|
+
envelope.kind = reader.readVarint();
|
|
233
|
+
break;
|
|
234
|
+
case 7:
|
|
235
|
+
envelope.one_way = reader.readVarint() !== 0;
|
|
236
|
+
break;
|
|
237
|
+
case 8:
|
|
238
|
+
envelope.timeout_ms = reader.readVarint();
|
|
239
|
+
break;
|
|
240
|
+
case 9:
|
|
241
|
+
envelope.payload = reader.readBytes();
|
|
242
|
+
break;
|
|
243
|
+
case 10:
|
|
244
|
+
Object.assign(envelope.headers, decodeStringMapEntry(new Reader(reader.readBytes())));
|
|
245
|
+
break;
|
|
246
|
+
case 11:
|
|
247
|
+
envelope.status = reader.readVarint();
|
|
248
|
+
break;
|
|
249
|
+
case 12:
|
|
250
|
+
envelope.error_code = reader.readString();
|
|
251
|
+
break;
|
|
252
|
+
case 13:
|
|
253
|
+
envelope.error_message = reader.readString();
|
|
254
|
+
break;
|
|
255
|
+
case 14:
|
|
256
|
+
envelope.delivery_hint = reader.readVarint();
|
|
257
|
+
break;
|
|
258
|
+
case 15:
|
|
259
|
+
envelope.message_type = reader.readString();
|
|
260
|
+
break;
|
|
261
|
+
case 16:
|
|
262
|
+
envelope.payload_schema_version = reader.readVarint();
|
|
263
|
+
break;
|
|
264
|
+
case 17:
|
|
265
|
+
envelope.payload_format = reader.readVarint();
|
|
266
|
+
break;
|
|
267
|
+
default:
|
|
268
|
+
reader.skip(wireType);
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return envelope;
|
|
273
|
+
}
|
|
274
|
+
export function decodeDeadletter(bytes) {
|
|
275
|
+
const reader = new Reader(bytes);
|
|
276
|
+
const deadletter = defaultDeadletter();
|
|
277
|
+
while (!reader.done()) {
|
|
278
|
+
const { fieldNumber, wireType } = reader.readTag();
|
|
279
|
+
switch (fieldNumber) {
|
|
280
|
+
case 1:
|
|
281
|
+
deadletter.original_envelope = decodeEnvelopeMessage(new Reader(reader.readBytes()));
|
|
282
|
+
break;
|
|
283
|
+
case 2:
|
|
284
|
+
deadletter.reason = reader.readVarint();
|
|
285
|
+
break;
|
|
286
|
+
case 3:
|
|
287
|
+
deadletter.detail = reader.readString();
|
|
288
|
+
break;
|
|
289
|
+
case 4:
|
|
290
|
+
deadletter.active_generation = reader.readVarint();
|
|
291
|
+
break;
|
|
292
|
+
case 5:
|
|
293
|
+
deadletter.resolved_host = reader.readString();
|
|
294
|
+
break;
|
|
295
|
+
case 6:
|
|
296
|
+
deadletter.resolved_port = reader.readVarint();
|
|
297
|
+
break;
|
|
298
|
+
default:
|
|
299
|
+
reader.skip(wireType);
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return deadletter;
|
|
304
|
+
}
|
|
305
|
+
function decodeStringMapEntry(reader) {
|
|
306
|
+
let key = "";
|
|
307
|
+
let value = "";
|
|
308
|
+
while (!reader.done()) {
|
|
309
|
+
const { fieldNumber, wireType } = reader.readTag();
|
|
310
|
+
switch (fieldNumber) {
|
|
311
|
+
case 1:
|
|
312
|
+
key = reader.readString();
|
|
313
|
+
break;
|
|
314
|
+
case 2:
|
|
315
|
+
value = reader.readString();
|
|
316
|
+
break;
|
|
317
|
+
default:
|
|
318
|
+
reader.skip(wireType);
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return key === "" ? {} : { [key]: value };
|
|
323
|
+
}
|