grpc-libp2p-client 0.0.37 → 0.0.39
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/dist/dc-http2/frame.cjs.js +6 -5
- package/dist/dc-http2/frame.cjs.js.map +1 -1
- package/dist/dc-http2/frame.d.ts +1 -1
- package/dist/dc-http2/frame.esm.js +6 -5
- package/dist/dc-http2/frame.esm.js.map +1 -1
- package/dist/dc-http2/hpack.cjs.js +3 -3
- package/dist/dc-http2/hpack.cjs.js.map +1 -1
- package/dist/dc-http2/hpack.esm.js +3 -3
- package/dist/dc-http2/hpack.esm.js.map +1 -1
- package/dist/dc-http2/parser.cjs.js +39 -28
- package/dist/dc-http2/parser.cjs.js.map +1 -1
- package/dist/dc-http2/parser.d.ts +7 -7
- package/dist/dc-http2/parser.esm.js +39 -28
- package/dist/dc-http2/parser.esm.js.map +1 -1
- package/dist/dc-http2/stream.cjs.js +26 -12
- package/dist/dc-http2/stream.cjs.js.map +1 -1
- package/dist/dc-http2/stream.d.ts +1 -1
- package/dist/dc-http2/stream.esm.js +26 -12
- package/dist/dc-http2/stream.esm.js.map +1 -1
- package/dist/grpc.js +245 -269
- package/dist/grpc.js.map +1 -1
- package/dist/grpc.min.js +1 -1
- package/dist/grpc.min.js.map +1 -1
- package/dist/index.cjs.js +103 -103
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +103 -103
- package/dist/index.esm.js.map +1 -1
- package/dist/stats.html +1 -1
- package/package.json +4 -4
- package/src/dc-http2/encoder.ts +3 -2
- package/src/dc-http2/hpack.ts +3 -3
- package/src/dc-http2/parser.ts +43 -38
- package/src/dc-http2/stream.ts +36 -23
- package/src/dc-http2/types.ts +1 -1
- package/src/index.ts +57 -85
package/src/index.ts
CHANGED
|
@@ -154,6 +154,7 @@ export class Libp2pGrpcClient {
|
|
|
154
154
|
|
|
155
155
|
await new Promise<void>((resolve, reject) => {
|
|
156
156
|
let settled = false;
|
|
157
|
+
// eslint-disable-next-line prefer-const
|
|
157
158
|
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
158
159
|
const cleanup = () => {
|
|
159
160
|
const idx = state.waiters.indexOf(waiter);
|
|
@@ -239,7 +240,7 @@ export class Libp2pGrpcClient {
|
|
|
239
240
|
if (signal?.aborted) {
|
|
240
241
|
throw new Error("Operation aborted");
|
|
241
242
|
}
|
|
242
|
-
await writer.write(frame
|
|
243
|
+
await writer.write(frame);
|
|
243
244
|
if (payloadLength > 0) {
|
|
244
245
|
parser.consumeSendWindow(streamId, payloadLength);
|
|
245
246
|
}
|
|
@@ -252,7 +253,7 @@ export class Libp2pGrpcClient {
|
|
|
252
253
|
if (pooled) {
|
|
253
254
|
const conn = pooled.connection;
|
|
254
255
|
if (conn) {
|
|
255
|
-
const status =
|
|
256
|
+
const status = conn.status;
|
|
256
257
|
if (!status || status === "open") {
|
|
257
258
|
return conn;
|
|
258
259
|
}
|
|
@@ -279,15 +280,8 @@ export class Libp2pGrpcClient {
|
|
|
279
280
|
}
|
|
280
281
|
};
|
|
281
282
|
try {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
anyConn.addEventListener("close", removeFromPool, {
|
|
285
|
-
once: true,
|
|
286
|
-
});
|
|
287
|
-
} else if (typeof anyConn.once === "function") {
|
|
288
|
-
anyConn.once("close", removeFromPool);
|
|
289
|
-
}
|
|
290
|
-
} catch {}
|
|
283
|
+
conn.addEventListener("close", removeFromPool, { once: true });
|
|
284
|
+
} catch { /* ignore event listener registration errors */ }
|
|
291
285
|
}
|
|
292
286
|
}
|
|
293
287
|
return conn;
|
|
@@ -364,17 +358,17 @@ export class Libp2pGrpcClient {
|
|
|
364
358
|
bufferSize: 16 * 1024 * 1024,
|
|
365
359
|
});
|
|
366
360
|
try {
|
|
367
|
-
writer.addEventListener("backpressure", (e:
|
|
368
|
-
const d = e
|
|
361
|
+
writer.addEventListener("backpressure", (e: CustomEvent) => {
|
|
362
|
+
const d = e.detail || {};
|
|
369
363
|
console.warn(
|
|
370
364
|
`[unary stream ${streamId}] backpressure current=${d.currentSize} avg=${d.averageSize} threshold=${d.threshold}`
|
|
371
365
|
);
|
|
372
366
|
});
|
|
373
|
-
writer.addEventListener("drain", (
|
|
374
|
-
|
|
367
|
+
writer.addEventListener("drain", () => {
|
|
368
|
+
// drain event - no action needed
|
|
375
369
|
});
|
|
376
|
-
writer.addEventListener("stalled", (e:
|
|
377
|
-
const d = e
|
|
370
|
+
writer.addEventListener("stalled", (e: CustomEvent) => {
|
|
371
|
+
const d = e.detail || {};
|
|
378
372
|
console.warn(
|
|
379
373
|
`[unary stream ${streamId}] stalled queue=${d.queueSize} drained=${d.drained} since=${d.sinceMs}ms — sending PING`
|
|
380
374
|
);
|
|
@@ -382,10 +376,10 @@ export class Libp2pGrpcClient {
|
|
|
382
376
|
const payload = new Uint8Array(8);
|
|
383
377
|
crypto.getRandomValues?.(payload);
|
|
384
378
|
const ping = Http2Frame.createFrame(0x6, 0x0, 0, payload);
|
|
385
|
-
writer.write(ping
|
|
386
|
-
} catch {}
|
|
379
|
+
writer.write(ping);
|
|
380
|
+
} catch { /* ignore ping write errors */ }
|
|
387
381
|
});
|
|
388
|
-
} catch {}
|
|
382
|
+
} catch { /* ignore addEventListener errors */ }
|
|
389
383
|
const parser = new HTTP2Parser(writer);
|
|
390
384
|
parser.onGoaway = (info) => {
|
|
391
385
|
console.warn("[unaryCall] GOAWAY received from server", info);
|
|
@@ -399,7 +393,7 @@ export class Libp2pGrpcClient {
|
|
|
399
393
|
exitFlag = true;
|
|
400
394
|
errMsg = `GOAWAY received: code=${info.errorCode}`;
|
|
401
395
|
try {
|
|
402
|
-
|
|
396
|
+
connection?.close();
|
|
403
397
|
} catch (err) {
|
|
404
398
|
console.warn("Error closing connection after GOAWAY:", err);
|
|
405
399
|
}
|
|
@@ -425,7 +419,6 @@ export class Libp2pGrpcClient {
|
|
|
425
419
|
if (payload.length < 5) {
|
|
426
420
|
return;
|
|
427
421
|
}
|
|
428
|
-
const compressionFlag = payload[0]; // 压缩标志
|
|
429
422
|
const lengthBytes = payload.slice(1, 5); // 消息长度的4字节
|
|
430
423
|
responseDataExpectedLength = new DataView(
|
|
431
424
|
lengthBytes.buffer,
|
|
@@ -508,19 +501,16 @@ export class Libp2pGrpcClient {
|
|
|
508
501
|
parser.onSettings = () => {
|
|
509
502
|
//接收settings,反馈ack
|
|
510
503
|
const ackSettingFrame = Http2Frame.createSettingsAckFrame();
|
|
511
|
-
writer.write(ackSettingFrame
|
|
504
|
+
writer.write(ackSettingFrame);
|
|
512
505
|
};
|
|
513
|
-
parser.onHeaders = (headers
|
|
514
|
-
|
|
506
|
+
parser.onHeaders = (headers) => {
|
|
515
507
|
const plainHeaders = hpack.decodeHeaderFields(headers);
|
|
516
508
|
if (plainHeaders.get("grpc-status") === "0") {
|
|
517
509
|
// 成功状态
|
|
518
|
-
|
|
519
510
|
} else if (plainHeaders.get("grpc-status") !== undefined) {
|
|
520
511
|
exitFlag = true;
|
|
521
512
|
errMsg = plainHeaders.get("grpc-message") || "gRPC call failed";
|
|
522
513
|
}
|
|
523
|
-
|
|
524
514
|
};
|
|
525
515
|
// 启动后台流处理,捕获任何异步错误
|
|
526
516
|
parser.processStream(stream).catch((error: unknown) => {
|
|
@@ -533,26 +523,17 @@ export class Libp2pGrpcClient {
|
|
|
533
523
|
|
|
534
524
|
// 握手
|
|
535
525
|
const preface = Http2Frame.createPreface();
|
|
536
|
-
await writer.write(preface
|
|
526
|
+
await writer.write(preface);
|
|
537
527
|
// 发送Settings请求
|
|
538
528
|
const settingFrme = Http2Frame.createSettingsFrame();
|
|
539
|
-
await writer.write(settingFrme
|
|
529
|
+
await writer.write(settingFrme);
|
|
540
530
|
// 等待对端 SETTINGS 或 ACK,择一即可,避免偶发握手竞态
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
})(),
|
|
548
|
-
(async () => {
|
|
549
|
-
await parser.waitForSettingsAck();
|
|
550
|
-
progressed = true;
|
|
551
|
-
})(),
|
|
552
|
-
new Promise<void>((res) => setTimeout(res, 300)),
|
|
553
|
-
]);
|
|
554
|
-
// 即使未等到,也继续;多数实现会随后发送
|
|
555
|
-
}
|
|
531
|
+
await Promise.race([
|
|
532
|
+
parser.waitForPeerSettings(1000),
|
|
533
|
+
parser.waitForSettingsAck(),
|
|
534
|
+
new Promise<void>((res) => setTimeout(res, 300)),
|
|
535
|
+
]);
|
|
536
|
+
// 即使未等到,也继续;多数实现会随后发送
|
|
556
537
|
// 创建头部帧
|
|
557
538
|
const headerFrame = Http2Frame.createHeadersFrame(
|
|
558
539
|
streamId,
|
|
@@ -560,7 +541,7 @@ export class Libp2pGrpcClient {
|
|
|
560
541
|
true,
|
|
561
542
|
this.token
|
|
562
543
|
);
|
|
563
|
-
await writer.write(headerFrame
|
|
544
|
+
await writer.write(headerFrame);
|
|
564
545
|
// 直接按帧大小分片发送(保持与之前一致的稳定路径)
|
|
565
546
|
const dataFrames = Http2Frame.createDataFrames(
|
|
566
547
|
streamId,
|
|
@@ -596,8 +577,8 @@ export class Libp2pGrpcClient {
|
|
|
596
577
|
checkResponse();
|
|
597
578
|
});
|
|
598
579
|
try {
|
|
599
|
-
await
|
|
600
|
-
} catch {}
|
|
580
|
+
await writer.flush(timeout);
|
|
581
|
+
} catch { /* ignore flush errors */ }
|
|
601
582
|
await writer.end();
|
|
602
583
|
} catch (err) {
|
|
603
584
|
console.error("unaryCall error:", err);
|
|
@@ -649,7 +630,7 @@ export class Libp2pGrpcClient {
|
|
|
649
630
|
) {
|
|
650
631
|
// 创建内部AbortController用于控制操作
|
|
651
632
|
const internalController = new AbortController();
|
|
652
|
-
let timeoutHandle:
|
|
633
|
+
let timeoutHandle: ReturnType<typeof setTimeout> | undefined;
|
|
653
634
|
let stream: Stream | null = null;
|
|
654
635
|
|
|
655
636
|
const profile: TransportProfile =
|
|
@@ -715,7 +696,7 @@ export class Libp2pGrpcClient {
|
|
|
715
696
|
if (options?.freshConnection) {
|
|
716
697
|
try {
|
|
717
698
|
this.connectionPool.delete(this.peerAddr.toString());
|
|
718
|
-
await
|
|
699
|
+
await this.node.hangUp(this.peerAddr);
|
|
719
700
|
console.warn(
|
|
720
701
|
"[Call] hangUp existing connection before dialing due to freshConnection=true"
|
|
721
702
|
);
|
|
@@ -757,17 +738,17 @@ export class Libp2pGrpcClient {
|
|
|
757
738
|
bufferSize: 16 * 1024 * 1024,
|
|
758
739
|
});
|
|
759
740
|
try {
|
|
760
|
-
writer.addEventListener("backpressure", (e:
|
|
761
|
-
const d = e
|
|
741
|
+
writer.addEventListener("backpressure", (e: CustomEvent) => {
|
|
742
|
+
const d = e.detail || {};
|
|
762
743
|
console.warn(
|
|
763
744
|
`[stream ${streamId}] backpressure current=${d.currentSize} avg=${d.averageSize} threshold=${d.threshold}`
|
|
764
745
|
);
|
|
765
746
|
});
|
|
766
|
-
writer.addEventListener("drain", (
|
|
767
|
-
|
|
747
|
+
writer.addEventListener("drain", () => {
|
|
748
|
+
// drain event - no action needed
|
|
768
749
|
});
|
|
769
|
-
writer.addEventListener("stalled", (e:
|
|
770
|
-
const d = e
|
|
750
|
+
writer.addEventListener("stalled", (e: CustomEvent) => {
|
|
751
|
+
const d = e.detail || {};
|
|
771
752
|
console.warn(
|
|
772
753
|
`[stream ${streamId}] stalled queue=${d.queueSize} drained=${d.drained} since=${d.sinceMs}ms — sending PING`
|
|
773
754
|
);
|
|
@@ -775,10 +756,10 @@ export class Libp2pGrpcClient {
|
|
|
775
756
|
const payload = new Uint8Array(8);
|
|
776
757
|
crypto.getRandomValues?.(payload);
|
|
777
758
|
const ping = Http2Frame.createFrame(0x6, 0x0, 0, payload);
|
|
778
|
-
writer.write(ping
|
|
779
|
-
} catch { /*
|
|
759
|
+
writer.write(ping);
|
|
760
|
+
} catch { /* ignore ping write errors */ }
|
|
780
761
|
});
|
|
781
|
-
} catch { /*
|
|
762
|
+
} catch { /* ignore addEventListener errors */ }
|
|
782
763
|
const parser = new HTTP2Parser(writer, {
|
|
783
764
|
compatibilityMode: !useFlowControl,
|
|
784
765
|
});
|
|
@@ -798,7 +779,7 @@ export class Libp2pGrpcClient {
|
|
|
798
779
|
}
|
|
799
780
|
internalController.abort();
|
|
800
781
|
try {
|
|
801
|
-
|
|
782
|
+
connection?.close();
|
|
802
783
|
} catch (err) {
|
|
803
784
|
console.warn("Error closing connection after GOAWAY:", err);
|
|
804
785
|
}
|
|
@@ -832,7 +813,7 @@ export class Libp2pGrpcClient {
|
|
|
832
813
|
if (internalController.signal.aborted) {
|
|
833
814
|
throw new Error("Operation aborted");
|
|
834
815
|
}
|
|
835
|
-
await writer.write(frame
|
|
816
|
+
await writer.write(frame);
|
|
836
817
|
}
|
|
837
818
|
};
|
|
838
819
|
const writeDataFrames = async (frames: Uint8Array[]) => {
|
|
@@ -842,7 +823,7 @@ export class Libp2pGrpcClient {
|
|
|
842
823
|
};
|
|
843
824
|
|
|
844
825
|
// 在各个回调中检查是否已中止
|
|
845
|
-
parser.onData = async (payload
|
|
826
|
+
parser.onData = async (payload): Promise<void> => {
|
|
846
827
|
// 检查是否已中止
|
|
847
828
|
if (internalController.signal.aborted) {
|
|
848
829
|
return;
|
|
@@ -867,7 +848,6 @@ export class Libp2pGrpcClient {
|
|
|
867
848
|
// 如果还没有读取消息长度,且缓冲区有足够数据
|
|
868
849
|
if (expectedMessageLength === -1 && messageBuffer.length >= 5) {
|
|
869
850
|
// 读取 gRPC 消息头:1字节压缩标志 + 4字节长度
|
|
870
|
-
const compressionFlag = messageBuffer[0];
|
|
871
851
|
const lengthBytes = messageBuffer.slice(1, 5);
|
|
872
852
|
expectedMessageLength = new DataView(
|
|
873
853
|
lengthBytes.buffer,
|
|
@@ -911,10 +891,10 @@ export class Libp2pGrpcClient {
|
|
|
911
891
|
if (internalController.signal.aborted) return;
|
|
912
892
|
|
|
913
893
|
const ackSettingFrame = Http2Frame.createSettingsAckFrame();
|
|
914
|
-
writer.write(ackSettingFrame
|
|
894
|
+
writer.write(ackSettingFrame);
|
|
915
895
|
};
|
|
916
896
|
|
|
917
|
-
parser.onHeaders = (headers
|
|
897
|
+
parser.onHeaders = (headers) => {
|
|
918
898
|
// 检查是否已中止
|
|
919
899
|
if (internalController.signal.aborted) return;
|
|
920
900
|
|
|
@@ -947,7 +927,7 @@ export class Libp2pGrpcClient {
|
|
|
947
927
|
|
|
948
928
|
// Handshake - send HTTP/2 preface
|
|
949
929
|
const preface = Http2Frame.createPreface();
|
|
950
|
-
await writer.write(preface
|
|
930
|
+
await writer.write(preface);
|
|
951
931
|
|
|
952
932
|
// 检查是否已中止
|
|
953
933
|
if (internalController.signal.aborted) {
|
|
@@ -956,7 +936,7 @@ export class Libp2pGrpcClient {
|
|
|
956
936
|
|
|
957
937
|
// Send Settings request
|
|
958
938
|
const settingFrame = Http2Frame.createSettingsFrame();
|
|
959
|
-
await writer.write(settingFrame
|
|
939
|
+
await writer.write(settingFrame);
|
|
960
940
|
|
|
961
941
|
// 检查是否已中止
|
|
962
942
|
if (internalController.signal.aborted) {
|
|
@@ -965,16 +945,9 @@ export class Libp2pGrpcClient {
|
|
|
965
945
|
|
|
966
946
|
// 等待对端 SETTINGS 或 ACK,择一即可,避免偶发握手竞态
|
|
967
947
|
{
|
|
968
|
-
let progressed = false;
|
|
969
948
|
await Promise.race([
|
|
970
|
-
(
|
|
971
|
-
|
|
972
|
-
progressed = true;
|
|
973
|
-
})(),
|
|
974
|
-
(async () => {
|
|
975
|
-
await parser.waitForSettingsAck();
|
|
976
|
-
progressed = true;
|
|
977
|
-
})(),
|
|
949
|
+
parser.waitForPeerSettings(1000),
|
|
950
|
+
parser.waitForSettingsAck(),
|
|
978
951
|
new Promise<void>((res) => setTimeout(res, 300)),
|
|
979
952
|
]);
|
|
980
953
|
// 即使未等到,也继续;多数实现会随后发送
|
|
@@ -998,7 +971,7 @@ export class Libp2pGrpcClient {
|
|
|
998
971
|
this.token
|
|
999
972
|
);
|
|
1000
973
|
if (mode === "unary" || mode === "server-streaming") {
|
|
1001
|
-
await writer.write(headerFrame
|
|
974
|
+
await writer.write(headerFrame);
|
|
1002
975
|
const dfs = Http2Frame.createDataFrames(streamId, requestData, true);
|
|
1003
976
|
await writeDataFrames(dfs);
|
|
1004
977
|
|
|
@@ -1010,7 +983,7 @@ export class Libp2pGrpcClient {
|
|
|
1010
983
|
(mode === "client-streaming" || mode === "bidirectional") &&
|
|
1011
984
|
dataSourceCallback
|
|
1012
985
|
) {
|
|
1013
|
-
await writer.write(headerFrame
|
|
986
|
+
await writer.write(headerFrame);
|
|
1014
987
|
|
|
1015
988
|
// 检查是否已中止
|
|
1016
989
|
if (internalController.signal.aborted) {
|
|
@@ -1028,13 +1001,12 @@ export class Libp2pGrpcClient {
|
|
|
1028
1001
|
|
|
1029
1002
|
// 动态批量处理逻辑 - 在处理过程中动态补充新数据
|
|
1030
1003
|
const batchSize = options?.batchSize || 10;
|
|
1031
|
-
const maxBatchWaitMs = options?.maxBatchWaitMs || 50;
|
|
1032
1004
|
|
|
1033
1005
|
// 动态批处理器
|
|
1034
1006
|
const processingQueue: {
|
|
1035
1007
|
chunk: Uint8Array;
|
|
1036
1008
|
resolve: (value: void | PromiseLike<void>) => void;
|
|
1037
|
-
reject: (reason?:
|
|
1009
|
+
reject: (reason?: unknown) => void;
|
|
1038
1010
|
}[] = [];
|
|
1039
1011
|
|
|
1040
1012
|
let isProcessing = false;
|
|
@@ -1195,8 +1167,8 @@ export class Libp2pGrpcClient {
|
|
|
1195
1167
|
await writeFrame(finalFrame);
|
|
1196
1168
|
// 在结束前尽量冲刷内部队列,避免服务器看到部分数据 + context canceled
|
|
1197
1169
|
try {
|
|
1198
|
-
await
|
|
1199
|
-
} catch {}
|
|
1170
|
+
await writer.flush(timeout);
|
|
1171
|
+
} catch { /* ignore flush errors */ }
|
|
1200
1172
|
await writer.end();
|
|
1201
1173
|
}
|
|
1202
1174
|
|
|
@@ -1242,14 +1214,14 @@ export class Libp2pGrpcClient {
|
|
|
1242
1214
|
if (options?.freshConnection) {
|
|
1243
1215
|
try {
|
|
1244
1216
|
// 通过 libp2p 连接管理器关闭到该 peer 的连接
|
|
1245
|
-
|
|
1246
|
-
|
|
1217
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1218
|
+
const conns = (this.node as any).getConnections?.(this.peerAddr as any) || [];
|
|
1247
1219
|
for (const c of conns) {
|
|
1248
1220
|
try {
|
|
1249
1221
|
await c.close?.();
|
|
1250
|
-
} catch {}
|
|
1222
|
+
} catch { /* ignore close errors */ }
|
|
1251
1223
|
}
|
|
1252
|
-
} catch {}
|
|
1224
|
+
} catch { /* ignore connection cleanup errors */ }
|
|
1253
1225
|
}
|
|
1254
1226
|
if (streamSlotAcquired && state) {
|
|
1255
1227
|
state.activeStreams = Math.max(0, state.activeStreams - 1);
|