grpc-libp2p-client 0.0.38 → 0.0.40
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 +51 -19
- 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 +51 -19
- package/dist/dc-http2/frame.esm.js.map +1 -1
- package/dist/dc-http2/hpack.cjs.js +43 -13
- package/dist/dc-http2/hpack.cjs.js.map +1 -1
- package/dist/dc-http2/hpack.esm.js +43 -13
- package/dist/dc-http2/hpack.esm.js.map +1 -1
- package/dist/dc-http2/parser.cjs.js +281 -189
- package/dist/dc-http2/parser.cjs.js.map +1 -1
- package/dist/dc-http2/parser.d.ts +21 -2
- package/dist/dc-http2/parser.esm.js +281 -189
- package/dist/dc-http2/parser.esm.js.map +1 -1
- package/dist/dc-http2/stream.cjs.js +111 -74
- package/dist/dc-http2/stream.cjs.js.map +1 -1
- package/dist/dc-http2/stream.d.ts +2 -0
- package/dist/dc-http2/stream.esm.js +111 -74
- package/dist/dc-http2/stream.esm.js.map +1 -1
- package/dist/grpc.js +824 -583
- 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 +647 -415
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +647 -415
- package/dist/index.esm.js.map +1 -1
- package/dist/stats.html +1 -1
- package/package.json +1 -1
- package/src/dc-http2/frame.ts +11 -9
- package/src/dc-http2/hpack.ts +43 -13
- package/src/dc-http2/parser.ts +219 -196
- package/src/dc-http2/stream.ts +99 -84
- package/src/index.ts +240 -183
package/dist/grpc.js
CHANGED
|
@@ -366,7 +366,6 @@
|
|
|
366
366
|
this.dynamicTable.unshift([name, value]);
|
|
367
367
|
this.dynamicTableSize += size;
|
|
368
368
|
}
|
|
369
|
-
this.dynamicTable.push([name, value]);
|
|
370
369
|
};
|
|
371
370
|
// 获取索引的头部
|
|
372
371
|
HPACK.prototype.getIndexedHeader = function (index) {
|
|
@@ -483,22 +482,29 @@
|
|
|
483
482
|
// Huffman编码实现
|
|
484
483
|
HPACK.prototype.huffmanEncode = function (bytes) {
|
|
485
484
|
var result = [];
|
|
485
|
+
// 使用高精度浮点数累积位,避免 JS 32-bit 有符号整数在位数 >31 时溢出。
|
|
486
|
+
// Huffman 码最长 30 bits,加上未输出的最多 7 bits = 37 bits,超过 32-bit 安全范围。
|
|
487
|
+
// Number 可精确表示 2^53 以内的整数,足够累积多个码字。
|
|
486
488
|
var current = 0;
|
|
487
489
|
var bits = 0;
|
|
488
490
|
for (var i = 0; i < bytes.length; i++) {
|
|
489
491
|
var b = bytes[i];
|
|
490
492
|
var code = this.huffmanTable.codes[b];
|
|
491
493
|
var length_3 = this.huffmanTable.lengths[b];
|
|
494
|
+
// 用乘法左移替代 <<,避免 32-bit 截断
|
|
495
|
+
current = current * (1 << length_3) + code;
|
|
492
496
|
bits += length_3;
|
|
493
|
-
current = (current << length_3) | code;
|
|
494
497
|
while (bits >= 8) {
|
|
495
498
|
bits -= 8;
|
|
496
|
-
result.push((current
|
|
499
|
+
result.push(Math.floor(current / (1 << bits)) & 0xFF);
|
|
500
|
+
// 保留低 bits 位
|
|
501
|
+
current = current % (1 << bits);
|
|
497
502
|
}
|
|
498
503
|
}
|
|
499
|
-
//
|
|
504
|
+
// 处理剩余的位(用 EOS 填充 1)
|
|
500
505
|
if (bits > 0) {
|
|
501
|
-
|
|
506
|
+
var pad = 8 - bits;
|
|
507
|
+
current = current * (1 << pad) + ((1 << pad) - 1);
|
|
502
508
|
result.push(current & 0xFF);
|
|
503
509
|
}
|
|
504
510
|
return new Uint8Array(result);
|
|
@@ -521,17 +527,25 @@
|
|
|
521
527
|
headers.set(name_3, value);
|
|
522
528
|
index = newIndex;
|
|
523
529
|
}
|
|
524
|
-
else if ((firstByte & 0x20) !== 0) { // 001xxxxx - Dynamic Table Size Update
|
|
525
|
-
index
|
|
530
|
+
else if ((firstByte & 0x20) !== 0) { // 001xxxxx - Dynamic Table Size Update (RFC 7541 §6.3)
|
|
531
|
+
var _c = this.decodeInteger(buffer, index, 5), newSize = _c[0], newIndex = _c[1];
|
|
532
|
+
this.maxDynamicTableSize = newSize;
|
|
533
|
+
// evict entries that exceed the new limit
|
|
534
|
+
while (this.dynamicTableSize > this.maxDynamicTableSize && this.dynamicTable.length > 0) {
|
|
535
|
+
var entry = this.dynamicTable.pop();
|
|
536
|
+
if (entry)
|
|
537
|
+
this.dynamicTableSize -= entry[0].length + entry[1].length + 32;
|
|
538
|
+
}
|
|
539
|
+
index = newIndex;
|
|
526
540
|
}
|
|
527
541
|
else if ((firstByte & 0x10) !== 0) { // 0001xxxx - Literal Header Field Never Indexed
|
|
528
|
-
var
|
|
542
|
+
var _d = this.decodeLiteralHeaderWithoutIndexing(buffer, index), name_4 = _d[0], value = _d[1], newIndex = _d[2];
|
|
529
543
|
if (name_4 && value)
|
|
530
544
|
headers.set(name_4, value);
|
|
531
545
|
index = newIndex;
|
|
532
546
|
}
|
|
533
547
|
else { // 0000xxxx - Literal Header Field without Indexing
|
|
534
|
-
var
|
|
548
|
+
var _e = this.decodeLiteralHeaderWithoutIndexing(buffer, index), name_5 = _e[0], value = _e[1], newIndex = _e[2];
|
|
535
549
|
if (name_5 && value)
|
|
536
550
|
headers.set(name_5, value);
|
|
537
551
|
index = newIndex;
|
|
@@ -594,18 +608,18 @@
|
|
|
594
608
|
if (staticIndex <= 0) {
|
|
595
609
|
return ['', '', newIndex];
|
|
596
610
|
}
|
|
597
|
-
var headerField = this.
|
|
611
|
+
var headerField = this.getIndexedHeader(staticIndex);
|
|
598
612
|
if (!headerField) {
|
|
599
613
|
return ['', '', newIndex];
|
|
600
614
|
}
|
|
601
615
|
return [headerField[0], headerField[1], newIndex];
|
|
602
616
|
};
|
|
603
617
|
HPACK.prototype.decodeLiteralHeaderWithIndexing = function (buffer, index) {
|
|
604
|
-
var _a = this.decodeInteger(buffer, index, 6),
|
|
605
|
-
index =
|
|
618
|
+
var _a = this.decodeInteger(buffer, index, 6), nameIndex = _a[0], nextIndex = _a[1];
|
|
619
|
+
index = nextIndex;
|
|
606
620
|
var name;
|
|
607
|
-
if (
|
|
608
|
-
var headerField = this.
|
|
621
|
+
if (nameIndex > 0) {
|
|
622
|
+
var headerField = this.getIndexedHeader(nameIndex);
|
|
609
623
|
name = headerField ? headerField[0] : '';
|
|
610
624
|
}
|
|
611
625
|
else {
|
|
@@ -614,10 +628,26 @@
|
|
|
614
628
|
index = newIndex;
|
|
615
629
|
}
|
|
616
630
|
var _c = this.decodeLiteralString(buffer, index), value = _c[0], finalIndex = _c[1];
|
|
631
|
+
// RFC 7541 §6.2.1: Literal Header Field with Incremental Indexing must add to dynamic table
|
|
632
|
+
this.addToDynamicTable(name, value);
|
|
617
633
|
return [name, value, finalIndex];
|
|
618
634
|
};
|
|
619
635
|
HPACK.prototype.decodeLiteralHeaderWithoutIndexing = function (buffer, index) {
|
|
620
|
-
|
|
636
|
+
// RFC 7541 §6.2.2 / §6.2.3: 4-bit prefix, do NOT add to dynamic table
|
|
637
|
+
var _a = this.decodeInteger(buffer, index, 4), nameIndex = _a[0], nextIndex = _a[1];
|
|
638
|
+
index = nextIndex;
|
|
639
|
+
var name;
|
|
640
|
+
if (nameIndex > 0) {
|
|
641
|
+
var headerField = this.getIndexedHeader(nameIndex);
|
|
642
|
+
name = headerField ? headerField[0] : '';
|
|
643
|
+
}
|
|
644
|
+
else {
|
|
645
|
+
var _b = this.decodeLiteralString(buffer, index), decodedName = _b[0], newIndex = _b[1];
|
|
646
|
+
name = decodedName;
|
|
647
|
+
index = newIndex;
|
|
648
|
+
}
|
|
649
|
+
var _c = this.decodeLiteralString(buffer, index), value = _c[0], finalIndex = _c[1];
|
|
650
|
+
return [name, value, finalIndex];
|
|
621
651
|
};
|
|
622
652
|
// 直接转换为字符串的方法
|
|
623
653
|
HPACK.prototype.huffmanDecodeToString = function (bytes) {
|
|
@@ -711,9 +741,11 @@
|
|
|
711
741
|
};
|
|
712
742
|
var defaultSettings = (_a = {},
|
|
713
743
|
_a[SETTINGS_PARAMETERS.HEADER_TABLE_SIZE] = 4096,
|
|
714
|
-
|
|
744
|
+
// gRPC 客户端不使用 Server Push,禁用以避免无效的 PUSH_PROMISE 处理
|
|
745
|
+
_a[SETTINGS_PARAMETERS.ENABLE_PUSH] = 0,
|
|
715
746
|
_a[SETTINGS_PARAMETERS.MAX_CONCURRENT_STREAMS] = 100,
|
|
716
|
-
|
|
747
|
+
// 匹配 parser 的实际接收缓冲区大小(4MB),避免服务端在单流上过早被限速
|
|
748
|
+
_a[SETTINGS_PARAMETERS.INITIAL_WINDOW_SIZE] = 4 << 20,
|
|
717
749
|
_a[SETTINGS_PARAMETERS.MAX_FRAME_SIZE] = 16 << 10,
|
|
718
750
|
_a[SETTINGS_PARAMETERS.MAX_HEADER_LIST_SIZE] = 8192,
|
|
719
751
|
_a);
|
|
@@ -779,8 +811,8 @@
|
|
|
779
811
|
// Message-Data
|
|
780
812
|
grpcMessage.set(data, 5);
|
|
781
813
|
// 然后将完整的 gRPC 消息分割成多个 HTTP/2 DATA 帧
|
|
782
|
-
//
|
|
783
|
-
var maxDataPerFrame = maxFrameSize
|
|
814
|
+
// maxFrameSize 是 payload 上限(RFC 7540 §6.5.2 MAX_FRAME_SIZE),不含 9 字节帧头
|
|
815
|
+
var maxDataPerFrame = maxFrameSize;
|
|
784
816
|
for (var offset = 0; offset < grpcMessage.length; offset += maxDataPerFrame) {
|
|
785
817
|
var remaining = grpcMessage.length - offset;
|
|
786
818
|
var chunkSize = Math.min(maxDataPerFrame, remaining);
|
|
@@ -813,14 +845,15 @@
|
|
|
813
845
|
var flags = endStream ? 0x01 : 0x0; // END_STREAM flag
|
|
814
846
|
return Http2Frame.createFrame(0x0, flags, streamId, framedData);
|
|
815
847
|
};
|
|
816
|
-
Http2Frame.createHeadersFrame = function (streamId, path, endHeaders, token) {
|
|
848
|
+
Http2Frame.createHeadersFrame = function (streamId, path, endHeaders, token, authority) {
|
|
817
849
|
if (endHeaders === void 0) { endHeaders = true; }
|
|
850
|
+
if (authority === void 0) { authority = 'localhost'; }
|
|
818
851
|
// gRPC-Web 需要的标准 headers
|
|
819
852
|
var headersList = {
|
|
820
853
|
':path': path,
|
|
821
854
|
':method': 'POST',
|
|
822
855
|
':scheme': 'http',
|
|
823
|
-
':authority':
|
|
856
|
+
':authority': authority,
|
|
824
857
|
'content-type': 'application/grpc+proto',
|
|
825
858
|
'user-agent': 'grpc-web-client/0.1',
|
|
826
859
|
'accept': 'application/grpc+proto',
|
|
@@ -954,7 +987,11 @@
|
|
|
954
987
|
var HTTP2Parser = /** @class */ (function () {
|
|
955
988
|
function HTTP2Parser(writer, options) {
|
|
956
989
|
var _a;
|
|
957
|
-
|
|
990
|
+
/** 分段缓冲:避免每次 chunk 到达时 O(n) 全量拷贝 */
|
|
991
|
+
this.bufferChunks = [];
|
|
992
|
+
this.bufferTotalLength = 0;
|
|
993
|
+
this.bufferChunks = [];
|
|
994
|
+
this.bufferTotalLength = 0;
|
|
958
995
|
this.settingsAckReceived = false;
|
|
959
996
|
this.peerSettingsReceived = false;
|
|
960
997
|
// 初始化连接级别的流控制窗口大小(默认值:65,535)
|
|
@@ -968,15 +1005,51 @@
|
|
|
968
1005
|
this.sendStreamWindows = new Map();
|
|
969
1006
|
this.peerInitialStreamWindow = 65535;
|
|
970
1007
|
this.sendWindowWaiters = [];
|
|
1008
|
+
this.settingsAckWaiters = [];
|
|
1009
|
+
this.peerSettingsWaiters = [];
|
|
1010
|
+
this.endOfStreamWaiters = [];
|
|
971
1011
|
// 结束标志
|
|
972
1012
|
this.endFlag = false;
|
|
973
1013
|
this.writer = writer;
|
|
974
1014
|
this.compatibilityMode = (_a = options === null || options === void 0 ? void 0 : options.compatibilityMode) !== null && _a !== void 0 ? _a : false;
|
|
975
1015
|
}
|
|
1016
|
+
Object.defineProperty(HTTP2Parser.prototype, "buffer", {
|
|
1017
|
+
/** 兼容旧代码读取 buffer —— 仅在必须全量访问时调用 _flattenBuffer() */
|
|
1018
|
+
get: function () { return this._flattenBuffer(); },
|
|
1019
|
+
set: function (v) { this.bufferChunks = v.length ? [v] : []; this.bufferTotalLength = v.length; },
|
|
1020
|
+
enumerable: false,
|
|
1021
|
+
configurable: true
|
|
1022
|
+
});
|
|
1023
|
+
/** 将所有分段合并为一个连续 Uint8Array(仅在必要时调用)*/
|
|
1024
|
+
HTTP2Parser.prototype._flattenBuffer = function () {
|
|
1025
|
+
if (this.bufferChunks.length === 0)
|
|
1026
|
+
return new Uint8Array(0);
|
|
1027
|
+
if (this.bufferChunks.length === 1)
|
|
1028
|
+
return this.bufferChunks[0];
|
|
1029
|
+
var out = new Uint8Array(this.bufferTotalLength);
|
|
1030
|
+
var off = 0;
|
|
1031
|
+
for (var _i = 0, _a = this.bufferChunks; _i < _a.length; _i++) {
|
|
1032
|
+
var c = _a[_i];
|
|
1033
|
+
out.set(c, off);
|
|
1034
|
+
off += c.length;
|
|
1035
|
+
}
|
|
1036
|
+
return out;
|
|
1037
|
+
};
|
|
1038
|
+
/** 唤醒所有发送窗口等待者 */
|
|
1039
|
+
HTTP2Parser.prototype._wakeWindowWaiters = function () {
|
|
1040
|
+
var ws = this.sendWindowWaiters.splice(0);
|
|
1041
|
+
for (var _i = 0, ws_1 = ws; _i < ws_1.length; _i++) {
|
|
1042
|
+
var w = ws_1[_i];
|
|
1043
|
+
try {
|
|
1044
|
+
w.resolve();
|
|
1045
|
+
}
|
|
1046
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
1047
|
+
}
|
|
1048
|
+
};
|
|
976
1049
|
// 持续处理流数据
|
|
977
1050
|
HTTP2Parser.prototype.processStream = function (stream) {
|
|
978
1051
|
return __awaiter(this, void 0, void 0, function () {
|
|
979
|
-
var chunk, e_1_1, error_1;
|
|
1052
|
+
var chunk, e_1_1, error_1, errMsg, isAbortCleanup;
|
|
980
1053
|
var _a, stream_1, stream_1_1;
|
|
981
1054
|
var _b, e_1, _c, _d;
|
|
982
1055
|
var _e;
|
|
@@ -1020,7 +1093,6 @@
|
|
|
1020
1093
|
case 12:
|
|
1021
1094
|
// Stream 结束后的清理工作
|
|
1022
1095
|
if (!this.compatibilityMode && !this.endFlag) {
|
|
1023
|
-
this.endFlag = true;
|
|
1024
1096
|
try {
|
|
1025
1097
|
(_e = this.onEnd) === null || _e === void 0 ? void 0 : _e.call(this);
|
|
1026
1098
|
}
|
|
@@ -1028,55 +1100,87 @@
|
|
|
1028
1100
|
console.error("Error during onEnd callback:", err);
|
|
1029
1101
|
}
|
|
1030
1102
|
}
|
|
1103
|
+
// 无论何种模式,stream 结束时都通知 waitForEndOfStream 等待者,
|
|
1104
|
+
// 防止 compatibilityMode=true(server-streaming)时 waitForEndOfStream(0) 永久挂死
|
|
1105
|
+
if (!this.endFlag) {
|
|
1106
|
+
this._notifyEndOfStream();
|
|
1107
|
+
}
|
|
1031
1108
|
return [3 /*break*/, 14];
|
|
1032
1109
|
case 13:
|
|
1033
1110
|
error_1 = _f.sent();
|
|
1034
|
-
|
|
1111
|
+
errMsg = error_1 instanceof Error ? error_1.message : String(error_1);
|
|
1112
|
+
isAbortCleanup = /cleanup/i.test(errMsg) || /aborted/i.test(errMsg);
|
|
1113
|
+
if (isAbortCleanup) {
|
|
1114
|
+
console.debug("[processStream] stream aborted (expected):", errMsg);
|
|
1115
|
+
}
|
|
1116
|
+
else {
|
|
1117
|
+
console.error("Error processing stream:", error_1);
|
|
1118
|
+
}
|
|
1119
|
+
// 确保 waitForEndOfStream 等待者得到通知,防止 operationPromise 后台挂死
|
|
1120
|
+
if (!this.endFlag) {
|
|
1121
|
+
this._notifyEndOfStream();
|
|
1122
|
+
}
|
|
1035
1123
|
throw error_1;
|
|
1036
1124
|
case 14: return [2 /*return*/];
|
|
1037
1125
|
}
|
|
1038
1126
|
});
|
|
1039
1127
|
});
|
|
1040
1128
|
};
|
|
1041
|
-
// 处理单个数据块
|
|
1129
|
+
// 处理单个数据块 — 分段列表追加,避免每次 O(n) 全量拷贝
|
|
1042
1130
|
HTTP2Parser.prototype._processChunk = function (chunk) {
|
|
1043
1131
|
// chunk 是 Uint8ArrayList 或 Uint8Array
|
|
1044
1132
|
var newData = 'subarray' in chunk && typeof chunk.subarray === 'function'
|
|
1045
1133
|
? chunk.subarray()
|
|
1046
1134
|
: chunk;
|
|
1047
|
-
//
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1135
|
+
// 追加到分段列表,O(1),不拷贝历史数据
|
|
1136
|
+
if (newData.length > 0) {
|
|
1137
|
+
this.bufferChunks.push(newData);
|
|
1138
|
+
this.bufferTotalLength += newData.length;
|
|
1139
|
+
}
|
|
1140
|
+
// 将所有分段合并为一块后处理帧(只合并一次,后续 slice 替换)
|
|
1141
|
+
// 仅在确实有完整帧时才触发合并,碎片仅 push 不合并
|
|
1142
|
+
if (this.bufferTotalLength < 9)
|
|
1143
|
+
return;
|
|
1144
|
+
// 合并一次
|
|
1145
|
+
var flat = this._flattenBuffer();
|
|
1146
|
+
this.bufferChunks = [flat];
|
|
1147
|
+
// bufferTotalLength 保持不变
|
|
1052
1148
|
// 持续处理所有完整的帧
|
|
1053
1149
|
var readOffset = 0;
|
|
1054
|
-
while (
|
|
1150
|
+
while (flat.length - readOffset >= 9) {
|
|
1055
1151
|
// 判断是否有HTTP/2前导
|
|
1056
|
-
if (
|
|
1152
|
+
if (flat.length - readOffset >= 24 && this.isHttp2Preface(flat.subarray(readOffset))) {
|
|
1057
1153
|
readOffset += 24;
|
|
1058
1154
|
// 发送SETTINGS帧
|
|
1059
1155
|
var settingFrame = Http2Frame.createSettingsFrame();
|
|
1060
1156
|
this.writer.write(settingFrame);
|
|
1061
1157
|
continue;
|
|
1062
1158
|
}
|
|
1063
|
-
var frameHeader = this._parseFrameHeader(
|
|
1159
|
+
var frameHeader = this._parseFrameHeader(flat.subarray(readOffset));
|
|
1064
1160
|
var totalFrameLength = 9 + frameHeader.length;
|
|
1065
1161
|
// 检查是否有完整的帧
|
|
1066
|
-
if (
|
|
1162
|
+
if (flat.length - readOffset < totalFrameLength) {
|
|
1067
1163
|
break;
|
|
1068
1164
|
}
|
|
1069
|
-
//
|
|
1070
|
-
var frameData =
|
|
1165
|
+
// 获取完整帧数据(subarray 视图,零拷贝)
|
|
1166
|
+
var frameData = flat.subarray(readOffset, readOffset + totalFrameLength);
|
|
1071
1167
|
// 处理不同类型的帧
|
|
1072
1168
|
this._handleFrame(frameHeader, frameData).catch(function (err) {
|
|
1073
1169
|
console.error("Error handling frame:", err);
|
|
1074
1170
|
});
|
|
1075
|
-
// 移动偏移量
|
|
1076
1171
|
readOffset += totalFrameLength;
|
|
1077
1172
|
}
|
|
1173
|
+
// 保留未消费的尾部字节(slice 一次,后续仍分段追加)
|
|
1078
1174
|
if (readOffset > 0) {
|
|
1079
|
-
|
|
1175
|
+
if (readOffset >= flat.length) {
|
|
1176
|
+
this.bufferChunks = [];
|
|
1177
|
+
this.bufferTotalLength = 0;
|
|
1178
|
+
}
|
|
1179
|
+
else {
|
|
1180
|
+
var remaining = flat.slice(readOffset);
|
|
1181
|
+
this.bufferChunks = [remaining];
|
|
1182
|
+
this.bufferTotalLength = remaining.length;
|
|
1183
|
+
}
|
|
1080
1184
|
}
|
|
1081
1185
|
};
|
|
1082
1186
|
HTTP2Parser.prototype.isHttp2Preface = function (buffer) {
|
|
@@ -1088,11 +1192,7 @@
|
|
|
1088
1192
|
}
|
|
1089
1193
|
return true;
|
|
1090
1194
|
};
|
|
1091
|
-
//
|
|
1092
|
-
HTTP2Parser.prototype._oldProcessStream_removed = function () {
|
|
1093
|
-
// 这个方法已被上面的事件驱动实现替代
|
|
1094
|
-
};
|
|
1095
|
-
// 等待SETTINGS ACK
|
|
1195
|
+
// 等待SETTINGS ACK — 事件驱动,无轮询
|
|
1096
1196
|
HTTP2Parser.prototype.waitForSettingsAck = function () {
|
|
1097
1197
|
var _this = this;
|
|
1098
1198
|
return new Promise(function (resolve, reject) {
|
|
@@ -1100,20 +1200,32 @@
|
|
|
1100
1200
|
resolve();
|
|
1101
1201
|
return;
|
|
1102
1202
|
}
|
|
1103
|
-
var
|
|
1104
|
-
|
|
1105
|
-
clearInterval(interval);
|
|
1106
|
-
clearTimeout(timeout);
|
|
1107
|
-
resolve();
|
|
1108
|
-
}
|
|
1109
|
-
}, 100);
|
|
1203
|
+
var waiter = { resolve: resolve, reject: reject };
|
|
1204
|
+
_this.settingsAckWaiters.push(waiter);
|
|
1110
1205
|
var timeout = setTimeout(function () {
|
|
1111
|
-
|
|
1206
|
+
var idx = _this.settingsAckWaiters.indexOf(waiter);
|
|
1207
|
+
if (idx >= 0)
|
|
1208
|
+
_this.settingsAckWaiters.splice(idx, 1);
|
|
1112
1209
|
reject(new Error("Settings ACK timeout"));
|
|
1113
1210
|
}, 30000);
|
|
1211
|
+
// 覆盖 resolve 以便超时前自动清理定时器
|
|
1212
|
+
waiter.resolve = function () { clearTimeout(timeout); resolve(); };
|
|
1213
|
+
waiter.reject = function (e) { clearTimeout(timeout); reject(e); };
|
|
1114
1214
|
});
|
|
1115
1215
|
};
|
|
1116
|
-
|
|
1216
|
+
/** 内部调用:SETTINGS ACK 收到时唤醒所有等待者 */
|
|
1217
|
+
HTTP2Parser.prototype._notifySettingsAck = function () {
|
|
1218
|
+
this.settingsAckReceived = true;
|
|
1219
|
+
var ws = this.settingsAckWaiters.splice(0);
|
|
1220
|
+
for (var _i = 0, ws_2 = ws; _i < ws_2.length; _i++) {
|
|
1221
|
+
var w = ws_2[_i];
|
|
1222
|
+
try {
|
|
1223
|
+
w.resolve();
|
|
1224
|
+
}
|
|
1225
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
1226
|
+
}
|
|
1227
|
+
};
|
|
1228
|
+
// 等待接收来自对端的 SETTINGS(非 ACK)— 事件驱动,无轮询
|
|
1117
1229
|
HTTP2Parser.prototype.waitForPeerSettings = function (timeoutMs) {
|
|
1118
1230
|
var _this = this;
|
|
1119
1231
|
if (timeoutMs === void 0) { timeoutMs = 30000; }
|
|
@@ -1122,19 +1234,30 @@
|
|
|
1122
1234
|
resolve();
|
|
1123
1235
|
return;
|
|
1124
1236
|
}
|
|
1125
|
-
var
|
|
1126
|
-
|
|
1127
|
-
clearInterval(interval);
|
|
1128
|
-
clearTimeout(timeout);
|
|
1129
|
-
resolve();
|
|
1130
|
-
}
|
|
1131
|
-
}, 100);
|
|
1237
|
+
var waiter = { resolve: resolve, reject: reject };
|
|
1238
|
+
_this.peerSettingsWaiters.push(waiter);
|
|
1132
1239
|
var timeout = setTimeout(function () {
|
|
1133
|
-
|
|
1240
|
+
var idx = _this.peerSettingsWaiters.indexOf(waiter);
|
|
1241
|
+
if (idx >= 0)
|
|
1242
|
+
_this.peerSettingsWaiters.splice(idx, 1);
|
|
1134
1243
|
reject(new Error("Peer SETTINGS timeout"));
|
|
1135
1244
|
}, timeoutMs);
|
|
1245
|
+
waiter.resolve = function () { clearTimeout(timeout); resolve(); };
|
|
1246
|
+
waiter.reject = function (e) { clearTimeout(timeout); reject(e); };
|
|
1136
1247
|
});
|
|
1137
1248
|
};
|
|
1249
|
+
/** 内部调用:收到对端 SETTINGS(非 ACK)时唤醒等待者 */
|
|
1250
|
+
HTTP2Parser.prototype._notifyPeerSettings = function () {
|
|
1251
|
+
this.peerSettingsReceived = true;
|
|
1252
|
+
var ws = this.peerSettingsWaiters.splice(0);
|
|
1253
|
+
for (var _i = 0, ws_3 = ws; _i < ws_3.length; _i++) {
|
|
1254
|
+
var w = ws_3[_i];
|
|
1255
|
+
try {
|
|
1256
|
+
w.resolve();
|
|
1257
|
+
}
|
|
1258
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1138
1261
|
// 注册我们要发送数据的出站流(用于初始化该流的对端窗口)
|
|
1139
1262
|
HTTP2Parser.prototype.registerOutboundStream = function (streamId) {
|
|
1140
1263
|
if (!this.sendStreamWindows.has(streamId)) {
|
|
@@ -1164,75 +1287,67 @@
|
|
|
1164
1287
|
this.sendConnWindow = Math.min(0x7fffffff, this.sendConnWindow + bytes);
|
|
1165
1288
|
var cur = (_a = this.sendStreamWindows.get(streamId)) !== null && _a !== void 0 ? _a : 0;
|
|
1166
1289
|
this.sendStreamWindows.set(streamId, Math.min(0x7fffffff, cur + bytes));
|
|
1290
|
+
// 窗口增大,唤醒等待者
|
|
1291
|
+
this._wakeWindowWaiters();
|
|
1167
1292
|
};
|
|
1168
|
-
//
|
|
1169
|
-
HTTP2Parser.prototype.waitForSendWindow = function (
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
return
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
_this.sendWindowWaiters.push(wake);
|
|
1214
|
-
// 同时做一个轻微的轮询,防止错过唤醒
|
|
1215
|
-
interval = setInterval(function () {
|
|
1216
|
-
if (check() && interval) {
|
|
1217
|
-
clearInterval(interval);
|
|
1218
|
-
interval = null;
|
|
1219
|
-
}
|
|
1220
|
-
}, 50);
|
|
1221
|
-
})];
|
|
1222
|
-
});
|
|
1293
|
+
// 等待可用发送窗口 — 事件驱动,WINDOW_UPDATE/SETTINGS 收到时直接唤醒
|
|
1294
|
+
HTTP2Parser.prototype.waitForSendWindow = function (streamId, minBytes, timeoutMs) {
|
|
1295
|
+
var _this = this;
|
|
1296
|
+
if (minBytes === void 0) { minBytes = 1; }
|
|
1297
|
+
if (timeoutMs === void 0) { timeoutMs = 30000; }
|
|
1298
|
+
var _a = this.getSendWindows(streamId), conn = _a.conn, stream = _a.stream;
|
|
1299
|
+
if (conn >= minBytes && stream >= minBytes)
|
|
1300
|
+
return Promise.resolve();
|
|
1301
|
+
return new Promise(function (resolve, reject) {
|
|
1302
|
+
var settled = false;
|
|
1303
|
+
var timeout = timeoutMs > 0
|
|
1304
|
+
? setTimeout(function () {
|
|
1305
|
+
if (settled)
|
|
1306
|
+
return;
|
|
1307
|
+
settled = true;
|
|
1308
|
+
var idx = _this.sendWindowWaiters.findIndex(function (w) { return w.resolve === resolveWrap; });
|
|
1309
|
+
if (idx >= 0)
|
|
1310
|
+
_this.sendWindowWaiters.splice(idx, 1);
|
|
1311
|
+
reject(new Error('Send window wait timeout'));
|
|
1312
|
+
}, timeoutMs)
|
|
1313
|
+
: undefined;
|
|
1314
|
+
var resolveWrap = function () {
|
|
1315
|
+
if (settled)
|
|
1316
|
+
return;
|
|
1317
|
+
var _a = _this.getSendWindows(streamId), c2 = _a.conn, s2 = _a.stream;
|
|
1318
|
+
if (c2 >= minBytes && s2 >= minBytes) {
|
|
1319
|
+
settled = true;
|
|
1320
|
+
if (timeout)
|
|
1321
|
+
clearTimeout(timeout);
|
|
1322
|
+
resolve();
|
|
1323
|
+
}
|
|
1324
|
+
else {
|
|
1325
|
+
// 窗口仍不够,重新入队等待下一次更新
|
|
1326
|
+
_this.sendWindowWaiters.push({ resolve: resolveWrap, reject: rejectWrap });
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
var rejectWrap = function (e) {
|
|
1330
|
+
if (settled)
|
|
1331
|
+
return;
|
|
1332
|
+
settled = true;
|
|
1333
|
+
if (timeout)
|
|
1334
|
+
clearTimeout(timeout);
|
|
1335
|
+
reject(e);
|
|
1336
|
+
};
|
|
1337
|
+
_this.sendWindowWaiters.push({ resolve: resolveWrap, reject: rejectWrap });
|
|
1223
1338
|
});
|
|
1224
1339
|
};
|
|
1225
1340
|
// 处理单个帧
|
|
1226
1341
|
HTTP2Parser.prototype._handleFrame = function (frameHeader, frameData) {
|
|
1227
1342
|
return __awaiter(this, void 0, void 0, function () {
|
|
1228
|
-
var settingsPayload, settings, initialWindowDelta_1, maxConcurrentStreams, i, id, value, payload,
|
|
1343
|
+
var settingsPayload, settings, initialWindowDelta_1, maxConcurrentStreams, i, id, value, payload, dataLength, streamWindowUpdate, connWindowUpdate, result, cur, info, body, view, lastStreamId, errorCode;
|
|
1229
1344
|
var _this = this;
|
|
1230
|
-
var _a, _b, _c, _d, _e;
|
|
1231
|
-
return __generator(this, function (
|
|
1345
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1346
|
+
return __generator(this, function (_h) {
|
|
1232
1347
|
switch (frameHeader.type) {
|
|
1233
1348
|
case FRAME_TYPES.SETTINGS:
|
|
1234
1349
|
if ((frameHeader.flags & FRAME_FLAGS.ACK) === FRAME_FLAGS.ACK) {
|
|
1235
|
-
this.
|
|
1350
|
+
this._notifySettingsAck();
|
|
1236
1351
|
}
|
|
1237
1352
|
else {
|
|
1238
1353
|
settingsPayload = frameData.slice(9);
|
|
@@ -1241,10 +1356,10 @@
|
|
|
1241
1356
|
maxConcurrentStreams = void 0;
|
|
1242
1357
|
for (i = 0; i < settingsPayload.length; i += 6) {
|
|
1243
1358
|
id = (settingsPayload[i] << 8) | settingsPayload[i + 1];
|
|
1244
|
-
value = (settingsPayload[i + 2] << 24) |
|
|
1359
|
+
value = ((settingsPayload[i + 2] << 24) |
|
|
1245
1360
|
(settingsPayload[i + 3] << 16) |
|
|
1246
1361
|
(settingsPayload[i + 4] << 8) |
|
|
1247
|
-
settingsPayload[i + 5];
|
|
1362
|
+
settingsPayload[i + 5]) >>> 0;
|
|
1248
1363
|
settings[id] = value;
|
|
1249
1364
|
if (id === 4) {
|
|
1250
1365
|
// SETTINGS_INITIAL_WINDOW_SIZE
|
|
@@ -1283,45 +1398,41 @@
|
|
|
1283
1398
|
if (this.onSettings) {
|
|
1284
1399
|
this.onSettings(frameHeader);
|
|
1285
1400
|
}
|
|
1286
|
-
// 标记已收到对端 SETTINGS
|
|
1287
|
-
this.
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
fn();
|
|
1291
|
-
}
|
|
1292
|
-
catch (e) {
|
|
1293
|
-
console.debug('waiter error', e);
|
|
1294
|
-
} });
|
|
1401
|
+
// 标记已收到对端 SETTINGS 并唤醒等待者
|
|
1402
|
+
this._notifyPeerSettings();
|
|
1403
|
+
// 唤醒发送窗口等待者(以防部分实现通过 SETTINGS 改变有效窗口)
|
|
1404
|
+
this._wakeWindowWaiters();
|
|
1295
1405
|
}
|
|
1296
1406
|
break;
|
|
1297
|
-
case FRAME_TYPES.DATA:
|
|
1407
|
+
case FRAME_TYPES.DATA: {
|
|
1298
1408
|
// 处理数据帧
|
|
1299
1409
|
if (this.onData) {
|
|
1300
1410
|
this.onData(frameData.slice(9), frameHeader); // 跳过帧头
|
|
1301
1411
|
}
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1412
|
+
dataLength = (_a = frameHeader.length) !== null && _a !== void 0 ? _a : 0;
|
|
1413
|
+
if (dataLength > 0) {
|
|
1414
|
+
try {
|
|
1415
|
+
// 更新流级别的窗口
|
|
1416
|
+
if (frameHeader.streamId !== 0) {
|
|
1417
|
+
streamWindowUpdate = Http2Frame.createWindowUpdateFrame(frameHeader.streamId, dataLength);
|
|
1418
|
+
this.writer.write(streamWindowUpdate);
|
|
1419
|
+
}
|
|
1420
|
+
connWindowUpdate = Http2Frame.createWindowUpdateFrame(0, dataLength);
|
|
1421
|
+
this.writer.write(connWindowUpdate);
|
|
1422
|
+
}
|
|
1423
|
+
catch (err) {
|
|
1424
|
+
console.error("[HTTP2] Error sending window update:", err);
|
|
1308
1425
|
}
|
|
1309
|
-
connWindowUpdate = Http2Frame.createWindowUpdateFrame(0, (_b = frameHeader.length) !== null && _b !== void 0 ? _b : 0);
|
|
1310
|
-
this.writer.write(connWindowUpdate);
|
|
1311
|
-
}
|
|
1312
|
-
catch (err) {
|
|
1313
|
-
console.error("[HTTP2] Error sending window update:", err);
|
|
1314
1426
|
}
|
|
1315
1427
|
//判断是否是最后一个帧
|
|
1316
1428
|
if ((frameHeader.flags & FRAME_FLAGS.END_STREAM) ===
|
|
1317
1429
|
FRAME_FLAGS.END_STREAM) {
|
|
1318
|
-
this.
|
|
1319
|
-
|
|
1320
|
-
this.onEnd();
|
|
1321
|
-
}
|
|
1430
|
+
(_b = this.onEnd) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
1431
|
+
this._notifyEndOfStream();
|
|
1322
1432
|
return [2 /*return*/];
|
|
1323
1433
|
}
|
|
1324
1434
|
break;
|
|
1435
|
+
}
|
|
1325
1436
|
case FRAME_TYPES.HEADERS:
|
|
1326
1437
|
// 处理头部帧
|
|
1327
1438
|
if (this.onHeaders) {
|
|
@@ -1330,35 +1441,26 @@
|
|
|
1330
1441
|
//判断是否是最后一个帧
|
|
1331
1442
|
if ((frameHeader.flags & FRAME_FLAGS.END_STREAM) ===
|
|
1332
1443
|
FRAME_FLAGS.END_STREAM) {
|
|
1333
|
-
this.
|
|
1334
|
-
|
|
1335
|
-
this.onEnd();
|
|
1336
|
-
}
|
|
1444
|
+
(_c = this.onEnd) === null || _c === void 0 ? void 0 : _c.call(this);
|
|
1445
|
+
this._notifyEndOfStream();
|
|
1337
1446
|
return [2 /*return*/];
|
|
1338
1447
|
}
|
|
1339
1448
|
break;
|
|
1340
1449
|
case FRAME_TYPES.WINDOW_UPDATE:
|
|
1341
|
-
//
|
|
1342
|
-
this.handleWindowUpdateFrame(frameHeader, frameData);
|
|
1343
|
-
// 更新发送窗口(对端接收窗口)
|
|
1450
|
+
// 处理窗口更新帧(同时更新接收侧诊断计数器和发送侧流控窗口,只解析一次)
|
|
1344
1451
|
try {
|
|
1345
|
-
|
|
1452
|
+
result = this.handleWindowUpdateFrame(frameHeader, frameData);
|
|
1453
|
+
// 更新发送方向窗口(对端的接收窗口)
|
|
1346
1454
|
if (frameHeader.streamId === 0) {
|
|
1347
|
-
this.sendConnWindow +=
|
|
1455
|
+
this.sendConnWindow += result.windowSizeIncrement;
|
|
1348
1456
|
}
|
|
1349
1457
|
else {
|
|
1350
|
-
cur = (
|
|
1351
|
-
this.sendStreamWindows.set(frameHeader.streamId, cur +
|
|
1352
|
-
}
|
|
1353
|
-
waiters = this.sendWindowWaiters.splice(0);
|
|
1354
|
-
waiters.forEach(function (fn) { try {
|
|
1355
|
-
fn();
|
|
1458
|
+
cur = (_d = this.sendStreamWindows.get(frameHeader.streamId)) !== null && _d !== void 0 ? _d : this.peerInitialStreamWindow;
|
|
1459
|
+
this.sendStreamWindows.set(frameHeader.streamId, cur + result.windowSizeIncrement);
|
|
1356
1460
|
}
|
|
1357
|
-
|
|
1358
|
-
console.debug('waiter error', e);
|
|
1359
|
-
} });
|
|
1461
|
+
this._wakeWindowWaiters();
|
|
1360
1462
|
}
|
|
1361
|
-
catch ( /* ignore WINDOW_UPDATE parse errors */
|
|
1463
|
+
catch ( /* ignore WINDOW_UPDATE parse errors (e.g. increment=0 is RFC PROTOCOL_ERROR) */_j) { /* ignore WINDOW_UPDATE parse errors (e.g. increment=0 is RFC PROTOCOL_ERROR) */ }
|
|
1362
1464
|
break;
|
|
1363
1465
|
case FRAME_TYPES.PING:
|
|
1364
1466
|
// 处理PING帧
|
|
@@ -1380,20 +1482,20 @@
|
|
|
1380
1482
|
info = {};
|
|
1381
1483
|
}
|
|
1382
1484
|
}
|
|
1383
|
-
catch ( /* ignore GOAWAY parse errors */
|
|
1485
|
+
catch ( /* ignore GOAWAY parse errors */_k) { /* ignore GOAWAY parse errors */ }
|
|
1384
1486
|
try {
|
|
1385
|
-
(
|
|
1487
|
+
(_e = this.onGoaway) === null || _e === void 0 ? void 0 : _e.call(this, info !== null && info !== void 0 ? info : {});
|
|
1386
1488
|
}
|
|
1387
1489
|
catch (err) {
|
|
1388
1490
|
console.error('Error during GOAWAY callback:', err);
|
|
1389
1491
|
}
|
|
1390
|
-
this.endFlag = true;
|
|
1391
1492
|
try {
|
|
1392
|
-
(
|
|
1493
|
+
(_f = this.onEnd) === null || _f === void 0 ? void 0 : _f.call(this);
|
|
1393
1494
|
}
|
|
1394
1495
|
catch (err) {
|
|
1395
1496
|
console.error('Error during GOAWAY onEnd callback:', err);
|
|
1396
1497
|
}
|
|
1498
|
+
this._notifyEndOfStream();
|
|
1397
1499
|
break;
|
|
1398
1500
|
}
|
|
1399
1501
|
// case FRAME_TYPES.PUSH_PROMISE:
|
|
@@ -1401,10 +1503,8 @@
|
|
|
1401
1503
|
// this.handlePushPromiseFrame(frameHeader, frameData);
|
|
1402
1504
|
// break;
|
|
1403
1505
|
case FRAME_TYPES.RST_STREAM:
|
|
1404
|
-
this.
|
|
1405
|
-
|
|
1406
|
-
this.onEnd();
|
|
1407
|
-
}
|
|
1506
|
+
(_g = this.onEnd) === null || _g === void 0 ? void 0 : _g.call(this);
|
|
1507
|
+
this._notifyEndOfStream();
|
|
1408
1508
|
break;
|
|
1409
1509
|
default:
|
|
1410
1510
|
console.debug("Unknown frame type:", frameHeader.type);
|
|
@@ -1417,7 +1517,8 @@
|
|
|
1417
1517
|
var length = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
|
|
1418
1518
|
var type = buffer[3];
|
|
1419
1519
|
var flags = buffer[4];
|
|
1420
|
-
|
|
1520
|
+
// RFC 7540 §4.1: most significant bit is reserved and MUST be ignored on receipt
|
|
1521
|
+
var streamId = ((buffer[5] << 24) | (buffer[6] << 16) | (buffer[7] << 8) | buffer[8]) & 0x7fffffff;
|
|
1421
1522
|
return {
|
|
1422
1523
|
length: length,
|
|
1423
1524
|
type: type,
|
|
@@ -1446,53 +1547,42 @@
|
|
|
1446
1547
|
throw error;
|
|
1447
1548
|
}
|
|
1448
1549
|
};
|
|
1449
|
-
|
|
1550
|
+
// 等待流结束 — 事件驱动,onEnd 触发时直接唤醒,无 setInterval 轮询
|
|
1450
1551
|
HTTP2Parser.prototype.waitForEndOfStream = function (waitTime) {
|
|
1451
1552
|
var _this = this;
|
|
1452
1553
|
return new Promise(function (resolve, reject) {
|
|
1453
|
-
// If the stream has already ended, resolve immediately
|
|
1454
1554
|
if (_this.endFlag) {
|
|
1455
1555
|
resolve();
|
|
1456
1556
|
return;
|
|
1457
1557
|
}
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1558
|
+
var waiter = { resolve: resolve, reject: reject };
|
|
1559
|
+
_this.endOfStreamWaiters.push(waiter);
|
|
1560
|
+
var timeout = waitTime > 0
|
|
1561
|
+
? setTimeout(function () {
|
|
1562
|
+
var idx = _this.endOfStreamWaiters.indexOf(waiter);
|
|
1563
|
+
if (idx >= 0)
|
|
1564
|
+
_this.endOfStreamWaiters.splice(idx, 1);
|
|
1463
1565
|
reject(new Error("End of stream timeout"));
|
|
1464
|
-
}, waitTime)
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
if (_this.endFlag) {
|
|
1471
|
-
if (timeout !== null) {
|
|
1472
|
-
clearTimeout(timeout);
|
|
1473
|
-
}
|
|
1474
|
-
clearInterval(interval);
|
|
1475
|
-
resolve();
|
|
1476
|
-
}
|
|
1477
|
-
}, checkInterval);
|
|
1478
|
-
// If the onEnd is triggered externally, it should now be marked manually
|
|
1479
|
-
var originalOnEnd = _this.onEnd;
|
|
1480
|
-
_this.onEnd = function () {
|
|
1481
|
-
if (!_this.endFlag) {
|
|
1482
|
-
// The external trigger may set endFlag; if not, handle here
|
|
1483
|
-
_this.endFlag = true;
|
|
1484
|
-
}
|
|
1485
|
-
if (timeout !== null) {
|
|
1486
|
-
clearTimeout(timeout);
|
|
1487
|
-
}
|
|
1488
|
-
clearInterval(interval);
|
|
1489
|
-
resolve();
|
|
1490
|
-
if (originalOnEnd) {
|
|
1491
|
-
originalOnEnd(); // Call the original onEnd function if set
|
|
1492
|
-
}
|
|
1493
|
-
};
|
|
1566
|
+
}, waitTime)
|
|
1567
|
+
: null;
|
|
1568
|
+
waiter.resolve = function () { if (timeout)
|
|
1569
|
+
clearTimeout(timeout); resolve(); };
|
|
1570
|
+
waiter.reject = function (e) { if (timeout)
|
|
1571
|
+
clearTimeout(timeout); reject(e); };
|
|
1494
1572
|
});
|
|
1495
1573
|
};
|
|
1574
|
+
/** 内部调用:流结束时唤醒所有 waitForEndOfStream 等待者 */
|
|
1575
|
+
HTTP2Parser.prototype._notifyEndOfStream = function () {
|
|
1576
|
+
this.endFlag = true;
|
|
1577
|
+
var ws = this.endOfStreamWaiters.splice(0);
|
|
1578
|
+
for (var _i = 0, ws_4 = ws; _i < ws_4.length; _i++) {
|
|
1579
|
+
var w = ws_4[_i];
|
|
1580
|
+
try {
|
|
1581
|
+
w.resolve();
|
|
1582
|
+
}
|
|
1583
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
1584
|
+
}
|
|
1585
|
+
};
|
|
1496
1586
|
// 解析 WINDOW_UPDATE 帧
|
|
1497
1587
|
HTTP2Parser.prototype.parseWindowUpdateFrame = function (frameBuffer, frameHeader) {
|
|
1498
1588
|
// WINDOW_UPDATE帧的payload固定为4字节
|
|
@@ -1886,6 +1976,8 @@
|
|
|
1886
1976
|
this.lastBytesDrainedSeen = 0;
|
|
1887
1977
|
this.lastBpWarnAt = 0;
|
|
1888
1978
|
this.isHandlingError = false; // 防止重复错误处理
|
|
1979
|
+
/** drain 事件驱动等待者,替代 flush() 中的 setInterval 轮询 */
|
|
1980
|
+
this.drainWaiters = [];
|
|
1889
1981
|
// 事件系统
|
|
1890
1982
|
this.listeners = new Map();
|
|
1891
1983
|
// 验证 stream 参数
|
|
@@ -2016,10 +2108,12 @@
|
|
|
2016
2108
|
_l.trys.push([4, 7, , 8]);
|
|
2017
2109
|
canContinue = this.stream.send(chunk);
|
|
2018
2110
|
if (!!canContinue) return [3 /*break*/, 6];
|
|
2019
|
-
//
|
|
2020
|
-
|
|
2111
|
+
// 传入 abort signal,当流被 abort 时 onDrain() 会立即 reject,
|
|
2112
|
+
// 避免在 abort 路径下永久挂住
|
|
2113
|
+
return [4 /*yield*/, this.stream.onDrain({ signal: this.abortController.signal })];
|
|
2021
2114
|
case 5:
|
|
2022
|
-
//
|
|
2115
|
+
// 传入 abort signal,当流被 abort 时 onDrain() 会立即 reject,
|
|
2116
|
+
// 避免在 abort 路径下永久挂住
|
|
2023
2117
|
_l.sent();
|
|
2024
2118
|
_l.label = 6;
|
|
2025
2119
|
case 6: return [3 /*break*/, 8];
|
|
@@ -2054,7 +2148,11 @@
|
|
|
2054
2148
|
if (e_1) throw e_1.error;
|
|
2055
2149
|
return [7 /*endfinally*/];
|
|
2056
2150
|
case 15: return [7 /*endfinally*/];
|
|
2057
|
-
case 16:
|
|
2151
|
+
case 16:
|
|
2152
|
+
// pipeline 正常结束(stream 关闭或 pushable 耗尽)—— 确保资源清理
|
|
2153
|
+
// 若已通过 abort() 触发则 cleanup() 内部幂等处理
|
|
2154
|
+
this.cleanup();
|
|
2155
|
+
return [2 /*return*/];
|
|
2058
2156
|
}
|
|
2059
2157
|
});
|
|
2060
2158
|
});
|
|
@@ -2064,7 +2162,7 @@
|
|
|
2064
2162
|
var self = this;
|
|
2065
2163
|
return function (source) {
|
|
2066
2164
|
return __asyncGenerator(this, arguments, function () {
|
|
2067
|
-
var _a, source_1, source_1_1, chunk, now, e_2_1;
|
|
2165
|
+
var _a, source_1, source_1_1, chunk, now, ws, _i, ws_1, fn, e_2_1;
|
|
2068
2166
|
var _b, e_2, _c, _d;
|
|
2069
2167
|
return __generator(this, function (_e) {
|
|
2070
2168
|
switch (_e.label) {
|
|
@@ -2101,6 +2199,17 @@
|
|
|
2101
2199
|
self.lastDrainEventAt = now;
|
|
2102
2200
|
self.dispatchEvent(new CustomEvent('drain', { detail: { drained: self.bytesDrained, queueSize: self.queueSize } }));
|
|
2103
2201
|
}
|
|
2202
|
+
// 唤醒所有在等 flush() 或背压解除 的 drainWaiters(队列降低时就可唤醒)
|
|
2203
|
+
if (self.drainWaiters.length > 0) {
|
|
2204
|
+
ws = self.drainWaiters.splice(0);
|
|
2205
|
+
for (_i = 0, ws_1 = ws; _i < ws_1.length; _i++) {
|
|
2206
|
+
fn = ws_1[_i];
|
|
2207
|
+
try {
|
|
2208
|
+
fn();
|
|
2209
|
+
}
|
|
2210
|
+
catch ( /* ignore */_f) { /* ignore */ }
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2104
2213
|
// 记录本次已消耗字节,用于看门狗判断是否前进
|
|
2105
2214
|
self.lastBytesDrainedSeen = self.bytesDrained;
|
|
2106
2215
|
}
|
|
@@ -2136,13 +2245,14 @@
|
|
|
2136
2245
|
};
|
|
2137
2246
|
};
|
|
2138
2247
|
// 简单的卡顿看门狗:当队列长期高位且 bytesDrained 无进展时发出 stalled 事件
|
|
2248
|
+
// 使用递归 setTimeout 而非 setInterval,避免标签页后台恢复时回调堆积导致 Violation
|
|
2139
2249
|
StreamWriter.prototype.startWatchdog = function (intervalMs, stallMs) {
|
|
2140
2250
|
var _this = this;
|
|
2141
2251
|
if (intervalMs === void 0) { intervalMs = 500; }
|
|
2142
2252
|
if (stallMs === void 0) { stallMs = 1500; }
|
|
2143
2253
|
if (this.watchdogTimer)
|
|
2144
2254
|
return;
|
|
2145
|
-
|
|
2255
|
+
var tick = function () {
|
|
2146
2256
|
if (_this.abortController.signal.aborted)
|
|
2147
2257
|
return;
|
|
2148
2258
|
var baseThreshold = _this.options.bufferSize * 0.7;
|
|
@@ -2153,7 +2263,13 @@
|
|
|
2153
2263
|
if (!_this.stallStartAt)
|
|
2154
2264
|
_this.stallStartAt = now;
|
|
2155
2265
|
if (now - _this.stallStartAt >= stallMs) {
|
|
2156
|
-
|
|
2266
|
+
// 异步触发事件,让当前 tick 立即返回,避免同步事件处理器阻塞主线程
|
|
2267
|
+
var detail_1 = { queueSize: q, drained: _this.bytesDrained, sinceMs: now - _this.stallStartAt };
|
|
2268
|
+
setTimeout(function () {
|
|
2269
|
+
if (!_this.abortController.signal.aborted) {
|
|
2270
|
+
_this.dispatchEvent(new CustomEvent('stalled', { detail: detail_1 }));
|
|
2271
|
+
}
|
|
2272
|
+
}, 0);
|
|
2157
2273
|
// 避免持续触发,推进起点
|
|
2158
2274
|
_this.stallStartAt = now;
|
|
2159
2275
|
}
|
|
@@ -2168,7 +2284,10 @@
|
|
|
2168
2284
|
// 队列回落,重置
|
|
2169
2285
|
_this.stallStartAt = 0;
|
|
2170
2286
|
}
|
|
2171
|
-
|
|
2287
|
+
// 本次 tick 完成后再安排下一次,不会因主线程繁忙而堆积
|
|
2288
|
+
_this.watchdogTimer = setTimeout(tick, intervalMs);
|
|
2289
|
+
};
|
|
2290
|
+
this.watchdogTimer = setTimeout(tick, intervalMs);
|
|
2172
2291
|
};
|
|
2173
2292
|
StreamWriter.prototype.write = function (data) {
|
|
2174
2293
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -2227,17 +2346,17 @@
|
|
|
2227
2346
|
};
|
|
2228
2347
|
StreamWriter.prototype.writeChunks = function (buffer) {
|
|
2229
2348
|
return __awaiter(this, void 0, void 0, function () {
|
|
2230
|
-
var offset, end, chunk;
|
|
2349
|
+
var src, offset, end, chunk;
|
|
2231
2350
|
return __generator(this, function (_a) {
|
|
2232
2351
|
switch (_a.label) {
|
|
2233
2352
|
case 0:
|
|
2353
|
+
src = new Uint8Array(buffer);
|
|
2234
2354
|
offset = 0;
|
|
2235
2355
|
_a.label = 1;
|
|
2236
2356
|
case 1:
|
|
2237
|
-
if (!(offset <
|
|
2238
|
-
end = Math.min(offset + this.options.chunkSize,
|
|
2239
|
-
chunk =
|
|
2240
|
-
chunk.set(new Uint8Array(buffer.slice(offset, end)));
|
|
2357
|
+
if (!(offset < src.byteLength)) return [3 /*break*/, 4];
|
|
2358
|
+
end = Math.min(offset + this.options.chunkSize, src.byteLength);
|
|
2359
|
+
chunk = src.subarray(offset, end);
|
|
2241
2360
|
return [4 /*yield*/, this.retryableWrite(chunk)];
|
|
2242
2361
|
case 2:
|
|
2243
2362
|
_a.sent();
|
|
@@ -2254,7 +2373,6 @@
|
|
|
2254
2373
|
StreamWriter.prototype.retryableWrite = function (chunk_1) {
|
|
2255
2374
|
return __awaiter(this, arguments, void 0, function (chunk, attempt) {
|
|
2256
2375
|
var currentSize, threshold, err_3, delay_1;
|
|
2257
|
-
var _this = this;
|
|
2258
2376
|
if (attempt === void 0) { attempt = 0; }
|
|
2259
2377
|
return __generator(this, function (_a) {
|
|
2260
2378
|
switch (_a.label) {
|
|
@@ -2265,7 +2383,7 @@
|
|
|
2265
2383
|
}
|
|
2266
2384
|
_a.label = 1;
|
|
2267
2385
|
case 1:
|
|
2268
|
-
_a.trys.push([1,
|
|
2386
|
+
_a.trys.push([1, 4, , 7]);
|
|
2269
2387
|
currentSize = this.queueSize;
|
|
2270
2388
|
threshold = this.options.bufferSize * 0.7;
|
|
2271
2389
|
if (!(currentSize > threshold)) return [3 /*break*/, 3];
|
|
@@ -2278,94 +2396,92 @@
|
|
|
2278
2396
|
if (this.abortController.signal.aborted) {
|
|
2279
2397
|
throw new Error('Stream aborted during backpressure monitoring');
|
|
2280
2398
|
}
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
}
|
|
2285
|
-
catch (err) {
|
|
2286
|
-
reject(err);
|
|
2287
|
-
}
|
|
2288
|
-
resolve();
|
|
2289
|
-
})];
|
|
2399
|
+
// push 是同步操作,直接调用即可
|
|
2400
|
+
this.p.push(chunk);
|
|
2401
|
+
return [3 /*break*/, 7];
|
|
2290
2402
|
case 4:
|
|
2291
|
-
_a.sent();
|
|
2292
|
-
return [3 /*break*/, 8];
|
|
2293
|
-
case 5:
|
|
2294
2403
|
err_3 = _a.sent();
|
|
2295
|
-
if (!(attempt < this.options.retries)) return [3 /*break*/,
|
|
2404
|
+
if (!(!this.abortController.signal.aborted && attempt < this.options.retries)) return [3 /*break*/, 6];
|
|
2296
2405
|
delay_1 = this.calculateRetryDelay(attempt);
|
|
2297
2406
|
return [4 /*yield*/, new Promise(function (r) { return setTimeout(r, delay_1); })];
|
|
2298
|
-
case
|
|
2407
|
+
case 5:
|
|
2299
2408
|
_a.sent();
|
|
2300
2409
|
return [2 /*return*/, this.retryableWrite(chunk, attempt + 1)];
|
|
2301
|
-
case
|
|
2302
|
-
case
|
|
2410
|
+
case 6: throw err_3;
|
|
2411
|
+
case 7: return [2 /*return*/];
|
|
2303
2412
|
}
|
|
2304
2413
|
});
|
|
2305
2414
|
});
|
|
2306
2415
|
};
|
|
2307
2416
|
StreamWriter.prototype.monitorBackpressure = function () {
|
|
2308
2417
|
return __awaiter(this, void 0, void 0, function () {
|
|
2309
|
-
var
|
|
2418
|
+
var baseThreshold, criticalThreshold, maxRounds, _loop_1, this_1, i, state_1, now;
|
|
2419
|
+
var _this = this;
|
|
2310
2420
|
return __generator(this, function (_a) {
|
|
2311
2421
|
switch (_a.label) {
|
|
2312
2422
|
case 0:
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
;
|
|
2318
|
-
// 快速路径:无背压时直接返回
|
|
2319
|
-
if (currentSize < baseThreshold) {
|
|
2423
|
+
baseThreshold = this.options.bufferSize * 0.7;
|
|
2424
|
+
criticalThreshold = this.options.bufferSize * 0.9;
|
|
2425
|
+
// 快速路径
|
|
2426
|
+
if (this.queueSize < baseThreshold) {
|
|
2320
2427
|
if (this.isBackpressure) {
|
|
2321
2428
|
this.isBackpressure = false;
|
|
2322
|
-
this.dispatchBackpressureEvent({
|
|
2323
|
-
currentSize: currentSize,
|
|
2324
|
-
averageSize: this.getAverageQueueSize(),
|
|
2325
|
-
threshold: baseThreshold,
|
|
2326
|
-
waitingTime: 0
|
|
2327
|
-
});
|
|
2429
|
+
this.dispatchBackpressureEvent({ currentSize: this.queueSize, averageSize: this.getAverageQueueSize(), threshold: baseThreshold, waitingTime: 0 });
|
|
2328
2430
|
}
|
|
2329
2431
|
return [2 /*return*/];
|
|
2330
2432
|
}
|
|
2331
|
-
// 进入背压状态
|
|
2332
2433
|
if (!this.isBackpressure) {
|
|
2333
2434
|
this.isBackpressure = true;
|
|
2334
|
-
this.dispatchBackpressureEvent({
|
|
2335
|
-
currentSize: currentSize,
|
|
2336
|
-
averageSize: this.getAverageQueueSize(),
|
|
2337
|
-
threshold: baseThreshold,
|
|
2338
|
-
waitingTime: 0
|
|
2339
|
-
});
|
|
2435
|
+
this.dispatchBackpressureEvent({ currentSize: this.queueSize, averageSize: this.getAverageQueueSize(), threshold: baseThreshold, waitingTime: 0 });
|
|
2340
2436
|
}
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2437
|
+
maxRounds = 3;
|
|
2438
|
+
_loop_1 = function (i) {
|
|
2439
|
+
var isCritical, waitMs;
|
|
2440
|
+
return __generator(this, function (_b) {
|
|
2441
|
+
switch (_b.label) {
|
|
2442
|
+
case 0:
|
|
2443
|
+
if (this_1.abortController.signal.aborted)
|
|
2444
|
+
return [2 /*return*/, "break"];
|
|
2445
|
+
if (this_1.queueSize < baseThreshold)
|
|
2446
|
+
return [2 /*return*/, "break"];
|
|
2447
|
+
isCritical = this_1.queueSize >= criticalThreshold;
|
|
2448
|
+
waitMs = isCritical ? 100 : 30;
|
|
2449
|
+
return [4 /*yield*/, new Promise(function (resolve) {
|
|
2450
|
+
var done = false;
|
|
2451
|
+
var timer = setTimeout(function () { if (!done) {
|
|
2452
|
+
done = true;
|
|
2453
|
+
resolve();
|
|
2454
|
+
} }, waitMs);
|
|
2455
|
+
_this.drainWaiters.push(function () { if (!done) {
|
|
2456
|
+
done = true;
|
|
2457
|
+
clearTimeout(timer);
|
|
2458
|
+
resolve();
|
|
2459
|
+
} });
|
|
2460
|
+
})];
|
|
2461
|
+
case 1:
|
|
2462
|
+
_b.sent();
|
|
2463
|
+
return [2 /*return*/];
|
|
2464
|
+
}
|
|
2465
|
+
});
|
|
2466
|
+
};
|
|
2467
|
+
this_1 = this;
|
|
2468
|
+
i = 0;
|
|
2352
2469
|
_a.label = 1;
|
|
2353
2470
|
case 1:
|
|
2354
|
-
if (!(
|
|
2355
|
-
|
|
2356
|
-
return [3 /*break*/, 3];
|
|
2357
|
-
return [4 /*yield*/, new Promise(function (r) { return setTimeout(r, waitTime); })];
|
|
2471
|
+
if (!(i < maxRounds)) return [3 /*break*/, 4];
|
|
2472
|
+
return [5 /*yield**/, _loop_1(i)];
|
|
2358
2473
|
case 2:
|
|
2359
|
-
_a.sent();
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
return [3 /*break*/, 1];
|
|
2474
|
+
state_1 = _a.sent();
|
|
2475
|
+
if (state_1 === "break")
|
|
2476
|
+
return [3 /*break*/, 4];
|
|
2477
|
+
_a.label = 3;
|
|
2364
2478
|
case 3:
|
|
2365
|
-
|
|
2479
|
+
i++;
|
|
2480
|
+
return [3 /*break*/, 1];
|
|
2481
|
+
case 4:
|
|
2366
2482
|
if (this.queueSize >= baseThreshold) {
|
|
2367
2483
|
now = Date.now();
|
|
2368
|
-
if (now - this.lastBpWarnAt > 1000) {
|
|
2484
|
+
if (now - this.lastBpWarnAt > 1000) {
|
|
2369
2485
|
this.lastBpWarnAt = now;
|
|
2370
2486
|
console.warn("Stream writer: High backpressure detected (".concat(this.queueSize, " bytes), continuing anyway"));
|
|
2371
2487
|
}
|
|
@@ -2493,19 +2609,31 @@
|
|
|
2493
2609
|
if (!this.abortController.signal.aborted) {
|
|
2494
2610
|
this.abortController.abort();
|
|
2495
2611
|
}
|
|
2496
|
-
//
|
|
2612
|
+
// 执行所有待处理的写入任务:它们会检查 signal.aborted 并立即 resolve,
|
|
2613
|
+
// 不执行的话调用方的 Promise 会永远挂住
|
|
2497
2614
|
var pendingTasks = this.writeQueue.splice(0);
|
|
2498
|
-
pendingTasks.
|
|
2499
|
-
|
|
2500
|
-
|
|
2615
|
+
for (var _i = 0, pendingTasks_1 = pendingTasks; _i < pendingTasks_1.length; _i++) {
|
|
2616
|
+
var task = pendingTasks_1[_i];
|
|
2617
|
+
task().catch(function () { });
|
|
2618
|
+
}
|
|
2619
|
+
// 唤醒所有 drainWaiters(flush / monitorBackpressure 中的等待者),
|
|
2620
|
+
// 让它们检查 signal.aborted 并立即 resolve,不必等到各自的超时
|
|
2621
|
+
var ws = this.drainWaiters.splice(0);
|
|
2622
|
+
for (var _a = 0, ws_2 = ws; _a < ws_2.length; _a++) {
|
|
2623
|
+
var fn = ws_2[_a];
|
|
2624
|
+
try {
|
|
2625
|
+
fn();
|
|
2626
|
+
}
|
|
2627
|
+
catch ( /* ignore */_b) { /* ignore */ }
|
|
2628
|
+
}
|
|
2501
2629
|
try {
|
|
2502
2630
|
this.p.end();
|
|
2503
2631
|
}
|
|
2504
|
-
catch (
|
|
2632
|
+
catch (_c) {
|
|
2505
2633
|
// Ignore errors when ending pushable
|
|
2506
2634
|
}
|
|
2507
2635
|
if (this.watchdogTimer) {
|
|
2508
|
-
|
|
2636
|
+
clearTimeout(this.watchdogTimer);
|
|
2509
2637
|
this.watchdogTimer = undefined;
|
|
2510
2638
|
}
|
|
2511
2639
|
};
|
|
@@ -2513,30 +2641,49 @@
|
|
|
2513
2641
|
// 默认超时 10s,避免无限等待
|
|
2514
2642
|
StreamWriter.prototype.flush = function () {
|
|
2515
2643
|
return __awaiter(this, arguments, void 0, function (timeoutMs) {
|
|
2516
|
-
var
|
|
2644
|
+
var _this = this;
|
|
2517
2645
|
if (timeoutMs === void 0) { timeoutMs = 10000; }
|
|
2518
2646
|
return __generator(this, function (_a) {
|
|
2519
2647
|
switch (_a.label) {
|
|
2520
2648
|
case 0:
|
|
2521
|
-
start = Date.now();
|
|
2522
2649
|
// 快速路径
|
|
2523
2650
|
if (this.queueSize <= 0 && !this.isProcessingQueue && this.writeQueue.length === 0)
|
|
2524
2651
|
return [2 /*return*/];
|
|
2525
|
-
_a.label = 1;
|
|
2526
|
-
case 1:
|
|
2527
2652
|
if (this.abortController.signal.aborted)
|
|
2528
2653
|
return [2 /*return*/];
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2654
|
+
return [4 /*yield*/, new Promise(function (resolve) {
|
|
2655
|
+
// 已经清空
|
|
2656
|
+
if (_this.queueSize <= 0 && !_this.isProcessingQueue && _this.writeQueue.length === 0) {
|
|
2657
|
+
resolve();
|
|
2658
|
+
return;
|
|
2659
|
+
}
|
|
2660
|
+
var done = false;
|
|
2661
|
+
var timer = setTimeout(function () {
|
|
2662
|
+
if (!done) {
|
|
2663
|
+
done = true;
|
|
2664
|
+
console.warn("Stream writer: flush timeout with ".concat(_this.queueSize, " bytes still queued"));
|
|
2665
|
+
resolve();
|
|
2666
|
+
}
|
|
2667
|
+
}, timeoutMs);
|
|
2668
|
+
// 由 createTransform 在每个 chunk 被下游消耗后唤醒
|
|
2669
|
+
var check = function () {
|
|
2670
|
+
if (_this.abortController.signal.aborted || (_this.queueSize <= 0 && !_this.isProcessingQueue && _this.writeQueue.length === 0)) {
|
|
2671
|
+
if (!done) {
|
|
2672
|
+
done = true;
|
|
2673
|
+
clearTimeout(timer);
|
|
2674
|
+
resolve();
|
|
2675
|
+
}
|
|
2676
|
+
}
|
|
2677
|
+
else {
|
|
2678
|
+
// 下次 drain 时再检查
|
|
2679
|
+
_this.drainWaiters.push(check);
|
|
2680
|
+
}
|
|
2681
|
+
};
|
|
2682
|
+
_this.drainWaiters.push(check);
|
|
2683
|
+
})];
|
|
2684
|
+
case 1:
|
|
2537
2685
|
_a.sent();
|
|
2538
|
-
return [
|
|
2539
|
-
case 3: return [2 /*return*/];
|
|
2686
|
+
return [2 /*return*/];
|
|
2540
2687
|
}
|
|
2541
2688
|
});
|
|
2542
2689
|
});
|
|
@@ -2845,45 +2992,65 @@
|
|
|
2845
2992
|
Libp2pGrpcClient.prototype.setToken = function (token) {
|
|
2846
2993
|
this.token = token;
|
|
2847
2994
|
};
|
|
2995
|
+
/** 从 peerAddr 提取 HTTP/2 :authority 字段(host:port 格式) */
|
|
2996
|
+
Libp2pGrpcClient.prototype.getAuthority = function () {
|
|
2997
|
+
try {
|
|
2998
|
+
var addr = this.peerAddr.toString();
|
|
2999
|
+
var ip4 = addr.match(/\/ip4\/(\d[\d.]+)\/tcp\/(\d+)/);
|
|
3000
|
+
if (ip4)
|
|
3001
|
+
return "".concat(ip4[1], ":").concat(ip4[2]);
|
|
3002
|
+
var ip6 = addr.match(/\/ip6\/([^/]+)\/tcp\/(\d+)/);
|
|
3003
|
+
if (ip6)
|
|
3004
|
+
return "[".concat(ip6[1], "]:").concat(ip6[2]);
|
|
3005
|
+
var dns = addr.match(/\/dns(?:4|6)?\/([.\w-]+)\/tcp\/(\d+)/);
|
|
3006
|
+
if (dns)
|
|
3007
|
+
return "".concat(dns[1], ":").concat(dns[2]);
|
|
3008
|
+
}
|
|
3009
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
3010
|
+
return 'localhost';
|
|
3011
|
+
};
|
|
2848
3012
|
Libp2pGrpcClient.prototype.unaryCall = function (method_1, requestData_1) {
|
|
2849
3013
|
return __awaiter(this, arguments, void 0, function (method, requestData, timeout) {
|
|
2850
|
-
var stream, responseData, responseBuffer, responseDataExpectedLength, hpack, exitFlag, errMsg, isResponseComplete, connection, state, streamSlotAcquired, connectionKey_1, err_2, streamManager, streamId_1, writer_1, parser, preface, settingFrme, headerFrame, dataFrames, frameSendTimeout, _i, dataFrames_1, df, err_3;
|
|
3014
|
+
var stream, responseData, responseBuffer, responseDataExpectedLength, headerPartialBuffer, hpack, exitFlag, errMsg, isResponseComplete, notifyResponseComplete, connection, state, streamSlotAcquired, writerRef, connectionKey_1, err_2, streamManager, streamId_1, writer_1, parser, preface, settingFrme, headerFrame, dataFrames, frameSendTimeout, _i, dataFrames_1, df, err_3;
|
|
2851
3015
|
var _this = this;
|
|
2852
3016
|
if (timeout === void 0) { timeout = 30000; }
|
|
2853
|
-
return __generator(this, function (
|
|
2854
|
-
switch (
|
|
3017
|
+
return __generator(this, function (_c) {
|
|
3018
|
+
switch (_c.label) {
|
|
2855
3019
|
case 0:
|
|
2856
3020
|
stream = null;
|
|
2857
3021
|
responseData = null;
|
|
2858
3022
|
responseBuffer = [];
|
|
2859
3023
|
responseDataExpectedLength = -1;
|
|
3024
|
+
headerPartialBuffer = [];
|
|
2860
3025
|
hpack = new HPACK();
|
|
2861
3026
|
exitFlag = false;
|
|
2862
3027
|
errMsg = "";
|
|
2863
3028
|
isResponseComplete = false;
|
|
3029
|
+
notifyResponseComplete = null;
|
|
2864
3030
|
connection = null;
|
|
2865
3031
|
state = null;
|
|
2866
3032
|
streamSlotAcquired = false;
|
|
2867
|
-
|
|
3033
|
+
writerRef = null;
|
|
3034
|
+
_c.label = 1;
|
|
2868
3035
|
case 1:
|
|
2869
|
-
|
|
3036
|
+
_c.trys.push([1, 23, 24, 29]);
|
|
2870
3037
|
return [4 /*yield*/, this.acquireConnection(false)];
|
|
2871
3038
|
case 2:
|
|
2872
3039
|
// const stream = await this.node.dialProtocol(this.peerAddr, this.protocol)
|
|
2873
|
-
connection =
|
|
3040
|
+
connection = _c.sent();
|
|
2874
3041
|
connectionKey_1 = this.peerAddr.toString();
|
|
2875
3042
|
state = this.getConnectionState(connection);
|
|
2876
|
-
|
|
3043
|
+
_c.label = 3;
|
|
2877
3044
|
case 3:
|
|
2878
|
-
|
|
3045
|
+
_c.trys.push([3, 5, , 6]);
|
|
2879
3046
|
return [4 /*yield*/, this.waitForStreamSlot(state, undefined, timeout)];
|
|
2880
3047
|
case 4:
|
|
2881
|
-
|
|
3048
|
+
_c.sent();
|
|
2882
3049
|
state.activeStreams += 1;
|
|
2883
3050
|
streamSlotAcquired = true;
|
|
2884
3051
|
return [3 /*break*/, 6];
|
|
2885
3052
|
case 5:
|
|
2886
|
-
err_2 =
|
|
3053
|
+
err_2 = _c.sent();
|
|
2887
3054
|
console.warn("[unaryCall] waiting for stream slot failed:", err_2);
|
|
2888
3055
|
throw err_2;
|
|
2889
3056
|
case 6: return [4 /*yield*/, connection.newStream(this.protocol, {
|
|
@@ -2891,14 +3058,15 @@
|
|
|
2891
3058
|
negotiateFully: false,
|
|
2892
3059
|
})];
|
|
2893
3060
|
case 7:
|
|
2894
|
-
stream =
|
|
3061
|
+
stream = _c.sent();
|
|
2895
3062
|
streamManager = this.getStreamManagerFor(connection);
|
|
2896
3063
|
return [4 /*yield*/, streamManager.getNextAppLevelStreamId()];
|
|
2897
3064
|
case 8:
|
|
2898
|
-
streamId_1 =
|
|
3065
|
+
streamId_1 = _c.sent();
|
|
2899
3066
|
writer_1 = new StreamWriter(stream, {
|
|
2900
3067
|
bufferSize: 16 * 1024 * 1024,
|
|
2901
3068
|
});
|
|
3069
|
+
writerRef = writer_1;
|
|
2902
3070
|
try {
|
|
2903
3071
|
writer_1.addEventListener("backpressure", function (e) {
|
|
2904
3072
|
var d = e.detail || {};
|
|
@@ -2920,7 +3088,7 @@
|
|
|
2920
3088
|
catch ( /* ignore ping write errors */_b) { /* ignore ping write errors */ }
|
|
2921
3089
|
});
|
|
2922
3090
|
}
|
|
2923
|
-
catch ( /* ignore addEventListener errors */
|
|
3091
|
+
catch ( /* ignore addEventListener errors */_d) { /* ignore addEventListener errors */ }
|
|
2924
3092
|
parser = new HTTP2Parser(writer_1);
|
|
2925
3093
|
parser.onGoaway = function (info) {
|
|
2926
3094
|
console.warn("[unaryCall] GOAWAY received from server", info);
|
|
@@ -2930,6 +3098,7 @@
|
|
|
2930
3098
|
}
|
|
2931
3099
|
exitFlag = true;
|
|
2932
3100
|
errMsg = "GOAWAY received: code=".concat(info.errorCode);
|
|
3101
|
+
notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete(); // 唤醒等待中的 Promise
|
|
2933
3102
|
try {
|
|
2934
3103
|
connection === null || connection === void 0 ? void 0 : connection.close();
|
|
2935
3104
|
}
|
|
@@ -2948,86 +3117,99 @@
|
|
|
2948
3117
|
parser.registerOutboundStream(streamId_1);
|
|
2949
3118
|
responseDataExpectedLength = -1; // 重置期望长度
|
|
2950
3119
|
responseBuffer = []; // 重置缓冲区
|
|
3120
|
+
headerPartialBuffer = []; // 重置跨帧头部缓冲
|
|
2951
3121
|
parser.onData = function (payload, frameHeader) {
|
|
2952
3122
|
//接收数据
|
|
2953
3123
|
if (responseDataExpectedLength === -1) {
|
|
2954
3124
|
//grpc消息头部未读取
|
|
3125
|
+
// 如果有跨帧积累的部分头字节,先与本帧 payload 合并
|
|
3126
|
+
var effectivePayload = payload;
|
|
3127
|
+
if (headerPartialBuffer.length > 0) {
|
|
3128
|
+
headerPartialBuffer.push(payload);
|
|
3129
|
+
var totalLen = headerPartialBuffer.reduce(function (s, c) { return s + c.length; }, 0);
|
|
3130
|
+
effectivePayload = new Uint8Array(totalLen);
|
|
3131
|
+
var off = 0;
|
|
3132
|
+
for (var _i = 0, headerPartialBuffer_1 = headerPartialBuffer; _i < headerPartialBuffer_1.length; _i++) {
|
|
3133
|
+
var c = headerPartialBuffer_1[_i];
|
|
3134
|
+
effectivePayload.set(c, off);
|
|
3135
|
+
off += c.length;
|
|
3136
|
+
}
|
|
3137
|
+
headerPartialBuffer = [];
|
|
3138
|
+
}
|
|
2955
3139
|
//提取gRPC消息头部
|
|
2956
|
-
if (
|
|
3140
|
+
if (effectivePayload.length < 5) {
|
|
3141
|
+
// 头部字节不足 5,先缓存,等待后续帧补全
|
|
3142
|
+
headerPartialBuffer.push(effectivePayload);
|
|
2957
3143
|
return;
|
|
2958
3144
|
}
|
|
2959
|
-
var lengthBytes =
|
|
2960
|
-
responseDataExpectedLength = new DataView(lengthBytes.buffer, lengthBytes.byteOffset).getUint32(0, false); // big-endian
|
|
2961
|
-
if (responseDataExpectedLength
|
|
2962
|
-
throw new Error("Invalid gRPC message length");
|
|
2963
|
-
}
|
|
2964
|
-
if (responseDataExpectedLength + 5 > payload.length) {
|
|
3145
|
+
var lengthBytes = effectivePayload.slice(1, 5); // 消息长度的4字节
|
|
3146
|
+
responseDataExpectedLength = new DataView(lengthBytes.buffer, lengthBytes.byteOffset).getUint32(0, false); // big-endian(getUint32 返回无符号整数,结果不会为负)
|
|
3147
|
+
if (responseDataExpectedLength + 5 > effectivePayload.length) {
|
|
2965
3148
|
// 如果当前 payload 不足以包含完整的 gRPC 消息,缓存数据
|
|
2966
|
-
var grpcData =
|
|
3149
|
+
var grpcData = effectivePayload.subarray(5);
|
|
2967
3150
|
responseBuffer.push(grpcData);
|
|
2968
3151
|
responseDataExpectedLength -= grpcData.length; // 更新期望长度
|
|
2969
3152
|
return;
|
|
2970
3153
|
}
|
|
2971
3154
|
else {
|
|
2972
|
-
//
|
|
2973
|
-
var
|
|
3155
|
+
// payload 已包含完整的 gRPC 消息体,精确截取(避免尾部多余字节污染)
|
|
3156
|
+
var msgLen = responseDataExpectedLength;
|
|
3157
|
+
var grpcData = effectivePayload.slice(5, 5 + msgLen);
|
|
2974
3158
|
responseBuffer.push(grpcData);
|
|
2975
3159
|
responseData = grpcData;
|
|
2976
3160
|
isResponseComplete = true;
|
|
2977
|
-
responseDataExpectedLength = -1;
|
|
3161
|
+
responseDataExpectedLength = -1;
|
|
3162
|
+
notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete();
|
|
2978
3163
|
}
|
|
2979
3164
|
}
|
|
2980
3165
|
else if (responseDataExpectedLength > 0) {
|
|
2981
3166
|
//grpc消息头部已读取
|
|
2982
|
-
|
|
2983
|
-
responseDataExpectedLength -= payload.length; // 更新期望长度
|
|
3167
|
+
responseDataExpectedLength -= payload.length;
|
|
2984
3168
|
if (responseDataExpectedLength <= 0) {
|
|
2985
|
-
//
|
|
3169
|
+
// 超收时截掉多余字节
|
|
3170
|
+
var exactPayload = responseDataExpectedLength < 0
|
|
3171
|
+
? payload.slice(0, payload.length + responseDataExpectedLength)
|
|
3172
|
+
: payload;
|
|
3173
|
+
responseBuffer.push(exactPayload);
|
|
2986
3174
|
responseData = new Uint8Array(responseBuffer.reduce(function (sum, chunk) { return sum + chunk.length; }, 0));
|
|
2987
3175
|
var offset = 0;
|
|
2988
|
-
for (var
|
|
2989
|
-
var chunk = responseBuffer_1[
|
|
3176
|
+
for (var _a = 0, responseBuffer_1 = responseBuffer; _a < responseBuffer_1.length; _a++) {
|
|
3177
|
+
var chunk = responseBuffer_1[_a];
|
|
2990
3178
|
responseData.set(chunk, offset);
|
|
2991
3179
|
offset += chunk.length;
|
|
2992
3180
|
}
|
|
2993
3181
|
responseDataExpectedLength = -1;
|
|
2994
|
-
isResponseComplete = true;
|
|
3182
|
+
isResponseComplete = true;
|
|
3183
|
+
notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete();
|
|
2995
3184
|
}
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
if (frameHeader && frameHeader.flags & 0x1 && !isResponseComplete) {
|
|
2999
|
-
// END_STREAM flag
|
|
3000
|
-
// 合并所有缓冲的数据
|
|
3001
|
-
var totalLength = responseBuffer.reduce(function (sum, chunk) { return sum + chunk.length; }, 0);
|
|
3002
|
-
responseData = new Uint8Array(totalLength);
|
|
3003
|
-
var offset = 0;
|
|
3004
|
-
for (var _a = 0, responseBuffer_2 = responseBuffer; _a < responseBuffer_2.length; _a++) {
|
|
3005
|
-
var chunk = responseBuffer_2[_a];
|
|
3006
|
-
responseData.set(chunk, offset);
|
|
3007
|
-
offset += chunk.length;
|
|
3185
|
+
else {
|
|
3186
|
+
responseBuffer.push(payload); // 还不完整,继续累积
|
|
3008
3187
|
}
|
|
3009
|
-
isResponseComplete = true;
|
|
3010
3188
|
}
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
isResponseComplete = true; // 设置响应完成标志
|
|
3016
|
-
if (responseBuffer.length === 0) {
|
|
3017
|
-
responseData = new Uint8Array(); // 如果没有数据,返回空数组
|
|
3018
|
-
}
|
|
3019
|
-
else {
|
|
3020
|
-
// 合并所有缓冲的数据
|
|
3021
|
-
var totalLength = responseBuffer.reduce(function (sum, chunk) { return sum + chunk.length; }, 0);
|
|
3189
|
+
// END_STREAM 兜底:数据路径已处理大多数情况;此分支仅在边缘情况下触发
|
|
3190
|
+
if (frameHeader && frameHeader.flags & 0x1 && !isResponseComplete) {
|
|
3191
|
+
if (responseBuffer.length > 0) {
|
|
3192
|
+
var totalLength = responseBuffer.reduce(function (sum, c) { return sum + c.length; }, 0);
|
|
3022
3193
|
responseData = new Uint8Array(totalLength);
|
|
3023
3194
|
var offset = 0;
|
|
3024
|
-
for (var
|
|
3025
|
-
var chunk =
|
|
3195
|
+
for (var _b = 0, responseBuffer_2 = responseBuffer; _b < responseBuffer_2.length; _b++) {
|
|
3196
|
+
var chunk = responseBuffer_2[_b];
|
|
3026
3197
|
responseData.set(chunk, offset);
|
|
3027
3198
|
offset += chunk.length;
|
|
3028
3199
|
}
|
|
3029
|
-
isResponseComplete = true;
|
|
3030
3200
|
}
|
|
3201
|
+
else {
|
|
3202
|
+
responseData = new Uint8Array(0);
|
|
3203
|
+
}
|
|
3204
|
+
isResponseComplete = true;
|
|
3205
|
+
notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete();
|
|
3206
|
+
}
|
|
3207
|
+
};
|
|
3208
|
+
parser.onEnd = function () {
|
|
3209
|
+
// 流结束时若响应未标记完成(空响应 / 纯 trailers),强制标记并唤醒等待者
|
|
3210
|
+
if (!isResponseComplete) {
|
|
3211
|
+
isResponseComplete = true;
|
|
3212
|
+
notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete();
|
|
3031
3213
|
}
|
|
3032
3214
|
};
|
|
3033
3215
|
parser.onSettings = function () {
|
|
@@ -3041,6 +3223,7 @@
|
|
|
3041
3223
|
else if (plainHeaders.get("grpc-status") !== undefined) {
|
|
3042
3224
|
exitFlag = true;
|
|
3043
3225
|
errMsg = plainHeaders.get("grpc-message") || "gRPC call failed";
|
|
3226
|
+
notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete(); // 唤醒等待中的 Promise
|
|
3044
3227
|
}
|
|
3045
3228
|
};
|
|
3046
3229
|
// 启动后台流处理,捕获任何异步错误
|
|
@@ -3050,94 +3233,109 @@
|
|
|
3050
3233
|
if (!errMsg) {
|
|
3051
3234
|
errMsg = error instanceof Error ? error.message : 'Stream processing failed';
|
|
3052
3235
|
}
|
|
3236
|
+
notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete(); // 流处理异常也需唤醒等待者
|
|
3053
3237
|
});
|
|
3054
3238
|
preface = Http2Frame.createPreface();
|
|
3055
3239
|
return [4 /*yield*/, writer_1.write(preface)];
|
|
3056
3240
|
case 9:
|
|
3057
|
-
|
|
3241
|
+
_c.sent();
|
|
3058
3242
|
settingFrme = Http2Frame.createSettingsFrame();
|
|
3059
3243
|
return [4 /*yield*/, writer_1.write(settingFrme)];
|
|
3060
3244
|
case 10:
|
|
3061
|
-
|
|
3245
|
+
_c.sent();
|
|
3062
3246
|
// 等待对端 SETTINGS 或 ACK,择一即可,避免偶发握手竞态
|
|
3247
|
+
// 注意:未胜出的 promise 内部有超时定时器,它们最终会 reject。
|
|
3248
|
+
// 必须绑定 .catch(…) 消除错误,否则在 Node.js 新版本中会导致 UnhandledPromiseRejection 崩溃。
|
|
3063
3249
|
return [4 /*yield*/, Promise.race([
|
|
3064
|
-
parser.waitForPeerSettings(1000),
|
|
3065
|
-
parser.waitForSettingsAck(),
|
|
3250
|
+
parser.waitForPeerSettings(1000).catch(function () { }),
|
|
3251
|
+
parser.waitForSettingsAck().catch(function () { }),
|
|
3066
3252
|
new Promise(function (res) { return setTimeout(res, 300); }),
|
|
3067
3253
|
])];
|
|
3068
3254
|
case 11:
|
|
3069
3255
|
// 等待对端 SETTINGS 或 ACK,择一即可,避免偶发握手竞态
|
|
3070
|
-
|
|
3071
|
-
|
|
3256
|
+
// 注意:未胜出的 promise 内部有超时定时器,它们最终会 reject。
|
|
3257
|
+
// 必须绑定 .catch(…) 消除错误,否则在 Node.js 新版本中会导致 UnhandledPromiseRejection 崩溃。
|
|
3258
|
+
_c.sent();
|
|
3259
|
+
headerFrame = Http2Frame.createHeadersFrame(streamId_1, method, true, this.token, this.getAuthority());
|
|
3072
3260
|
return [4 /*yield*/, writer_1.write(headerFrame)];
|
|
3073
3261
|
case 12:
|
|
3074
|
-
|
|
3262
|
+
_c.sent();
|
|
3075
3263
|
dataFrames = Http2Frame.createDataFrames(streamId_1, requestData, true);
|
|
3076
3264
|
frameSendTimeout = timeout > 0 ? timeout : DEFAULT_SEND_WINDOW_TIMEOUT;
|
|
3077
3265
|
_i = 0, dataFrames_1 = dataFrames;
|
|
3078
|
-
|
|
3266
|
+
_c.label = 13;
|
|
3079
3267
|
case 13:
|
|
3080
3268
|
if (!(_i < dataFrames_1.length)) return [3 /*break*/, 16];
|
|
3081
3269
|
df = dataFrames_1[_i];
|
|
3082
3270
|
return [4 /*yield*/, this.sendFrameWithFlowControl(parser, streamId_1, df, writer_1, undefined, frameSendTimeout)];
|
|
3083
3271
|
case 14:
|
|
3084
|
-
|
|
3085
|
-
|
|
3272
|
+
_c.sent();
|
|
3273
|
+
_c.label = 15;
|
|
3086
3274
|
case 15:
|
|
3087
3275
|
_i++;
|
|
3088
3276
|
return [3 /*break*/, 13];
|
|
3089
3277
|
case 16:
|
|
3090
|
-
// 等待responseData
|
|
3278
|
+
// 等待 responseData 不为空,或超时(事件驱动,不轮询)
|
|
3091
3279
|
return [4 /*yield*/, new Promise(function (resolve, reject) {
|
|
3280
|
+
if (isResponseComplete || exitFlag) {
|
|
3281
|
+
resolve();
|
|
3282
|
+
return;
|
|
3283
|
+
}
|
|
3092
3284
|
var t = setTimeout(function () {
|
|
3285
|
+
notifyResponseComplete = null;
|
|
3093
3286
|
reject(new Error("gRPC response timeout"));
|
|
3094
3287
|
}, timeout);
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
resolve(responseData);
|
|
3100
|
-
}
|
|
3101
|
-
else {
|
|
3102
|
-
setTimeout(checkResponse, 50);
|
|
3103
|
-
}
|
|
3288
|
+
notifyResponseComplete = function () {
|
|
3289
|
+
clearTimeout(t);
|
|
3290
|
+
notifyResponseComplete = null;
|
|
3291
|
+
resolve();
|
|
3104
3292
|
};
|
|
3105
|
-
checkResponse();
|
|
3106
3293
|
})];
|
|
3107
3294
|
case 17:
|
|
3108
|
-
// 等待responseData
|
|
3109
|
-
|
|
3110
|
-
|
|
3295
|
+
// 等待 responseData 不为空,或超时(事件驱动,不轮询)
|
|
3296
|
+
_c.sent();
|
|
3297
|
+
_c.label = 18;
|
|
3111
3298
|
case 18:
|
|
3112
|
-
|
|
3299
|
+
_c.trys.push([18, 20, , 21]);
|
|
3113
3300
|
return [4 /*yield*/, writer_1.flush(timeout)];
|
|
3114
3301
|
case 19:
|
|
3115
|
-
|
|
3302
|
+
_c.sent();
|
|
3116
3303
|
return [3 /*break*/, 21];
|
|
3117
3304
|
case 20:
|
|
3118
|
-
|
|
3305
|
+
_c.sent();
|
|
3119
3306
|
return [3 /*break*/, 21];
|
|
3120
3307
|
case 21: return [4 /*yield*/, writer_1.end()];
|
|
3121
3308
|
case 22:
|
|
3122
|
-
|
|
3123
|
-
return [3 /*break*/,
|
|
3309
|
+
_c.sent();
|
|
3310
|
+
return [3 /*break*/, 29];
|
|
3124
3311
|
case 23:
|
|
3125
|
-
err_3 =
|
|
3312
|
+
err_3 = _c.sent();
|
|
3126
3313
|
console.error("unaryCall error:", err_3);
|
|
3127
3314
|
throw err_3;
|
|
3128
3315
|
case 24:
|
|
3129
|
-
|
|
3130
|
-
|
|
3316
|
+
// 必须先 abort writer(立即强制停止 pushable + stream),再 close stream。
|
|
3317
|
+
// 若顺序颠倒:stream.close() 会等待服务端半关闭确认,网络异常时永久挂住,
|
|
3318
|
+
// 导致 writer.abort() 永远不执行 → watchdog 定时器 / pushable 泄漏。
|
|
3319
|
+
// writer.abort() 内部幂等,成功路径下 writer.end() 已调用 cleanup(),安全。
|
|
3320
|
+
writerRef === null || writerRef === void 0 ? void 0 : writerRef.abort('unaryCall cleanup');
|
|
3321
|
+
if (!stream) return [3 /*break*/, 28];
|
|
3322
|
+
_c.label = 25;
|
|
3131
3323
|
case 25:
|
|
3132
|
-
|
|
3133
|
-
|
|
3324
|
+
_c.trys.push([25, 27, , 28]);
|
|
3325
|
+
return [4 /*yield*/, stream.close()];
|
|
3134
3326
|
case 26:
|
|
3327
|
+
_c.sent();
|
|
3328
|
+
return [3 /*break*/, 28];
|
|
3329
|
+
case 27:
|
|
3330
|
+
_c.sent();
|
|
3331
|
+
return [3 /*break*/, 28];
|
|
3332
|
+
case 28:
|
|
3135
3333
|
if (streamSlotAcquired && state) {
|
|
3136
3334
|
state.activeStreams = Math.max(0, state.activeStreams - 1);
|
|
3137
3335
|
this.notifyStreamSlotAvailable(state);
|
|
3138
3336
|
}
|
|
3139
3337
|
return [7 /*endfinally*/];
|
|
3140
|
-
case
|
|
3338
|
+
case 29:
|
|
3141
3339
|
if (exitFlag) {
|
|
3142
3340
|
throw new Error(errMsg);
|
|
3143
3341
|
}
|
|
@@ -3166,7 +3364,7 @@
|
|
|
3166
3364
|
*/
|
|
3167
3365
|
Libp2pGrpcClient.prototype.Call = function (method_1, requestData_1) {
|
|
3168
3366
|
return __awaiter(this, arguments, void 0, function (method, requestData, timeout, mode, onDataCallback, dataSourceCallback, onEndCallback, onErrorCallback, context, options) {
|
|
3169
|
-
var internalController, timeoutHandle, stream, profile, useFlowControl, cancelOperation, timeoutPromise, operationPromise, error_1;
|
|
3367
|
+
var internalController, timeoutHandle, stream, contextAbortHandler, profile, useFlowControl, cancelOperation, timeoutPromise, operationPromise, error_1;
|
|
3170
3368
|
var _this = this;
|
|
3171
3369
|
var _a;
|
|
3172
3370
|
if (timeout === void 0) { timeout = 30000; }
|
|
@@ -3193,17 +3391,16 @@
|
|
|
3193
3391
|
};
|
|
3194
3392
|
// 如果提供了外部信号,监听它
|
|
3195
3393
|
if (context === null || context === void 0 ? void 0 : context.signal) {
|
|
3196
|
-
//
|
|
3394
|
+
// 如果外部信号已经触发中止,立即返回——避免启动 IIFE 后在 catch 中再次调用 onErrorCallback
|
|
3197
3395
|
if (context.signal.aborted) {
|
|
3198
3396
|
if (onErrorCallback) {
|
|
3199
3397
|
onErrorCallback(new Error("Operation aborted by context"));
|
|
3200
3398
|
}
|
|
3201
|
-
cancelOperation
|
|
3399
|
+
return [2 /*return*/, cancelOperation];
|
|
3202
3400
|
}
|
|
3203
|
-
// 监听外部的abort
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
});
|
|
3401
|
+
// 监听外部的abort事件(保存引用以便后续移除,防止内存泄漏)
|
|
3402
|
+
contextAbortHandler = function () { cancelOperation(); };
|
|
3403
|
+
context.signal.addEventListener("abort", contextAbortHandler);
|
|
3207
3404
|
}
|
|
3208
3405
|
timeoutPromise = new Promise(function (_, reject) {
|
|
3209
3406
|
timeoutHandle = setTimeout(function () {
|
|
@@ -3212,58 +3409,83 @@
|
|
|
3212
3409
|
}, timeout);
|
|
3213
3410
|
});
|
|
3214
3411
|
operationPromise = (function () { return __awaiter(_this, void 0, void 0, function () {
|
|
3215
|
-
var
|
|
3412
|
+
var errorCallbackFired, reportError, msgChunks, msgTotalLen, expectedMessageLength, flattenMsgBuffer, hpack, connection, connectionKey, state, streamSlotAcquired, writer, err_4, err_5, streamManager, streamId_2, parser_1, sendWindowTimeout_1, writeFrame_1, writeDataFrames_1, preface, settingFrame, headerFrame, dfs, dfs0, batchSize_1, processingQueue_1, batchDoneWaiters_1, isProcessing_1, _notifyBatchDone_1, processNextBatch_1, addToQueue_1, _a, _b, _c, chunkOrChunks, chunksToProcess, addPromises, e_1_1, error_2, remainingQueue, finalFrame, err_6, conns, _i, conns_1, c;
|
|
3216
3413
|
var _this = this;
|
|
3217
|
-
var
|
|
3218
|
-
var
|
|
3219
|
-
return __generator(this, function (
|
|
3220
|
-
switch (
|
|
3414
|
+
var _h, e_1, _j, _k;
|
|
3415
|
+
var _l, _m, _o;
|
|
3416
|
+
return __generator(this, function (_p) {
|
|
3417
|
+
switch (_p.label) {
|
|
3221
3418
|
case 0:
|
|
3222
|
-
|
|
3419
|
+
errorCallbackFired = false;
|
|
3420
|
+
reportError = function (err) {
|
|
3421
|
+
if (errorCallbackFired)
|
|
3422
|
+
return;
|
|
3423
|
+
errorCallbackFired = true;
|
|
3424
|
+
internalController.abort();
|
|
3425
|
+
if (onErrorCallback)
|
|
3426
|
+
onErrorCallback(err);
|
|
3427
|
+
};
|
|
3428
|
+
msgChunks = [];
|
|
3429
|
+
msgTotalLen = 0;
|
|
3223
3430
|
expectedMessageLength = -1;
|
|
3431
|
+
flattenMsgBuffer = function () {
|
|
3432
|
+
if (msgChunks.length === 0)
|
|
3433
|
+
return new Uint8Array(0);
|
|
3434
|
+
if (msgChunks.length === 1)
|
|
3435
|
+
return msgChunks[0];
|
|
3436
|
+
var out = new Uint8Array(msgTotalLen);
|
|
3437
|
+
var off = 0;
|
|
3438
|
+
for (var _i = 0, msgChunks_1 = msgChunks; _i < msgChunks_1.length; _i++) {
|
|
3439
|
+
var c = msgChunks_1[_i];
|
|
3440
|
+
out.set(c, off);
|
|
3441
|
+
off += c.length;
|
|
3442
|
+
}
|
|
3443
|
+
return out;
|
|
3444
|
+
};
|
|
3224
3445
|
hpack = new HPACK();
|
|
3225
3446
|
connection = null;
|
|
3226
3447
|
connectionKey = null;
|
|
3227
3448
|
state = null;
|
|
3228
3449
|
streamSlotAcquired = false;
|
|
3229
|
-
|
|
3450
|
+
writer = null;
|
|
3451
|
+
_p.label = 1;
|
|
3230
3452
|
case 1:
|
|
3231
|
-
|
|
3453
|
+
_p.trys.push([1, 49, 50, 64]);
|
|
3232
3454
|
// 检查是否已经中止
|
|
3233
3455
|
if (internalController.signal.aborted) {
|
|
3234
3456
|
throw new Error("Operation aborted");
|
|
3235
3457
|
}
|
|
3236
3458
|
if (!(options === null || options === void 0 ? void 0 : options.freshConnection)) return [3 /*break*/, 5];
|
|
3237
|
-
|
|
3459
|
+
_p.label = 2;
|
|
3238
3460
|
case 2:
|
|
3239
|
-
|
|
3461
|
+
_p.trys.push([2, 4, , 5]);
|
|
3240
3462
|
this.connectionPool.delete(this.peerAddr.toString());
|
|
3241
3463
|
return [4 /*yield*/, this.node.hangUp(this.peerAddr)];
|
|
3242
3464
|
case 3:
|
|
3243
|
-
|
|
3465
|
+
_p.sent();
|
|
3244
3466
|
console.warn("[Call] hangUp existing connection before dialing due to freshConnection=true");
|
|
3245
3467
|
return [3 /*break*/, 5];
|
|
3246
3468
|
case 4:
|
|
3247
|
-
err_4 =
|
|
3469
|
+
err_4 = _p.sent();
|
|
3248
3470
|
console.warn("[Call] hangUp failed or not supported, proceeding to dial", err_4);
|
|
3249
3471
|
return [3 /*break*/, 5];
|
|
3250
3472
|
case 5: return [4 /*yield*/, this.acquireConnection(Boolean(options === null || options === void 0 ? void 0 : options.freshConnection))];
|
|
3251
3473
|
case 6:
|
|
3252
|
-
connection =
|
|
3474
|
+
connection = _p.sent();
|
|
3253
3475
|
connectionKey = this.peerAddr.toString();
|
|
3254
3476
|
state = this.getConnectionState(connection);
|
|
3255
3477
|
if (!state) return [3 /*break*/, 10];
|
|
3256
|
-
|
|
3478
|
+
_p.label = 7;
|
|
3257
3479
|
case 7:
|
|
3258
|
-
|
|
3480
|
+
_p.trys.push([7, 9, , 10]);
|
|
3259
3481
|
return [4 /*yield*/, this.waitForStreamSlot(state, internalController.signal, timeout)];
|
|
3260
3482
|
case 8:
|
|
3261
|
-
|
|
3483
|
+
_p.sent();
|
|
3262
3484
|
state.activeStreams += 1;
|
|
3263
3485
|
streamSlotAcquired = true;
|
|
3264
3486
|
return [3 /*break*/, 10];
|
|
3265
3487
|
case 9:
|
|
3266
|
-
err_5 =
|
|
3488
|
+
err_5 = _p.sent();
|
|
3267
3489
|
console.warn("[Call] waiting for stream slot failed:", err_5);
|
|
3268
3490
|
throw err_5;
|
|
3269
3491
|
case 10: return [4 /*yield*/, connection.newStream(this.protocol, {
|
|
@@ -3272,23 +3494,23 @@
|
|
|
3272
3494
|
negotiateFully: false,
|
|
3273
3495
|
})];
|
|
3274
3496
|
case 11:
|
|
3275
|
-
stream =
|
|
3497
|
+
stream = _p.sent();
|
|
3276
3498
|
streamManager = this.getStreamManagerFor(connection);
|
|
3277
3499
|
return [4 /*yield*/, streamManager.getNextAppLevelStreamId()];
|
|
3278
3500
|
case 12:
|
|
3279
|
-
streamId_2 =
|
|
3280
|
-
|
|
3501
|
+
streamId_2 = _p.sent();
|
|
3502
|
+
writer = new StreamWriter(stream, {
|
|
3281
3503
|
bufferSize: 16 * 1024 * 1024,
|
|
3282
3504
|
});
|
|
3283
3505
|
try {
|
|
3284
|
-
|
|
3506
|
+
writer.addEventListener("backpressure", function (e) {
|
|
3285
3507
|
var d = e.detail || {};
|
|
3286
3508
|
console.warn("[stream ".concat(streamId_2, "] backpressure current=").concat(d.currentSize, " avg=").concat(d.averageSize, " threshold=").concat(d.threshold));
|
|
3287
3509
|
});
|
|
3288
|
-
|
|
3510
|
+
writer.addEventListener("drain", function () {
|
|
3289
3511
|
// drain event - no action needed
|
|
3290
3512
|
});
|
|
3291
|
-
|
|
3513
|
+
writer.addEventListener("stalled", function (e) {
|
|
3292
3514
|
var _a;
|
|
3293
3515
|
var d = e.detail || {};
|
|
3294
3516
|
console.warn("[stream ".concat(streamId_2, "] stalled queue=").concat(d.queueSize, " drained=").concat(d.drained, " since=").concat(d.sinceMs, "ms \u2014 sending PING"));
|
|
@@ -3296,13 +3518,13 @@
|
|
|
3296
3518
|
var payload = new Uint8Array(8);
|
|
3297
3519
|
(_a = crypto.getRandomValues) === null || _a === void 0 ? void 0 : _a.call(crypto, payload);
|
|
3298
3520
|
var ping = Http2Frame.createFrame(0x6, 0x0, 0, payload);
|
|
3299
|
-
|
|
3521
|
+
writer.write(ping);
|
|
3300
3522
|
}
|
|
3301
3523
|
catch ( /* ignore ping write errors */_b) { /* ignore ping write errors */ }
|
|
3302
3524
|
});
|
|
3303
3525
|
}
|
|
3304
|
-
catch ( /* ignore addEventListener errors */
|
|
3305
|
-
parser_1 = new HTTP2Parser(
|
|
3526
|
+
catch ( /* ignore addEventListener errors */_q) { /* ignore addEventListener errors */ }
|
|
3527
|
+
parser_1 = new HTTP2Parser(writer, {
|
|
3306
3528
|
compatibilityMode: !useFlowControl,
|
|
3307
3529
|
});
|
|
3308
3530
|
parser_1.onGoaway = function (info) {
|
|
@@ -3313,10 +3535,8 @@
|
|
|
3313
3535
|
if (state) {
|
|
3314
3536
|
_this.rejectStreamWaiters(state, new Error("Connection received GOAWAY"));
|
|
3315
3537
|
}
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
}
|
|
3319
|
-
internalController.abort();
|
|
3538
|
+
// reportError 统一完成:标记已报错 + abort + 触发回调(幂等,不会重复触发)
|
|
3539
|
+
reportError(new Error("GOAWAY received: code=".concat(info.errorCode)));
|
|
3320
3540
|
try {
|
|
3321
3541
|
connection === null || connection === void 0 ? void 0 : connection.close();
|
|
3322
3542
|
}
|
|
@@ -3341,7 +3561,7 @@
|
|
|
3341
3561
|
switch (_a.label) {
|
|
3342
3562
|
case 0:
|
|
3343
3563
|
if (!useFlowControl) return [3 /*break*/, 2];
|
|
3344
|
-
return [4 /*yield*/, this.sendFrameWithFlowControl(parser_1, streamId_2, frame,
|
|
3564
|
+
return [4 /*yield*/, this.sendFrameWithFlowControl(parser_1, streamId_2, frame, writer, internalController.signal, sendWindowTimeout_1)];
|
|
3345
3565
|
case 1:
|
|
3346
3566
|
_a.sent();
|
|
3347
3567
|
return [3 /*break*/, 4];
|
|
@@ -3349,7 +3569,7 @@
|
|
|
3349
3569
|
if (internalController.signal.aborted) {
|
|
3350
3570
|
throw new Error("Operation aborted");
|
|
3351
3571
|
}
|
|
3352
|
-
return [4 /*yield*/,
|
|
3572
|
+
return [4 /*yield*/, writer.write(frame)];
|
|
3353
3573
|
case 3:
|
|
3354
3574
|
_a.sent();
|
|
3355
3575
|
_a.label = 4;
|
|
@@ -3380,51 +3600,44 @@
|
|
|
3380
3600
|
}); };
|
|
3381
3601
|
// 在各个回调中检查是否已中止
|
|
3382
3602
|
parser_1.onData = function (payload) { return __awaiter(_this, void 0, void 0, function () {
|
|
3383
|
-
var
|
|
3603
|
+
var flat, lengthBytes, flat, completeMessage, remaining;
|
|
3384
3604
|
return __generator(this, function (_a) {
|
|
3385
|
-
|
|
3386
|
-
if (internalController.signal.aborted) {
|
|
3605
|
+
if (internalController.signal.aborted)
|
|
3387
3606
|
return [2 /*return*/];
|
|
3388
|
-
}
|
|
3389
3607
|
try {
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
messageBuffer = newBuffer;
|
|
3608
|
+
// 追加到分段列表,O(1),不拷贝历史数据
|
|
3609
|
+
msgChunks.push(payload);
|
|
3610
|
+
msgTotalLen += payload.length;
|
|
3394
3611
|
// 处理缓冲区中的完整消息
|
|
3395
|
-
while (
|
|
3396
|
-
|
|
3397
|
-
if (internalController.signal.aborted) {
|
|
3612
|
+
while (msgTotalLen > 0) {
|
|
3613
|
+
if (internalController.signal.aborted)
|
|
3398
3614
|
return [2 /*return*/];
|
|
3615
|
+
// 读取 gRPC 消息头(5字节)
|
|
3616
|
+
if (expectedMessageLength === -1 && msgTotalLen >= 5) {
|
|
3617
|
+
flat = flattenMsgBuffer();
|
|
3618
|
+
msgChunks = [flat];
|
|
3619
|
+
lengthBytes = flat.slice(1, 5);
|
|
3620
|
+
expectedMessageLength = new DataView(lengthBytes.buffer, lengthBytes.byteOffset).getUint32(0, false);
|
|
3399
3621
|
}
|
|
3400
|
-
//
|
|
3401
|
-
if (expectedMessageLength
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
// 如果知道期望长度且有足够数据
|
|
3406
|
-
if (expectedMessageLength !== -1 &&
|
|
3407
|
-
messageBuffer.length >= expectedMessageLength + 5) {
|
|
3408
|
-
completeMessage = messageBuffer.slice(5, expectedMessageLength + 5);
|
|
3409
|
-
// 调用回调处理这个完整消息
|
|
3622
|
+
// 有完整消息
|
|
3623
|
+
if (expectedMessageLength !== -1 && msgTotalLen >= expectedMessageLength + 5) {
|
|
3624
|
+
flat = flattenMsgBuffer();
|
|
3625
|
+
msgChunks = [flat];
|
|
3626
|
+
completeMessage = flat.slice(5, expectedMessageLength + 5);
|
|
3410
3627
|
onDataCallback(completeMessage);
|
|
3411
|
-
|
|
3412
|
-
|
|
3628
|
+
remaining = flat.slice(expectedMessageLength + 5);
|
|
3629
|
+
msgChunks = remaining.length > 0 ? [remaining] : [];
|
|
3630
|
+
msgTotalLen = remaining.length;
|
|
3413
3631
|
expectedMessageLength = -1;
|
|
3414
3632
|
}
|
|
3415
3633
|
else {
|
|
3416
|
-
// 没有足够数据构成完整消息,等待更多数据
|
|
3417
3634
|
break;
|
|
3418
3635
|
}
|
|
3419
3636
|
}
|
|
3420
3637
|
}
|
|
3421
3638
|
catch (error) {
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
}
|
|
3425
|
-
else {
|
|
3426
|
-
throw error;
|
|
3427
|
-
}
|
|
3639
|
+
// reportError 统一报错并中止,防止 onEndCallback 在数据处理异常后仍被调用
|
|
3640
|
+
reportError(error);
|
|
3428
3641
|
}
|
|
3429
3642
|
return [2 /*return*/];
|
|
3430
3643
|
});
|
|
@@ -3434,7 +3647,7 @@
|
|
|
3434
3647
|
if (internalController.signal.aborted)
|
|
3435
3648
|
return;
|
|
3436
3649
|
var ackSettingFrame = Http2Frame.createSettingsAckFrame();
|
|
3437
|
-
|
|
3650
|
+
writer.write(ackSettingFrame);
|
|
3438
3651
|
};
|
|
3439
3652
|
parser_1.onHeaders = function (headers) {
|
|
3440
3653
|
// 检查是否已中止
|
|
@@ -3444,20 +3657,16 @@
|
|
|
3444
3657
|
if (plainHeaders.get("grpc-status") === "0") ;
|
|
3445
3658
|
else if (plainHeaders.get("grpc-status") !== undefined) {
|
|
3446
3659
|
var errMsg = plainHeaders.get("grpc-message") || "gRPC call failed";
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
onErrorCallback(err);
|
|
3450
|
-
}
|
|
3451
|
-
else {
|
|
3452
|
-
throw err;
|
|
3453
|
-
}
|
|
3660
|
+
// reportError 统一完成:标记已报错 + abort + 触发回调(幂等,不会重复触发)
|
|
3661
|
+
reportError(new Error(errMsg));
|
|
3454
3662
|
}
|
|
3455
3663
|
};
|
|
3456
3664
|
// 启动后台流处理
|
|
3457
3665
|
parser_1.processStream(stream).catch(function (error) {
|
|
3458
|
-
|
|
3459
|
-
if (
|
|
3460
|
-
|
|
3666
|
+
// abort() 触发的清理错误属于预期行为,不打印错误日志,不重复触发回调
|
|
3667
|
+
if (!internalController.signal.aborted) {
|
|
3668
|
+
console.error('Error in processStream:', error);
|
|
3669
|
+
reportError(error);
|
|
3461
3670
|
}
|
|
3462
3671
|
});
|
|
3463
3672
|
// 检查是否已中止
|
|
@@ -3465,56 +3674,52 @@
|
|
|
3465
3674
|
throw new Error("Operation aborted");
|
|
3466
3675
|
}
|
|
3467
3676
|
preface = Http2Frame.createPreface();
|
|
3468
|
-
return [4 /*yield*/,
|
|
3677
|
+
return [4 /*yield*/, writer.write(preface)];
|
|
3469
3678
|
case 13:
|
|
3470
|
-
|
|
3679
|
+
_p.sent();
|
|
3471
3680
|
// 检查是否已中止
|
|
3472
3681
|
if (internalController.signal.aborted) {
|
|
3473
3682
|
throw new Error("Operation aborted");
|
|
3474
3683
|
}
|
|
3475
3684
|
settingFrame = Http2Frame.createSettingsFrame();
|
|
3476
|
-
return [4 /*yield*/,
|
|
3685
|
+
return [4 /*yield*/, writer.write(settingFrame)];
|
|
3477
3686
|
case 14:
|
|
3478
|
-
|
|
3687
|
+
_p.sent();
|
|
3479
3688
|
// 检查是否已中止
|
|
3480
3689
|
if (internalController.signal.aborted) {
|
|
3481
3690
|
throw new Error("Operation aborted");
|
|
3482
3691
|
}
|
|
3483
3692
|
return [4 /*yield*/, Promise.race([
|
|
3484
|
-
parser_1.waitForPeerSettings(1000),
|
|
3485
|
-
parser_1.waitForSettingsAck(),
|
|
3693
|
+
parser_1.waitForPeerSettings(1000).catch(function () { }),
|
|
3694
|
+
parser_1.waitForSettingsAck().catch(function () { }),
|
|
3486
3695
|
new Promise(function (res) { return setTimeout(res, 300); }),
|
|
3487
3696
|
])];
|
|
3488
3697
|
case 15:
|
|
3489
|
-
|
|
3698
|
+
_p.sent();
|
|
3490
3699
|
// 检查是否已中止
|
|
3491
3700
|
if (internalController.signal.aborted) {
|
|
3492
3701
|
throw new Error("Operation aborted");
|
|
3493
3702
|
}
|
|
3494
|
-
|
|
3495
|
-
if (internalController.signal.aborted) {
|
|
3496
|
-
throw new Error("Operation aborted");
|
|
3497
|
-
}
|
|
3498
|
-
headerFrame = Http2Frame.createHeadersFrame(streamId_2, method, true, this.token);
|
|
3703
|
+
headerFrame = Http2Frame.createHeadersFrame(streamId_2, method, true, this.token, this.getAuthority());
|
|
3499
3704
|
if (!(mode === "unary" || mode === "server-streaming")) return [3 /*break*/, 18];
|
|
3500
|
-
return [4 /*yield*/,
|
|
3705
|
+
return [4 /*yield*/, writer.write(headerFrame)];
|
|
3501
3706
|
case 16:
|
|
3502
|
-
|
|
3707
|
+
_p.sent();
|
|
3503
3708
|
dfs = Http2Frame.createDataFrames(streamId_2, requestData, true);
|
|
3504
3709
|
return [4 /*yield*/, writeDataFrames_1(dfs)];
|
|
3505
3710
|
case 17:
|
|
3506
|
-
|
|
3711
|
+
_p.sent();
|
|
3507
3712
|
// 检查是否已中止
|
|
3508
3713
|
if (internalController.signal.aborted) {
|
|
3509
3714
|
throw new Error("Operation aborted");
|
|
3510
3715
|
}
|
|
3511
|
-
return [3 /*break*/,
|
|
3716
|
+
return [3 /*break*/, 45];
|
|
3512
3717
|
case 18:
|
|
3513
3718
|
if (!((mode === "client-streaming" || mode === "bidirectional") &&
|
|
3514
|
-
dataSourceCallback)) return [3 /*break*/,
|
|
3515
|
-
return [4 /*yield*/,
|
|
3719
|
+
dataSourceCallback)) return [3 /*break*/, 45];
|
|
3720
|
+
return [4 /*yield*/, writer.write(headerFrame)];
|
|
3516
3721
|
case 19:
|
|
3517
|
-
|
|
3722
|
+
_p.sent();
|
|
3518
3723
|
// 检查是否已中止
|
|
3519
3724
|
if (internalController.signal.aborted) {
|
|
3520
3725
|
throw new Error("Operation aborted");
|
|
@@ -3523,12 +3728,23 @@
|
|
|
3523
3728
|
dfs0 = Http2Frame.createDataFrames(streamId_2, requestData, false);
|
|
3524
3729
|
return [4 /*yield*/, writeDataFrames_1(dfs0)];
|
|
3525
3730
|
case 20:
|
|
3526
|
-
|
|
3527
|
-
|
|
3731
|
+
_p.sent();
|
|
3732
|
+
_p.label = 21;
|
|
3528
3733
|
case 21:
|
|
3529
3734
|
batchSize_1 = (options === null || options === void 0 ? void 0 : options.batchSize) || 10;
|
|
3530
3735
|
processingQueue_1 = [];
|
|
3736
|
+
batchDoneWaiters_1 = [];
|
|
3531
3737
|
isProcessing_1 = false;
|
|
3738
|
+
_notifyBatchDone_1 = function () {
|
|
3739
|
+
var ws = batchDoneWaiters_1.splice(0);
|
|
3740
|
+
for (var _i = 0, ws_1 = ws; _i < ws_1.length; _i++) {
|
|
3741
|
+
var fn = ws_1[_i];
|
|
3742
|
+
try {
|
|
3743
|
+
fn();
|
|
3744
|
+
}
|
|
3745
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
3746
|
+
}
|
|
3747
|
+
};
|
|
3532
3748
|
processNextBatch_1 = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
3533
3749
|
var currentBatch, _i, currentBatch_1, item, frames_2, item, frames1, error_3;
|
|
3534
3750
|
return __generator(this, function (_a) {
|
|
@@ -3589,10 +3805,13 @@
|
|
|
3589
3805
|
case 10:
|
|
3590
3806
|
isProcessing_1 = false;
|
|
3591
3807
|
// 如果队列中还有数据,继续处理
|
|
3592
|
-
if (processingQueue_1.length > 0 &&
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3808
|
+
if (processingQueue_1.length > 0 && !internalController.signal.aborted) {
|
|
3809
|
+
// 直接递归调用(已是 async,自动让出事件循环)
|
|
3810
|
+
processNextBatch_1().catch(function (err) { console.error("Error in processNextBatch:", err); });
|
|
3811
|
+
}
|
|
3812
|
+
else {
|
|
3813
|
+
// 队列清空,唤醒等待者
|
|
3814
|
+
_notifyBatchDone_1();
|
|
3596
3815
|
}
|
|
3597
3816
|
return [7 /*endfinally*/];
|
|
3598
3817
|
case 11: return [2 /*return*/];
|
|
@@ -3615,20 +3834,20 @@
|
|
|
3615
3834
|
}
|
|
3616
3835
|
});
|
|
3617
3836
|
};
|
|
3618
|
-
|
|
3837
|
+
_p.label = 22;
|
|
3619
3838
|
case 22:
|
|
3620
|
-
|
|
3621
|
-
|
|
3839
|
+
_p.trys.push([22, 36, , 37]);
|
|
3840
|
+
_p.label = 23;
|
|
3622
3841
|
case 23:
|
|
3623
|
-
|
|
3842
|
+
_p.trys.push([23, 29, 30, 35]);
|
|
3624
3843
|
_a = true, _b = __asyncValues(dataSourceCallback());
|
|
3625
|
-
|
|
3844
|
+
_p.label = 24;
|
|
3626
3845
|
case 24: return [4 /*yield*/, _b.next()];
|
|
3627
3846
|
case 25:
|
|
3628
|
-
if (!(_c =
|
|
3629
|
-
|
|
3847
|
+
if (!(_c = _p.sent(), _h = _c.done, !_h)) return [3 /*break*/, 28];
|
|
3848
|
+
_k = _c.value;
|
|
3630
3849
|
_a = false;
|
|
3631
|
-
chunkOrChunks =
|
|
3850
|
+
chunkOrChunks = _k;
|
|
3632
3851
|
// 检查是否已中止
|
|
3633
3852
|
if (internalController.signal.aborted) {
|
|
3634
3853
|
throw new Error("Operation aborted");
|
|
@@ -3643,23 +3862,23 @@
|
|
|
3643
3862
|
return [4 /*yield*/, Promise.all(addPromises)];
|
|
3644
3863
|
case 26:
|
|
3645
3864
|
// 等待当前批次的chunks被添加到队列(不等待处理完成)
|
|
3646
|
-
|
|
3647
|
-
|
|
3865
|
+
_p.sent();
|
|
3866
|
+
_p.label = 27;
|
|
3648
3867
|
case 27:
|
|
3649
3868
|
_a = true;
|
|
3650
3869
|
return [3 /*break*/, 24];
|
|
3651
3870
|
case 28: return [3 /*break*/, 35];
|
|
3652
3871
|
case 29:
|
|
3653
|
-
e_1_1 =
|
|
3872
|
+
e_1_1 = _p.sent();
|
|
3654
3873
|
e_1 = { error: e_1_1 };
|
|
3655
3874
|
return [3 /*break*/, 35];
|
|
3656
3875
|
case 30:
|
|
3657
|
-
|
|
3658
|
-
if (!(!_a && !
|
|
3659
|
-
return [4 /*yield*/,
|
|
3876
|
+
_p.trys.push([30, , 33, 34]);
|
|
3877
|
+
if (!(!_a && !_h && (_j = _b.return))) return [3 /*break*/, 32];
|
|
3878
|
+
return [4 /*yield*/, _j.call(_b)];
|
|
3660
3879
|
case 31:
|
|
3661
|
-
|
|
3662
|
-
|
|
3880
|
+
_p.sent();
|
|
3881
|
+
_p.label = 32;
|
|
3663
3882
|
case 32: return [3 /*break*/, 34];
|
|
3664
3883
|
case 33:
|
|
3665
3884
|
if (e_1) throw e_1.error;
|
|
@@ -3667,7 +3886,7 @@
|
|
|
3667
3886
|
case 34: return [7 /*endfinally*/];
|
|
3668
3887
|
case 35: return [3 /*break*/, 37];
|
|
3669
3888
|
case 36:
|
|
3670
|
-
error_2 =
|
|
3889
|
+
error_2 = _p.sent();
|
|
3671
3890
|
remainingQueue = processingQueue_1.splice(0);
|
|
3672
3891
|
remainingQueue.forEach(function (item) {
|
|
3673
3892
|
try {
|
|
@@ -3678,81 +3897,95 @@
|
|
|
3678
3897
|
}
|
|
3679
3898
|
});
|
|
3680
3899
|
throw error_2;
|
|
3681
|
-
case 37:
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
throw new Error("Operation aborted");
|
|
3689
|
-
}
|
|
3690
|
-
// 防止无限等待
|
|
3691
|
-
if (Date.now() - queueWaitStart > maxQueueWaitMs) {
|
|
3692
|
-
remainingQueue = processingQueue_1.splice(0);
|
|
3693
|
-
remainingQueue.forEach(function (item) {
|
|
3694
|
-
try {
|
|
3695
|
-
item.reject(new Error("Queue wait timeout"));
|
|
3900
|
+
case 37:
|
|
3901
|
+
// 等待所有剩余的数据处理完成(事件驱动,无 10ms 轮询)
|
|
3902
|
+
return [4 /*yield*/, new Promise(function (resolve, reject) {
|
|
3903
|
+
var check = function () {
|
|
3904
|
+
if (internalController.signal.aborted) {
|
|
3905
|
+
reject(new Error("Operation aborted"));
|
|
3906
|
+
return;
|
|
3696
3907
|
}
|
|
3697
|
-
|
|
3698
|
-
|
|
3908
|
+
if (processingQueue_1.length === 0 && !isProcessing_1) {
|
|
3909
|
+
resolve();
|
|
3910
|
+
return;
|
|
3699
3911
|
}
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3912
|
+
// processNextBatch 结束时会通知这里
|
|
3913
|
+
batchDoneWaiters_1.push(check);
|
|
3914
|
+
};
|
|
3915
|
+
check();
|
|
3916
|
+
})];
|
|
3917
|
+
case 38:
|
|
3918
|
+
// 等待所有剩余的数据处理完成(事件驱动,无 10ms 轮询)
|
|
3919
|
+
_p.sent();
|
|
3708
3920
|
// 检查是否已中止
|
|
3709
3921
|
if (internalController.signal.aborted) {
|
|
3710
3922
|
throw new Error("Operation aborted");
|
|
3711
3923
|
}
|
|
3712
|
-
finalFrame = Http2Frame.
|
|
3924
|
+
finalFrame = Http2Frame.createFrame(0x0, 0x01, streamId_2, new Uint8Array(0));
|
|
3713
3925
|
return [4 /*yield*/, writeFrame_1(finalFrame)];
|
|
3926
|
+
case 39:
|
|
3927
|
+
_p.sent();
|
|
3928
|
+
_p.label = 40;
|
|
3929
|
+
case 40:
|
|
3930
|
+
_p.trys.push([40, 42, , 43]);
|
|
3931
|
+
return [4 /*yield*/, writer.flush(timeout)];
|
|
3714
3932
|
case 41:
|
|
3715
|
-
|
|
3716
|
-
|
|
3933
|
+
_p.sent();
|
|
3934
|
+
return [3 /*break*/, 43];
|
|
3717
3935
|
case 42:
|
|
3718
|
-
|
|
3719
|
-
return [
|
|
3720
|
-
case 43:
|
|
3721
|
-
_o.sent();
|
|
3722
|
-
return [3 /*break*/, 45];
|
|
3936
|
+
_p.sent();
|
|
3937
|
+
return [3 /*break*/, 43];
|
|
3938
|
+
case 43: return [4 /*yield*/, writer.end()];
|
|
3723
3939
|
case 44:
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
case 45:
|
|
3727
|
-
case 46:
|
|
3728
|
-
_o.sent();
|
|
3729
|
-
_o.label = 47;
|
|
3730
|
-
case 47:
|
|
3940
|
+
_p.sent();
|
|
3941
|
+
_p.label = 45;
|
|
3942
|
+
case 45:
|
|
3731
3943
|
// 检查是否已中止
|
|
3732
3944
|
if (internalController.signal.aborted) {
|
|
3733
3945
|
throw new Error("Operation aborted");
|
|
3734
3946
|
}
|
|
3947
|
+
if (!!internalController.signal.aborted) return [3 /*break*/, 48];
|
|
3735
3948
|
return [4 /*yield*/, parser_1.waitForEndOfStream(0)];
|
|
3736
|
-
case
|
|
3737
|
-
|
|
3738
|
-
|
|
3949
|
+
case 46:
|
|
3950
|
+
_p.sent();
|
|
3951
|
+
// Yield one microtask tick so that processStream.catch (which calls
|
|
3952
|
+
// reportError + internalController.abort()) has a chance to run before
|
|
3953
|
+
// we check abort status. Without this yield, if the stream died
|
|
3954
|
+
// unexpectedly (network error), onEndCallback and onErrorCallback
|
|
3955
|
+
// could both fire because _notifyEndOfStream() is called in
|
|
3956
|
+
// processStream's catch block before the re-throw schedules the
|
|
3957
|
+
// .catch handler as a microtask.
|
|
3958
|
+
return [4 /*yield*/, Promise.resolve()];
|
|
3959
|
+
case 47:
|
|
3960
|
+
// Yield one microtask tick so that processStream.catch (which calls
|
|
3961
|
+
// reportError + internalController.abort()) has a chance to run before
|
|
3962
|
+
// we check abort status. Without this yield, if the stream died
|
|
3963
|
+
// unexpectedly (network error), onEndCallback and onErrorCallback
|
|
3964
|
+
// could both fire because _notifyEndOfStream() is called in
|
|
3965
|
+
// processStream's catch block before the re-throw schedules the
|
|
3966
|
+
// .catch handler as a microtask.
|
|
3967
|
+
_p.sent();
|
|
3968
|
+
if (!internalController.signal.aborted && onEndCallback) {
|
|
3739
3969
|
onEndCallback();
|
|
3740
3970
|
}
|
|
3741
|
-
|
|
3971
|
+
_p.label = 48;
|
|
3972
|
+
case 48: return [3 /*break*/, 64];
|
|
3742
3973
|
case 49:
|
|
3743
|
-
err_6 =
|
|
3974
|
+
err_6 = _p.sent();
|
|
3744
3975
|
// 如果是由于取消导致的错误,使用特定的错误消息
|
|
3745
3976
|
if (internalController.signal.aborted &&
|
|
3746
3977
|
err_6 instanceof Error &&
|
|
3747
3978
|
err_6.message === "Operation aborted") {
|
|
3748
|
-
|
|
3979
|
+
// onHeaders / onGoaway / processStream 错误已通过 reportError 处理,
|
|
3980
|
+
// 此处仅在回调尚未触发时才报告(外部取消/超时场景)
|
|
3981
|
+
if (!errorCallbackFired && onErrorCallback) {
|
|
3749
3982
|
onErrorCallback(new Error("Operation cancelled by user"));
|
|
3750
3983
|
}
|
|
3751
3984
|
}
|
|
3752
|
-
else if (onErrorCallback) {
|
|
3985
|
+
else if (!errorCallbackFired && onErrorCallback) {
|
|
3753
3986
|
onErrorCallback(err_6);
|
|
3754
3987
|
}
|
|
3755
|
-
else {
|
|
3988
|
+
else if (!errorCallbackFired) {
|
|
3756
3989
|
if (err_6 instanceof Error) {
|
|
3757
3990
|
console.error("asyncCall error:", err_6.message);
|
|
3758
3991
|
}
|
|
@@ -3763,45 +3996,53 @@
|
|
|
3763
3996
|
return [3 /*break*/, 64];
|
|
3764
3997
|
case 50:
|
|
3765
3998
|
clearTimeout(timeoutHandle);
|
|
3999
|
+
// 移除外部 abort 监听器,防止 AbortController 复用时触发迟到的 cancelOperation()
|
|
4000
|
+
if (contextAbortHandler && (context === null || context === void 0 ? void 0 : context.signal)) {
|
|
4001
|
+
context.signal.removeEventListener("abort", contextAbortHandler);
|
|
4002
|
+
}
|
|
4003
|
+
// 必须先 abort writer(立即强制停止 pushable + stream),再 close stream。
|
|
4004
|
+
// 若顺序颠倒:stream.close() 等待服务端半关闭确认,网络异常时永久挂住,
|
|
4005
|
+
// writer.abort() 永远不执行 → watchdog / pushable 泄漏。
|
|
4006
|
+
// abort() 内部幂等,重复调用安全。
|
|
4007
|
+
writer === null || writer === void 0 ? void 0 : writer.abort('Call cleanup');
|
|
3766
4008
|
if (!stream) return [3 /*break*/, 54];
|
|
3767
|
-
|
|
4009
|
+
_p.label = 51;
|
|
3768
4010
|
case 51:
|
|
3769
|
-
|
|
4011
|
+
_p.trys.push([51, 53, , 54]);
|
|
3770
4012
|
return [4 /*yield*/, stream.close()];
|
|
3771
4013
|
case 52:
|
|
3772
|
-
|
|
4014
|
+
_p.sent();
|
|
3773
4015
|
return [3 /*break*/, 54];
|
|
3774
4016
|
case 53:
|
|
3775
|
-
|
|
3776
|
-
console.error("Error closing stream:", err_7);
|
|
4017
|
+
_p.sent();
|
|
3777
4018
|
return [3 /*break*/, 54];
|
|
3778
4019
|
case 54:
|
|
3779
4020
|
if (!(options === null || options === void 0 ? void 0 : options.freshConnection)) return [3 /*break*/, 63];
|
|
3780
|
-
|
|
4021
|
+
_p.label = 55;
|
|
3781
4022
|
case 55:
|
|
3782
|
-
|
|
3783
|
-
conns = ((
|
|
4023
|
+
_p.trys.push([55, 62, , 63]);
|
|
4024
|
+
conns = ((_m = (_l = this.node).getConnections) === null || _m === void 0 ? void 0 : _m.call(_l, this.peerAddr)) || [];
|
|
3784
4025
|
_i = 0, conns_1 = conns;
|
|
3785
|
-
|
|
4026
|
+
_p.label = 56;
|
|
3786
4027
|
case 56:
|
|
3787
4028
|
if (!(_i < conns_1.length)) return [3 /*break*/, 61];
|
|
3788
4029
|
c = conns_1[_i];
|
|
3789
|
-
|
|
4030
|
+
_p.label = 57;
|
|
3790
4031
|
case 57:
|
|
3791
|
-
|
|
3792
|
-
return [4 /*yield*/, ((
|
|
4032
|
+
_p.trys.push([57, 59, , 60]);
|
|
4033
|
+
return [4 /*yield*/, ((_o = c.close) === null || _o === void 0 ? void 0 : _o.call(c))];
|
|
3793
4034
|
case 58:
|
|
3794
|
-
|
|
4035
|
+
_p.sent();
|
|
3795
4036
|
return [3 /*break*/, 60];
|
|
3796
4037
|
case 59:
|
|
3797
|
-
|
|
4038
|
+
_p.sent();
|
|
3798
4039
|
return [3 /*break*/, 60];
|
|
3799
4040
|
case 60:
|
|
3800
4041
|
_i++;
|
|
3801
4042
|
return [3 /*break*/, 56];
|
|
3802
4043
|
case 61: return [3 /*break*/, 63];
|
|
3803
4044
|
case 62:
|
|
3804
|
-
|
|
4045
|
+
_p.sent();
|
|
3805
4046
|
return [3 /*break*/, 63];
|
|
3806
4047
|
case 63:
|
|
3807
4048
|
if (streamSlotAcquired && state) {
|