grpc-libp2p-client 0.0.39 → 0.0.41
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 -188
- 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 -188
- package/dist/dc-http2/parser.esm.js.map +1 -1
- package/dist/dc-http2/stream.cjs.js +97 -70
- 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 +97 -70
- package/dist/dc-http2/stream.esm.js.map +1 -1
- package/dist/grpc.js +820 -582
- 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 +646 -414
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +646 -414
- 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 +220 -195
- package/src/dc-http2/stream.ts +84 -79
- package/src/index.ts +253 -187
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;
|
|
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,9 +1100,23 @@
|
|
|
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();
|
|
1111
|
+
// 确保 waitForEndOfStream 等待者得到通知,防止 operationPromise 后台挂死
|
|
1112
|
+
if (!this.endFlag) {
|
|
1113
|
+
this._notifyEndOfStream();
|
|
1114
|
+
}
|
|
1115
|
+
errMsg = error_1 instanceof Error ? error_1.message : String(error_1);
|
|
1116
|
+
if (/cleanup/i.test(errMsg)) {
|
|
1117
|
+
// 预期的主动清理,无需 re-throw,.catch in index.ts 不需要处理它
|
|
1118
|
+
return [2 /*return*/];
|
|
1119
|
+
}
|
|
1034
1120
|
console.error("Error processing stream:", error_1);
|
|
1035
1121
|
throw error_1;
|
|
1036
1122
|
case 14: return [2 /*return*/];
|
|
@@ -1038,45 +1124,61 @@
|
|
|
1038
1124
|
});
|
|
1039
1125
|
});
|
|
1040
1126
|
};
|
|
1041
|
-
// 处理单个数据块
|
|
1127
|
+
// 处理单个数据块 — 分段列表追加,避免每次 O(n) 全量拷贝
|
|
1042
1128
|
HTTP2Parser.prototype._processChunk = function (chunk) {
|
|
1043
1129
|
// chunk 是 Uint8ArrayList 或 Uint8Array
|
|
1044
1130
|
var newData = 'subarray' in chunk && typeof chunk.subarray === 'function'
|
|
1045
1131
|
? chunk.subarray()
|
|
1046
1132
|
: chunk;
|
|
1047
|
-
//
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1133
|
+
// 追加到分段列表,O(1),不拷贝历史数据
|
|
1134
|
+
if (newData.length > 0) {
|
|
1135
|
+
this.bufferChunks.push(newData);
|
|
1136
|
+
this.bufferTotalLength += newData.length;
|
|
1137
|
+
}
|
|
1138
|
+
// 将所有分段合并为一块后处理帧(只合并一次,后续 slice 替换)
|
|
1139
|
+
// 仅在确实有完整帧时才触发合并,碎片仅 push 不合并
|
|
1140
|
+
if (this.bufferTotalLength < 9)
|
|
1141
|
+
return;
|
|
1142
|
+
// 合并一次
|
|
1143
|
+
var flat = this._flattenBuffer();
|
|
1144
|
+
this.bufferChunks = [flat];
|
|
1145
|
+
// bufferTotalLength 保持不变
|
|
1052
1146
|
// 持续处理所有完整的帧
|
|
1053
1147
|
var readOffset = 0;
|
|
1054
|
-
while (
|
|
1148
|
+
while (flat.length - readOffset >= 9) {
|
|
1055
1149
|
// 判断是否有HTTP/2前导
|
|
1056
|
-
if (
|
|
1150
|
+
if (flat.length - readOffset >= 24 && this.isHttp2Preface(flat.subarray(readOffset))) {
|
|
1057
1151
|
readOffset += 24;
|
|
1058
1152
|
// 发送SETTINGS帧
|
|
1059
1153
|
var settingFrame = Http2Frame.createSettingsFrame();
|
|
1060
1154
|
this.writer.write(settingFrame);
|
|
1061
1155
|
continue;
|
|
1062
1156
|
}
|
|
1063
|
-
var frameHeader = this._parseFrameHeader(
|
|
1157
|
+
var frameHeader = this._parseFrameHeader(flat.subarray(readOffset));
|
|
1064
1158
|
var totalFrameLength = 9 + frameHeader.length;
|
|
1065
1159
|
// 检查是否有完整的帧
|
|
1066
|
-
if (
|
|
1160
|
+
if (flat.length - readOffset < totalFrameLength) {
|
|
1067
1161
|
break;
|
|
1068
1162
|
}
|
|
1069
|
-
//
|
|
1070
|
-
var frameData =
|
|
1163
|
+
// 获取完整帧数据(subarray 视图,零拷贝)
|
|
1164
|
+
var frameData = flat.subarray(readOffset, readOffset + totalFrameLength);
|
|
1071
1165
|
// 处理不同类型的帧
|
|
1072
1166
|
this._handleFrame(frameHeader, frameData).catch(function (err) {
|
|
1073
1167
|
console.error("Error handling frame:", err);
|
|
1074
1168
|
});
|
|
1075
|
-
// 移动偏移量
|
|
1076
1169
|
readOffset += totalFrameLength;
|
|
1077
1170
|
}
|
|
1171
|
+
// 保留未消费的尾部字节(slice 一次,后续仍分段追加)
|
|
1078
1172
|
if (readOffset > 0) {
|
|
1079
|
-
|
|
1173
|
+
if (readOffset >= flat.length) {
|
|
1174
|
+
this.bufferChunks = [];
|
|
1175
|
+
this.bufferTotalLength = 0;
|
|
1176
|
+
}
|
|
1177
|
+
else {
|
|
1178
|
+
var remaining = flat.slice(readOffset);
|
|
1179
|
+
this.bufferChunks = [remaining];
|
|
1180
|
+
this.bufferTotalLength = remaining.length;
|
|
1181
|
+
}
|
|
1080
1182
|
}
|
|
1081
1183
|
};
|
|
1082
1184
|
HTTP2Parser.prototype.isHttp2Preface = function (buffer) {
|
|
@@ -1088,11 +1190,7 @@
|
|
|
1088
1190
|
}
|
|
1089
1191
|
return true;
|
|
1090
1192
|
};
|
|
1091
|
-
//
|
|
1092
|
-
HTTP2Parser.prototype._oldProcessStream_removed = function () {
|
|
1093
|
-
// 这个方法已被上面的事件驱动实现替代
|
|
1094
|
-
};
|
|
1095
|
-
// 等待SETTINGS ACK
|
|
1193
|
+
// 等待SETTINGS ACK — 事件驱动,无轮询
|
|
1096
1194
|
HTTP2Parser.prototype.waitForSettingsAck = function () {
|
|
1097
1195
|
var _this = this;
|
|
1098
1196
|
return new Promise(function (resolve, reject) {
|
|
@@ -1100,20 +1198,32 @@
|
|
|
1100
1198
|
resolve();
|
|
1101
1199
|
return;
|
|
1102
1200
|
}
|
|
1103
|
-
var
|
|
1104
|
-
|
|
1105
|
-
clearInterval(interval);
|
|
1106
|
-
clearTimeout(timeout);
|
|
1107
|
-
resolve();
|
|
1108
|
-
}
|
|
1109
|
-
}, 100);
|
|
1201
|
+
var waiter = { resolve: resolve, reject: reject };
|
|
1202
|
+
_this.settingsAckWaiters.push(waiter);
|
|
1110
1203
|
var timeout = setTimeout(function () {
|
|
1111
|
-
|
|
1204
|
+
var idx = _this.settingsAckWaiters.indexOf(waiter);
|
|
1205
|
+
if (idx >= 0)
|
|
1206
|
+
_this.settingsAckWaiters.splice(idx, 1);
|
|
1112
1207
|
reject(new Error("Settings ACK timeout"));
|
|
1113
1208
|
}, 30000);
|
|
1209
|
+
// 覆盖 resolve 以便超时前自动清理定时器
|
|
1210
|
+
waiter.resolve = function () { clearTimeout(timeout); resolve(); };
|
|
1211
|
+
waiter.reject = function (e) { clearTimeout(timeout); reject(e); };
|
|
1114
1212
|
});
|
|
1115
1213
|
};
|
|
1116
|
-
|
|
1214
|
+
/** 内部调用:SETTINGS ACK 收到时唤醒所有等待者 */
|
|
1215
|
+
HTTP2Parser.prototype._notifySettingsAck = function () {
|
|
1216
|
+
this.settingsAckReceived = true;
|
|
1217
|
+
var ws = this.settingsAckWaiters.splice(0);
|
|
1218
|
+
for (var _i = 0, ws_2 = ws; _i < ws_2.length; _i++) {
|
|
1219
|
+
var w = ws_2[_i];
|
|
1220
|
+
try {
|
|
1221
|
+
w.resolve();
|
|
1222
|
+
}
|
|
1223
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
1224
|
+
}
|
|
1225
|
+
};
|
|
1226
|
+
// 等待接收来自对端的 SETTINGS(非 ACK)— 事件驱动,无轮询
|
|
1117
1227
|
HTTP2Parser.prototype.waitForPeerSettings = function (timeoutMs) {
|
|
1118
1228
|
var _this = this;
|
|
1119
1229
|
if (timeoutMs === void 0) { timeoutMs = 30000; }
|
|
@@ -1122,19 +1232,30 @@
|
|
|
1122
1232
|
resolve();
|
|
1123
1233
|
return;
|
|
1124
1234
|
}
|
|
1125
|
-
var
|
|
1126
|
-
|
|
1127
|
-
clearInterval(interval);
|
|
1128
|
-
clearTimeout(timeout);
|
|
1129
|
-
resolve();
|
|
1130
|
-
}
|
|
1131
|
-
}, 100);
|
|
1235
|
+
var waiter = { resolve: resolve, reject: reject };
|
|
1236
|
+
_this.peerSettingsWaiters.push(waiter);
|
|
1132
1237
|
var timeout = setTimeout(function () {
|
|
1133
|
-
|
|
1238
|
+
var idx = _this.peerSettingsWaiters.indexOf(waiter);
|
|
1239
|
+
if (idx >= 0)
|
|
1240
|
+
_this.peerSettingsWaiters.splice(idx, 1);
|
|
1134
1241
|
reject(new Error("Peer SETTINGS timeout"));
|
|
1135
1242
|
}, timeoutMs);
|
|
1243
|
+
waiter.resolve = function () { clearTimeout(timeout); resolve(); };
|
|
1244
|
+
waiter.reject = function (e) { clearTimeout(timeout); reject(e); };
|
|
1136
1245
|
});
|
|
1137
1246
|
};
|
|
1247
|
+
/** 内部调用:收到对端 SETTINGS(非 ACK)时唤醒等待者 */
|
|
1248
|
+
HTTP2Parser.prototype._notifyPeerSettings = function () {
|
|
1249
|
+
this.peerSettingsReceived = true;
|
|
1250
|
+
var ws = this.peerSettingsWaiters.splice(0);
|
|
1251
|
+
for (var _i = 0, ws_3 = ws; _i < ws_3.length; _i++) {
|
|
1252
|
+
var w = ws_3[_i];
|
|
1253
|
+
try {
|
|
1254
|
+
w.resolve();
|
|
1255
|
+
}
|
|
1256
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
1257
|
+
}
|
|
1258
|
+
};
|
|
1138
1259
|
// 注册我们要发送数据的出站流(用于初始化该流的对端窗口)
|
|
1139
1260
|
HTTP2Parser.prototype.registerOutboundStream = function (streamId) {
|
|
1140
1261
|
if (!this.sendStreamWindows.has(streamId)) {
|
|
@@ -1164,75 +1285,67 @@
|
|
|
1164
1285
|
this.sendConnWindow = Math.min(0x7fffffff, this.sendConnWindow + bytes);
|
|
1165
1286
|
var cur = (_a = this.sendStreamWindows.get(streamId)) !== null && _a !== void 0 ? _a : 0;
|
|
1166
1287
|
this.sendStreamWindows.set(streamId, Math.min(0x7fffffff, cur + bytes));
|
|
1288
|
+
// 窗口增大,唤醒等待者
|
|
1289
|
+
this._wakeWindowWaiters();
|
|
1167
1290
|
};
|
|
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
|
-
});
|
|
1291
|
+
// 等待可用发送窗口 — 事件驱动,WINDOW_UPDATE/SETTINGS 收到时直接唤醒
|
|
1292
|
+
HTTP2Parser.prototype.waitForSendWindow = function (streamId, minBytes, timeoutMs) {
|
|
1293
|
+
var _this = this;
|
|
1294
|
+
if (minBytes === void 0) { minBytes = 1; }
|
|
1295
|
+
if (timeoutMs === void 0) { timeoutMs = 30000; }
|
|
1296
|
+
var _a = this.getSendWindows(streamId), conn = _a.conn, stream = _a.stream;
|
|
1297
|
+
if (conn >= minBytes && stream >= minBytes)
|
|
1298
|
+
return Promise.resolve();
|
|
1299
|
+
return new Promise(function (resolve, reject) {
|
|
1300
|
+
var settled = false;
|
|
1301
|
+
var timeout = timeoutMs > 0
|
|
1302
|
+
? setTimeout(function () {
|
|
1303
|
+
if (settled)
|
|
1304
|
+
return;
|
|
1305
|
+
settled = true;
|
|
1306
|
+
var idx = _this.sendWindowWaiters.findIndex(function (w) { return w.resolve === resolveWrap; });
|
|
1307
|
+
if (idx >= 0)
|
|
1308
|
+
_this.sendWindowWaiters.splice(idx, 1);
|
|
1309
|
+
reject(new Error('Send window wait timeout'));
|
|
1310
|
+
}, timeoutMs)
|
|
1311
|
+
: undefined;
|
|
1312
|
+
var resolveWrap = function () {
|
|
1313
|
+
if (settled)
|
|
1314
|
+
return;
|
|
1315
|
+
var _a = _this.getSendWindows(streamId), c2 = _a.conn, s2 = _a.stream;
|
|
1316
|
+
if (c2 >= minBytes && s2 >= minBytes) {
|
|
1317
|
+
settled = true;
|
|
1318
|
+
if (timeout)
|
|
1319
|
+
clearTimeout(timeout);
|
|
1320
|
+
resolve();
|
|
1321
|
+
}
|
|
1322
|
+
else {
|
|
1323
|
+
// 窗口仍不够,重新入队等待下一次更新
|
|
1324
|
+
_this.sendWindowWaiters.push({ resolve: resolveWrap, reject: rejectWrap });
|
|
1325
|
+
}
|
|
1326
|
+
};
|
|
1327
|
+
var rejectWrap = function (e) {
|
|
1328
|
+
if (settled)
|
|
1329
|
+
return;
|
|
1330
|
+
settled = true;
|
|
1331
|
+
if (timeout)
|
|
1332
|
+
clearTimeout(timeout);
|
|
1333
|
+
reject(e);
|
|
1334
|
+
};
|
|
1335
|
+
_this.sendWindowWaiters.push({ resolve: resolveWrap, reject: rejectWrap });
|
|
1223
1336
|
});
|
|
1224
1337
|
};
|
|
1225
1338
|
// 处理单个帧
|
|
1226
1339
|
HTTP2Parser.prototype._handleFrame = function (frameHeader, frameData) {
|
|
1227
1340
|
return __awaiter(this, void 0, void 0, function () {
|
|
1228
|
-
var settingsPayload, settings, initialWindowDelta_1, maxConcurrentStreams, i, id, value, payload,
|
|
1341
|
+
var settingsPayload, settings, initialWindowDelta_1, maxConcurrentStreams, i, id, value, payload, dataLength, streamWindowUpdate, connWindowUpdate, result, cur, info, body, view, lastStreamId, errorCode;
|
|
1229
1342
|
var _this = this;
|
|
1230
|
-
var _a, _b, _c, _d, _e;
|
|
1231
|
-
return __generator(this, function (
|
|
1343
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1344
|
+
return __generator(this, function (_h) {
|
|
1232
1345
|
switch (frameHeader.type) {
|
|
1233
1346
|
case FRAME_TYPES.SETTINGS:
|
|
1234
1347
|
if ((frameHeader.flags & FRAME_FLAGS.ACK) === FRAME_FLAGS.ACK) {
|
|
1235
|
-
this.
|
|
1348
|
+
this._notifySettingsAck();
|
|
1236
1349
|
}
|
|
1237
1350
|
else {
|
|
1238
1351
|
settingsPayload = frameData.slice(9);
|
|
@@ -1241,10 +1354,10 @@
|
|
|
1241
1354
|
maxConcurrentStreams = void 0;
|
|
1242
1355
|
for (i = 0; i < settingsPayload.length; i += 6) {
|
|
1243
1356
|
id = (settingsPayload[i] << 8) | settingsPayload[i + 1];
|
|
1244
|
-
value = (settingsPayload[i + 2] << 24) |
|
|
1357
|
+
value = ((settingsPayload[i + 2] << 24) |
|
|
1245
1358
|
(settingsPayload[i + 3] << 16) |
|
|
1246
1359
|
(settingsPayload[i + 4] << 8) |
|
|
1247
|
-
settingsPayload[i + 5];
|
|
1360
|
+
settingsPayload[i + 5]) >>> 0;
|
|
1248
1361
|
settings[id] = value;
|
|
1249
1362
|
if (id === 4) {
|
|
1250
1363
|
// SETTINGS_INITIAL_WINDOW_SIZE
|
|
@@ -1283,45 +1396,41 @@
|
|
|
1283
1396
|
if (this.onSettings) {
|
|
1284
1397
|
this.onSettings(frameHeader);
|
|
1285
1398
|
}
|
|
1286
|
-
// 标记已收到对端 SETTINGS
|
|
1287
|
-
this.
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
fn();
|
|
1291
|
-
}
|
|
1292
|
-
catch (e) {
|
|
1293
|
-
console.debug('waiter error', e);
|
|
1294
|
-
} });
|
|
1399
|
+
// 标记已收到对端 SETTINGS 并唤醒等待者
|
|
1400
|
+
this._notifyPeerSettings();
|
|
1401
|
+
// 唤醒发送窗口等待者(以防部分实现通过 SETTINGS 改变有效窗口)
|
|
1402
|
+
this._wakeWindowWaiters();
|
|
1295
1403
|
}
|
|
1296
1404
|
break;
|
|
1297
|
-
case FRAME_TYPES.DATA:
|
|
1405
|
+
case FRAME_TYPES.DATA: {
|
|
1298
1406
|
// 处理数据帧
|
|
1299
1407
|
if (this.onData) {
|
|
1300
1408
|
this.onData(frameData.slice(9), frameHeader); // 跳过帧头
|
|
1301
1409
|
}
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1410
|
+
dataLength = (_a = frameHeader.length) !== null && _a !== void 0 ? _a : 0;
|
|
1411
|
+
if (dataLength > 0) {
|
|
1412
|
+
try {
|
|
1413
|
+
// 更新流级别的窗口
|
|
1414
|
+
if (frameHeader.streamId !== 0) {
|
|
1415
|
+
streamWindowUpdate = Http2Frame.createWindowUpdateFrame(frameHeader.streamId, dataLength);
|
|
1416
|
+
this.writer.write(streamWindowUpdate);
|
|
1417
|
+
}
|
|
1418
|
+
connWindowUpdate = Http2Frame.createWindowUpdateFrame(0, dataLength);
|
|
1419
|
+
this.writer.write(connWindowUpdate);
|
|
1420
|
+
}
|
|
1421
|
+
catch (err) {
|
|
1422
|
+
console.error("[HTTP2] Error sending window update:", err);
|
|
1308
1423
|
}
|
|
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
1424
|
}
|
|
1315
1425
|
//判断是否是最后一个帧
|
|
1316
1426
|
if ((frameHeader.flags & FRAME_FLAGS.END_STREAM) ===
|
|
1317
1427
|
FRAME_FLAGS.END_STREAM) {
|
|
1318
|
-
this.
|
|
1319
|
-
|
|
1320
|
-
this.onEnd();
|
|
1321
|
-
}
|
|
1428
|
+
(_b = this.onEnd) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
1429
|
+
this._notifyEndOfStream();
|
|
1322
1430
|
return [2 /*return*/];
|
|
1323
1431
|
}
|
|
1324
1432
|
break;
|
|
1433
|
+
}
|
|
1325
1434
|
case FRAME_TYPES.HEADERS:
|
|
1326
1435
|
// 处理头部帧
|
|
1327
1436
|
if (this.onHeaders) {
|
|
@@ -1330,35 +1439,26 @@
|
|
|
1330
1439
|
//判断是否是最后一个帧
|
|
1331
1440
|
if ((frameHeader.flags & FRAME_FLAGS.END_STREAM) ===
|
|
1332
1441
|
FRAME_FLAGS.END_STREAM) {
|
|
1333
|
-
this.
|
|
1334
|
-
|
|
1335
|
-
this.onEnd();
|
|
1336
|
-
}
|
|
1442
|
+
(_c = this.onEnd) === null || _c === void 0 ? void 0 : _c.call(this);
|
|
1443
|
+
this._notifyEndOfStream();
|
|
1337
1444
|
return [2 /*return*/];
|
|
1338
1445
|
}
|
|
1339
1446
|
break;
|
|
1340
1447
|
case FRAME_TYPES.WINDOW_UPDATE:
|
|
1341
|
-
//
|
|
1342
|
-
this.handleWindowUpdateFrame(frameHeader, frameData);
|
|
1343
|
-
// 更新发送窗口(对端接收窗口)
|
|
1448
|
+
// 处理窗口更新帧(同时更新接收侧诊断计数器和发送侧流控窗口,只解析一次)
|
|
1344
1449
|
try {
|
|
1345
|
-
|
|
1450
|
+
result = this.handleWindowUpdateFrame(frameHeader, frameData);
|
|
1451
|
+
// 更新发送方向窗口(对端的接收窗口)
|
|
1346
1452
|
if (frameHeader.streamId === 0) {
|
|
1347
|
-
this.sendConnWindow +=
|
|
1453
|
+
this.sendConnWindow += result.windowSizeIncrement;
|
|
1348
1454
|
}
|
|
1349
1455
|
else {
|
|
1350
|
-
cur = (
|
|
1351
|
-
this.sendStreamWindows.set(frameHeader.streamId, cur +
|
|
1456
|
+
cur = (_d = this.sendStreamWindows.get(frameHeader.streamId)) !== null && _d !== void 0 ? _d : this.peerInitialStreamWindow;
|
|
1457
|
+
this.sendStreamWindows.set(frameHeader.streamId, cur + result.windowSizeIncrement);
|
|
1352
1458
|
}
|
|
1353
|
-
|
|
1354
|
-
waiters.forEach(function (fn) { try {
|
|
1355
|
-
fn();
|
|
1356
|
-
}
|
|
1357
|
-
catch (e) {
|
|
1358
|
-
console.debug('waiter error', e);
|
|
1359
|
-
} });
|
|
1459
|
+
this._wakeWindowWaiters();
|
|
1360
1460
|
}
|
|
1361
|
-
catch ( /* ignore WINDOW_UPDATE parse errors */
|
|
1461
|
+
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
1462
|
break;
|
|
1363
1463
|
case FRAME_TYPES.PING:
|
|
1364
1464
|
// 处理PING帧
|
|
@@ -1380,20 +1480,20 @@
|
|
|
1380
1480
|
info = {};
|
|
1381
1481
|
}
|
|
1382
1482
|
}
|
|
1383
|
-
catch ( /* ignore GOAWAY parse errors */
|
|
1483
|
+
catch ( /* ignore GOAWAY parse errors */_k) { /* ignore GOAWAY parse errors */ }
|
|
1384
1484
|
try {
|
|
1385
|
-
(
|
|
1485
|
+
(_e = this.onGoaway) === null || _e === void 0 ? void 0 : _e.call(this, info !== null && info !== void 0 ? info : {});
|
|
1386
1486
|
}
|
|
1387
1487
|
catch (err) {
|
|
1388
1488
|
console.error('Error during GOAWAY callback:', err);
|
|
1389
1489
|
}
|
|
1390
|
-
this.endFlag = true;
|
|
1391
1490
|
try {
|
|
1392
|
-
(
|
|
1491
|
+
(_f = this.onEnd) === null || _f === void 0 ? void 0 : _f.call(this);
|
|
1393
1492
|
}
|
|
1394
1493
|
catch (err) {
|
|
1395
1494
|
console.error('Error during GOAWAY onEnd callback:', err);
|
|
1396
1495
|
}
|
|
1496
|
+
this._notifyEndOfStream();
|
|
1397
1497
|
break;
|
|
1398
1498
|
}
|
|
1399
1499
|
// case FRAME_TYPES.PUSH_PROMISE:
|
|
@@ -1401,10 +1501,8 @@
|
|
|
1401
1501
|
// this.handlePushPromiseFrame(frameHeader, frameData);
|
|
1402
1502
|
// break;
|
|
1403
1503
|
case FRAME_TYPES.RST_STREAM:
|
|
1404
|
-
this.
|
|
1405
|
-
|
|
1406
|
-
this.onEnd();
|
|
1407
|
-
}
|
|
1504
|
+
(_g = this.onEnd) === null || _g === void 0 ? void 0 : _g.call(this);
|
|
1505
|
+
this._notifyEndOfStream();
|
|
1408
1506
|
break;
|
|
1409
1507
|
default:
|
|
1410
1508
|
console.debug("Unknown frame type:", frameHeader.type);
|
|
@@ -1417,7 +1515,8 @@
|
|
|
1417
1515
|
var length = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
|
|
1418
1516
|
var type = buffer[3];
|
|
1419
1517
|
var flags = buffer[4];
|
|
1420
|
-
|
|
1518
|
+
// RFC 7540 §4.1: most significant bit is reserved and MUST be ignored on receipt
|
|
1519
|
+
var streamId = ((buffer[5] << 24) | (buffer[6] << 16) | (buffer[7] << 8) | buffer[8]) & 0x7fffffff;
|
|
1421
1520
|
return {
|
|
1422
1521
|
length: length,
|
|
1423
1522
|
type: type,
|
|
@@ -1446,53 +1545,42 @@
|
|
|
1446
1545
|
throw error;
|
|
1447
1546
|
}
|
|
1448
1547
|
};
|
|
1449
|
-
|
|
1548
|
+
// 等待流结束 — 事件驱动,onEnd 触发时直接唤醒,无 setInterval 轮询
|
|
1450
1549
|
HTTP2Parser.prototype.waitForEndOfStream = function (waitTime) {
|
|
1451
1550
|
var _this = this;
|
|
1452
1551
|
return new Promise(function (resolve, reject) {
|
|
1453
|
-
// If the stream has already ended, resolve immediately
|
|
1454
1552
|
if (_this.endFlag) {
|
|
1455
1553
|
resolve();
|
|
1456
1554
|
return;
|
|
1457
1555
|
}
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1556
|
+
var waiter = { resolve: resolve, reject: reject };
|
|
1557
|
+
_this.endOfStreamWaiters.push(waiter);
|
|
1558
|
+
var timeout = waitTime > 0
|
|
1559
|
+
? setTimeout(function () {
|
|
1560
|
+
var idx = _this.endOfStreamWaiters.indexOf(waiter);
|
|
1561
|
+
if (idx >= 0)
|
|
1562
|
+
_this.endOfStreamWaiters.splice(idx, 1);
|
|
1463
1563
|
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
|
-
};
|
|
1564
|
+
}, waitTime)
|
|
1565
|
+
: null;
|
|
1566
|
+
waiter.resolve = function () { if (timeout)
|
|
1567
|
+
clearTimeout(timeout); resolve(); };
|
|
1568
|
+
waiter.reject = function (e) { if (timeout)
|
|
1569
|
+
clearTimeout(timeout); reject(e); };
|
|
1494
1570
|
});
|
|
1495
1571
|
};
|
|
1572
|
+
/** 内部调用:流结束时唤醒所有 waitForEndOfStream 等待者 */
|
|
1573
|
+
HTTP2Parser.prototype._notifyEndOfStream = function () {
|
|
1574
|
+
this.endFlag = true;
|
|
1575
|
+
var ws = this.endOfStreamWaiters.splice(0);
|
|
1576
|
+
for (var _i = 0, ws_4 = ws; _i < ws_4.length; _i++) {
|
|
1577
|
+
var w = ws_4[_i];
|
|
1578
|
+
try {
|
|
1579
|
+
w.resolve();
|
|
1580
|
+
}
|
|
1581
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
1582
|
+
}
|
|
1583
|
+
};
|
|
1496
1584
|
// 解析 WINDOW_UPDATE 帧
|
|
1497
1585
|
HTTP2Parser.prototype.parseWindowUpdateFrame = function (frameBuffer, frameHeader) {
|
|
1498
1586
|
// WINDOW_UPDATE帧的payload固定为4字节
|
|
@@ -1886,6 +1974,8 @@
|
|
|
1886
1974
|
this.lastBytesDrainedSeen = 0;
|
|
1887
1975
|
this.lastBpWarnAt = 0;
|
|
1888
1976
|
this.isHandlingError = false; // 防止重复错误处理
|
|
1977
|
+
/** drain 事件驱动等待者,替代 flush() 中的 setInterval 轮询 */
|
|
1978
|
+
this.drainWaiters = [];
|
|
1889
1979
|
// 事件系统
|
|
1890
1980
|
this.listeners = new Map();
|
|
1891
1981
|
// 验证 stream 参数
|
|
@@ -2016,10 +2106,12 @@
|
|
|
2016
2106
|
_l.trys.push([4, 7, , 8]);
|
|
2017
2107
|
canContinue = this.stream.send(chunk);
|
|
2018
2108
|
if (!!canContinue) return [3 /*break*/, 6];
|
|
2019
|
-
//
|
|
2020
|
-
|
|
2109
|
+
// 传入 abort signal,当流被 abort 时 onDrain() 会立即 reject,
|
|
2110
|
+
// 避免在 abort 路径下永久挂住
|
|
2111
|
+
return [4 /*yield*/, this.stream.onDrain({ signal: this.abortController.signal })];
|
|
2021
2112
|
case 5:
|
|
2022
|
-
//
|
|
2113
|
+
// 传入 abort signal,当流被 abort 时 onDrain() 会立即 reject,
|
|
2114
|
+
// 避免在 abort 路径下永久挂住
|
|
2023
2115
|
_l.sent();
|
|
2024
2116
|
_l.label = 6;
|
|
2025
2117
|
case 6: return [3 /*break*/, 8];
|
|
@@ -2054,7 +2146,11 @@
|
|
|
2054
2146
|
if (e_1) throw e_1.error;
|
|
2055
2147
|
return [7 /*endfinally*/];
|
|
2056
2148
|
case 15: return [7 /*endfinally*/];
|
|
2057
|
-
case 16:
|
|
2149
|
+
case 16:
|
|
2150
|
+
// pipeline 正常结束(stream 关闭或 pushable 耗尽)—— 确保资源清理
|
|
2151
|
+
// 若已通过 abort() 触发则 cleanup() 内部幂等处理
|
|
2152
|
+
this.cleanup();
|
|
2153
|
+
return [2 /*return*/];
|
|
2058
2154
|
}
|
|
2059
2155
|
});
|
|
2060
2156
|
});
|
|
@@ -2064,7 +2160,7 @@
|
|
|
2064
2160
|
var self = this;
|
|
2065
2161
|
return function (source) {
|
|
2066
2162
|
return __asyncGenerator(this, arguments, function () {
|
|
2067
|
-
var _a, source_1, source_1_1, chunk, now, e_2_1;
|
|
2163
|
+
var _a, source_1, source_1_1, chunk, now, ws, _i, ws_1, fn, e_2_1;
|
|
2068
2164
|
var _b, e_2, _c, _d;
|
|
2069
2165
|
return __generator(this, function (_e) {
|
|
2070
2166
|
switch (_e.label) {
|
|
@@ -2101,6 +2197,17 @@
|
|
|
2101
2197
|
self.lastDrainEventAt = now;
|
|
2102
2198
|
self.dispatchEvent(new CustomEvent('drain', { detail: { drained: self.bytesDrained, queueSize: self.queueSize } }));
|
|
2103
2199
|
}
|
|
2200
|
+
// 唤醒所有在等 flush() 或背压解除 的 drainWaiters(队列降低时就可唤醒)
|
|
2201
|
+
if (self.drainWaiters.length > 0) {
|
|
2202
|
+
ws = self.drainWaiters.splice(0);
|
|
2203
|
+
for (_i = 0, ws_1 = ws; _i < ws_1.length; _i++) {
|
|
2204
|
+
fn = ws_1[_i];
|
|
2205
|
+
try {
|
|
2206
|
+
fn();
|
|
2207
|
+
}
|
|
2208
|
+
catch ( /* ignore */_f) { /* ignore */ }
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2104
2211
|
// 记录本次已消耗字节,用于看门狗判断是否前进
|
|
2105
2212
|
self.lastBytesDrainedSeen = self.bytesDrained;
|
|
2106
2213
|
}
|
|
@@ -2237,17 +2344,17 @@
|
|
|
2237
2344
|
};
|
|
2238
2345
|
StreamWriter.prototype.writeChunks = function (buffer) {
|
|
2239
2346
|
return __awaiter(this, void 0, void 0, function () {
|
|
2240
|
-
var offset, end, chunk;
|
|
2347
|
+
var src, offset, end, chunk;
|
|
2241
2348
|
return __generator(this, function (_a) {
|
|
2242
2349
|
switch (_a.label) {
|
|
2243
2350
|
case 0:
|
|
2351
|
+
src = new Uint8Array(buffer);
|
|
2244
2352
|
offset = 0;
|
|
2245
2353
|
_a.label = 1;
|
|
2246
2354
|
case 1:
|
|
2247
|
-
if (!(offset <
|
|
2248
|
-
end = Math.min(offset + this.options.chunkSize,
|
|
2249
|
-
chunk =
|
|
2250
|
-
chunk.set(new Uint8Array(buffer.slice(offset, end)));
|
|
2355
|
+
if (!(offset < src.byteLength)) return [3 /*break*/, 4];
|
|
2356
|
+
end = Math.min(offset + this.options.chunkSize, src.byteLength);
|
|
2357
|
+
chunk = src.subarray(offset, end);
|
|
2251
2358
|
return [4 /*yield*/, this.retryableWrite(chunk)];
|
|
2252
2359
|
case 2:
|
|
2253
2360
|
_a.sent();
|
|
@@ -2264,7 +2371,6 @@
|
|
|
2264
2371
|
StreamWriter.prototype.retryableWrite = function (chunk_1) {
|
|
2265
2372
|
return __awaiter(this, arguments, void 0, function (chunk, attempt) {
|
|
2266
2373
|
var currentSize, threshold, err_3, delay_1;
|
|
2267
|
-
var _this = this;
|
|
2268
2374
|
if (attempt === void 0) { attempt = 0; }
|
|
2269
2375
|
return __generator(this, function (_a) {
|
|
2270
2376
|
switch (_a.label) {
|
|
@@ -2275,7 +2381,7 @@
|
|
|
2275
2381
|
}
|
|
2276
2382
|
_a.label = 1;
|
|
2277
2383
|
case 1:
|
|
2278
|
-
_a.trys.push([1,
|
|
2384
|
+
_a.trys.push([1, 4, , 7]);
|
|
2279
2385
|
currentSize = this.queueSize;
|
|
2280
2386
|
threshold = this.options.bufferSize * 0.7;
|
|
2281
2387
|
if (!(currentSize > threshold)) return [3 /*break*/, 3];
|
|
@@ -2288,94 +2394,92 @@
|
|
|
2288
2394
|
if (this.abortController.signal.aborted) {
|
|
2289
2395
|
throw new Error('Stream aborted during backpressure monitoring');
|
|
2290
2396
|
}
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
}
|
|
2295
|
-
catch (err) {
|
|
2296
|
-
reject(err);
|
|
2297
|
-
}
|
|
2298
|
-
resolve();
|
|
2299
|
-
})];
|
|
2397
|
+
// push 是同步操作,直接调用即可
|
|
2398
|
+
this.p.push(chunk);
|
|
2399
|
+
return [3 /*break*/, 7];
|
|
2300
2400
|
case 4:
|
|
2301
|
-
_a.sent();
|
|
2302
|
-
return [3 /*break*/, 8];
|
|
2303
|
-
case 5:
|
|
2304
2401
|
err_3 = _a.sent();
|
|
2305
|
-
if (!(attempt < this.options.retries)) return [3 /*break*/,
|
|
2402
|
+
if (!(!this.abortController.signal.aborted && attempt < this.options.retries)) return [3 /*break*/, 6];
|
|
2306
2403
|
delay_1 = this.calculateRetryDelay(attempt);
|
|
2307
2404
|
return [4 /*yield*/, new Promise(function (r) { return setTimeout(r, delay_1); })];
|
|
2308
|
-
case
|
|
2405
|
+
case 5:
|
|
2309
2406
|
_a.sent();
|
|
2310
2407
|
return [2 /*return*/, this.retryableWrite(chunk, attempt + 1)];
|
|
2311
|
-
case
|
|
2312
|
-
case
|
|
2408
|
+
case 6: throw err_3;
|
|
2409
|
+
case 7: return [2 /*return*/];
|
|
2313
2410
|
}
|
|
2314
2411
|
});
|
|
2315
2412
|
});
|
|
2316
2413
|
};
|
|
2317
2414
|
StreamWriter.prototype.monitorBackpressure = function () {
|
|
2318
2415
|
return __awaiter(this, void 0, void 0, function () {
|
|
2319
|
-
var
|
|
2416
|
+
var baseThreshold, criticalThreshold, maxRounds, _loop_1, this_1, i, state_1, now;
|
|
2417
|
+
var _this = this;
|
|
2320
2418
|
return __generator(this, function (_a) {
|
|
2321
2419
|
switch (_a.label) {
|
|
2322
2420
|
case 0:
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
;
|
|
2328
|
-
// 快速路径:无背压时直接返回
|
|
2329
|
-
if (currentSize < baseThreshold) {
|
|
2421
|
+
baseThreshold = this.options.bufferSize * 0.7;
|
|
2422
|
+
criticalThreshold = this.options.bufferSize * 0.9;
|
|
2423
|
+
// 快速路径
|
|
2424
|
+
if (this.queueSize < baseThreshold) {
|
|
2330
2425
|
if (this.isBackpressure) {
|
|
2331
2426
|
this.isBackpressure = false;
|
|
2332
|
-
this.dispatchBackpressureEvent({
|
|
2333
|
-
currentSize: currentSize,
|
|
2334
|
-
averageSize: this.getAverageQueueSize(),
|
|
2335
|
-
threshold: baseThreshold,
|
|
2336
|
-
waitingTime: 0
|
|
2337
|
-
});
|
|
2427
|
+
this.dispatchBackpressureEvent({ currentSize: this.queueSize, averageSize: this.getAverageQueueSize(), threshold: baseThreshold, waitingTime: 0 });
|
|
2338
2428
|
}
|
|
2339
2429
|
return [2 /*return*/];
|
|
2340
2430
|
}
|
|
2341
|
-
// 进入背压状态
|
|
2342
2431
|
if (!this.isBackpressure) {
|
|
2343
2432
|
this.isBackpressure = true;
|
|
2344
|
-
this.dispatchBackpressureEvent({
|
|
2345
|
-
currentSize: currentSize,
|
|
2346
|
-
averageSize: this.getAverageQueueSize(),
|
|
2347
|
-
threshold: baseThreshold,
|
|
2348
|
-
waitingTime: 0
|
|
2349
|
-
});
|
|
2350
|
-
}
|
|
2351
|
-
pressure = currentSize / this.options.bufferSize;
|
|
2352
|
-
if (currentSize >= criticalThreshold) {
|
|
2353
|
-
// 临界状态:长时间等待
|
|
2354
|
-
waitTime = 50 + Math.min(200, pressure * 100);
|
|
2355
|
-
}
|
|
2356
|
-
else {
|
|
2357
|
-
// 轻度背压:短时间等待
|
|
2358
|
-
waitTime = Math.min(20, pressure * 30);
|
|
2433
|
+
this.dispatchBackpressureEvent({ currentSize: this.queueSize, averageSize: this.getAverageQueueSize(), threshold: baseThreshold, waitingTime: 0 });
|
|
2359
2434
|
}
|
|
2360
|
-
|
|
2361
|
-
|
|
2435
|
+
maxRounds = 3;
|
|
2436
|
+
_loop_1 = function (i) {
|
|
2437
|
+
var isCritical, waitMs;
|
|
2438
|
+
return __generator(this, function (_b) {
|
|
2439
|
+
switch (_b.label) {
|
|
2440
|
+
case 0:
|
|
2441
|
+
if (this_1.abortController.signal.aborted)
|
|
2442
|
+
return [2 /*return*/, "break"];
|
|
2443
|
+
if (this_1.queueSize < baseThreshold)
|
|
2444
|
+
return [2 /*return*/, "break"];
|
|
2445
|
+
isCritical = this_1.queueSize >= criticalThreshold;
|
|
2446
|
+
waitMs = isCritical ? 100 : 30;
|
|
2447
|
+
return [4 /*yield*/, new Promise(function (resolve) {
|
|
2448
|
+
var done = false;
|
|
2449
|
+
var timer = setTimeout(function () { if (!done) {
|
|
2450
|
+
done = true;
|
|
2451
|
+
resolve();
|
|
2452
|
+
} }, waitMs);
|
|
2453
|
+
_this.drainWaiters.push(function () { if (!done) {
|
|
2454
|
+
done = true;
|
|
2455
|
+
clearTimeout(timer);
|
|
2456
|
+
resolve();
|
|
2457
|
+
} });
|
|
2458
|
+
})];
|
|
2459
|
+
case 1:
|
|
2460
|
+
_b.sent();
|
|
2461
|
+
return [2 /*return*/];
|
|
2462
|
+
}
|
|
2463
|
+
});
|
|
2464
|
+
};
|
|
2465
|
+
this_1 = this;
|
|
2466
|
+
i = 0;
|
|
2362
2467
|
_a.label = 1;
|
|
2363
2468
|
case 1:
|
|
2364
|
-
if (!(
|
|
2365
|
-
|
|
2366
|
-
return [3 /*break*/, 3];
|
|
2367
|
-
return [4 /*yield*/, new Promise(function (r) { return setTimeout(r, waitTime); })];
|
|
2469
|
+
if (!(i < maxRounds)) return [3 /*break*/, 4];
|
|
2470
|
+
return [5 /*yield**/, _loop_1(i)];
|
|
2368
2471
|
case 2:
|
|
2369
|
-
_a.sent();
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
return [3 /*break*/, 1];
|
|
2472
|
+
state_1 = _a.sent();
|
|
2473
|
+
if (state_1 === "break")
|
|
2474
|
+
return [3 /*break*/, 4];
|
|
2475
|
+
_a.label = 3;
|
|
2374
2476
|
case 3:
|
|
2375
|
-
|
|
2477
|
+
i++;
|
|
2478
|
+
return [3 /*break*/, 1];
|
|
2479
|
+
case 4:
|
|
2376
2480
|
if (this.queueSize >= baseThreshold) {
|
|
2377
2481
|
now = Date.now();
|
|
2378
|
-
if (now - this.lastBpWarnAt > 1000) {
|
|
2482
|
+
if (now - this.lastBpWarnAt > 1000) {
|
|
2379
2483
|
this.lastBpWarnAt = now;
|
|
2380
2484
|
console.warn("Stream writer: High backpressure detected (".concat(this.queueSize, " bytes), continuing anyway"));
|
|
2381
2485
|
}
|
|
@@ -2503,15 +2607,27 @@
|
|
|
2503
2607
|
if (!this.abortController.signal.aborted) {
|
|
2504
2608
|
this.abortController.abort();
|
|
2505
2609
|
}
|
|
2506
|
-
//
|
|
2610
|
+
// 执行所有待处理的写入任务:它们会检查 signal.aborted 并立即 resolve,
|
|
2611
|
+
// 不执行的话调用方的 Promise 会永远挂住
|
|
2507
2612
|
var pendingTasks = this.writeQueue.splice(0);
|
|
2508
|
-
pendingTasks.
|
|
2509
|
-
|
|
2510
|
-
|
|
2613
|
+
for (var _i = 0, pendingTasks_1 = pendingTasks; _i < pendingTasks_1.length; _i++) {
|
|
2614
|
+
var task = pendingTasks_1[_i];
|
|
2615
|
+
task().catch(function () { });
|
|
2616
|
+
}
|
|
2617
|
+
// 唤醒所有 drainWaiters(flush / monitorBackpressure 中的等待者),
|
|
2618
|
+
// 让它们检查 signal.aborted 并立即 resolve,不必等到各自的超时
|
|
2619
|
+
var ws = this.drainWaiters.splice(0);
|
|
2620
|
+
for (var _a = 0, ws_2 = ws; _a < ws_2.length; _a++) {
|
|
2621
|
+
var fn = ws_2[_a];
|
|
2622
|
+
try {
|
|
2623
|
+
fn();
|
|
2624
|
+
}
|
|
2625
|
+
catch ( /* ignore */_b) { /* ignore */ }
|
|
2626
|
+
}
|
|
2511
2627
|
try {
|
|
2512
2628
|
this.p.end();
|
|
2513
2629
|
}
|
|
2514
|
-
catch (
|
|
2630
|
+
catch (_c) {
|
|
2515
2631
|
// Ignore errors when ending pushable
|
|
2516
2632
|
}
|
|
2517
2633
|
if (this.watchdogTimer) {
|
|
@@ -2523,30 +2639,49 @@
|
|
|
2523
2639
|
// 默认超时 10s,避免无限等待
|
|
2524
2640
|
StreamWriter.prototype.flush = function () {
|
|
2525
2641
|
return __awaiter(this, arguments, void 0, function (timeoutMs) {
|
|
2526
|
-
var
|
|
2642
|
+
var _this = this;
|
|
2527
2643
|
if (timeoutMs === void 0) { timeoutMs = 10000; }
|
|
2528
2644
|
return __generator(this, function (_a) {
|
|
2529
2645
|
switch (_a.label) {
|
|
2530
2646
|
case 0:
|
|
2531
|
-
start = Date.now();
|
|
2532
2647
|
// 快速路径
|
|
2533
2648
|
if (this.queueSize <= 0 && !this.isProcessingQueue && this.writeQueue.length === 0)
|
|
2534
2649
|
return [2 /*return*/];
|
|
2535
|
-
_a.label = 1;
|
|
2536
|
-
case 1:
|
|
2537
2650
|
if (this.abortController.signal.aborted)
|
|
2538
2651
|
return [2 /*return*/];
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2652
|
+
return [4 /*yield*/, new Promise(function (resolve) {
|
|
2653
|
+
// 已经清空
|
|
2654
|
+
if (_this.queueSize <= 0 && !_this.isProcessingQueue && _this.writeQueue.length === 0) {
|
|
2655
|
+
resolve();
|
|
2656
|
+
return;
|
|
2657
|
+
}
|
|
2658
|
+
var done = false;
|
|
2659
|
+
var timer = setTimeout(function () {
|
|
2660
|
+
if (!done) {
|
|
2661
|
+
done = true;
|
|
2662
|
+
console.warn("Stream writer: flush timeout with ".concat(_this.queueSize, " bytes still queued"));
|
|
2663
|
+
resolve();
|
|
2664
|
+
}
|
|
2665
|
+
}, timeoutMs);
|
|
2666
|
+
// 由 createTransform 在每个 chunk 被下游消耗后唤醒
|
|
2667
|
+
var check = function () {
|
|
2668
|
+
if (_this.abortController.signal.aborted || (_this.queueSize <= 0 && !_this.isProcessingQueue && _this.writeQueue.length === 0)) {
|
|
2669
|
+
if (!done) {
|
|
2670
|
+
done = true;
|
|
2671
|
+
clearTimeout(timer);
|
|
2672
|
+
resolve();
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
else {
|
|
2676
|
+
// 下次 drain 时再检查
|
|
2677
|
+
_this.drainWaiters.push(check);
|
|
2678
|
+
}
|
|
2679
|
+
};
|
|
2680
|
+
_this.drainWaiters.push(check);
|
|
2681
|
+
})];
|
|
2682
|
+
case 1:
|
|
2547
2683
|
_a.sent();
|
|
2548
|
-
return [
|
|
2549
|
-
case 3: return [2 /*return*/];
|
|
2684
|
+
return [2 /*return*/];
|
|
2550
2685
|
}
|
|
2551
2686
|
});
|
|
2552
2687
|
});
|
|
@@ -2855,45 +2990,65 @@
|
|
|
2855
2990
|
Libp2pGrpcClient.prototype.setToken = function (token) {
|
|
2856
2991
|
this.token = token;
|
|
2857
2992
|
};
|
|
2993
|
+
/** 从 peerAddr 提取 HTTP/2 :authority 字段(host:port 格式) */
|
|
2994
|
+
Libp2pGrpcClient.prototype.getAuthority = function () {
|
|
2995
|
+
try {
|
|
2996
|
+
var addr = this.peerAddr.toString();
|
|
2997
|
+
var ip4 = addr.match(/\/ip4\/(\d[\d.]+)\/tcp\/(\d+)/);
|
|
2998
|
+
if (ip4)
|
|
2999
|
+
return "".concat(ip4[1], ":").concat(ip4[2]);
|
|
3000
|
+
var ip6 = addr.match(/\/ip6\/([^/]+)\/tcp\/(\d+)/);
|
|
3001
|
+
if (ip6)
|
|
3002
|
+
return "[".concat(ip6[1], "]:").concat(ip6[2]);
|
|
3003
|
+
var dns = addr.match(/\/dns(?:4|6)?\/([.\w-]+)\/tcp\/(\d+)/);
|
|
3004
|
+
if (dns)
|
|
3005
|
+
return "".concat(dns[1], ":").concat(dns[2]);
|
|
3006
|
+
}
|
|
3007
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
3008
|
+
return 'localhost';
|
|
3009
|
+
};
|
|
2858
3010
|
Libp2pGrpcClient.prototype.unaryCall = function (method_1, requestData_1) {
|
|
2859
3011
|
return __awaiter(this, arguments, void 0, function (method, requestData, timeout) {
|
|
2860
|
-
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;
|
|
3012
|
+
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;
|
|
2861
3013
|
var _this = this;
|
|
2862
3014
|
if (timeout === void 0) { timeout = 30000; }
|
|
2863
|
-
return __generator(this, function (
|
|
2864
|
-
switch (
|
|
3015
|
+
return __generator(this, function (_c) {
|
|
3016
|
+
switch (_c.label) {
|
|
2865
3017
|
case 0:
|
|
2866
3018
|
stream = null;
|
|
2867
3019
|
responseData = null;
|
|
2868
3020
|
responseBuffer = [];
|
|
2869
3021
|
responseDataExpectedLength = -1;
|
|
3022
|
+
headerPartialBuffer = [];
|
|
2870
3023
|
hpack = new HPACK();
|
|
2871
3024
|
exitFlag = false;
|
|
2872
3025
|
errMsg = "";
|
|
2873
3026
|
isResponseComplete = false;
|
|
3027
|
+
notifyResponseComplete = null;
|
|
2874
3028
|
connection = null;
|
|
2875
3029
|
state = null;
|
|
2876
3030
|
streamSlotAcquired = false;
|
|
2877
|
-
|
|
3031
|
+
writerRef = null;
|
|
3032
|
+
_c.label = 1;
|
|
2878
3033
|
case 1:
|
|
2879
|
-
|
|
3034
|
+
_c.trys.push([1, 23, 24, 29]);
|
|
2880
3035
|
return [4 /*yield*/, this.acquireConnection(false)];
|
|
2881
3036
|
case 2:
|
|
2882
3037
|
// const stream = await this.node.dialProtocol(this.peerAddr, this.protocol)
|
|
2883
|
-
connection =
|
|
3038
|
+
connection = _c.sent();
|
|
2884
3039
|
connectionKey_1 = this.peerAddr.toString();
|
|
2885
3040
|
state = this.getConnectionState(connection);
|
|
2886
|
-
|
|
3041
|
+
_c.label = 3;
|
|
2887
3042
|
case 3:
|
|
2888
|
-
|
|
3043
|
+
_c.trys.push([3, 5, , 6]);
|
|
2889
3044
|
return [4 /*yield*/, this.waitForStreamSlot(state, undefined, timeout)];
|
|
2890
3045
|
case 4:
|
|
2891
|
-
|
|
3046
|
+
_c.sent();
|
|
2892
3047
|
state.activeStreams += 1;
|
|
2893
3048
|
streamSlotAcquired = true;
|
|
2894
3049
|
return [3 /*break*/, 6];
|
|
2895
3050
|
case 5:
|
|
2896
|
-
err_2 =
|
|
3051
|
+
err_2 = _c.sent();
|
|
2897
3052
|
console.warn("[unaryCall] waiting for stream slot failed:", err_2);
|
|
2898
3053
|
throw err_2;
|
|
2899
3054
|
case 6: return [4 /*yield*/, connection.newStream(this.protocol, {
|
|
@@ -2901,14 +3056,15 @@
|
|
|
2901
3056
|
negotiateFully: false,
|
|
2902
3057
|
})];
|
|
2903
3058
|
case 7:
|
|
2904
|
-
stream =
|
|
3059
|
+
stream = _c.sent();
|
|
2905
3060
|
streamManager = this.getStreamManagerFor(connection);
|
|
2906
3061
|
return [4 /*yield*/, streamManager.getNextAppLevelStreamId()];
|
|
2907
3062
|
case 8:
|
|
2908
|
-
streamId_1 =
|
|
3063
|
+
streamId_1 = _c.sent();
|
|
2909
3064
|
writer_1 = new StreamWriter(stream, {
|
|
2910
3065
|
bufferSize: 16 * 1024 * 1024,
|
|
2911
3066
|
});
|
|
3067
|
+
writerRef = writer_1;
|
|
2912
3068
|
try {
|
|
2913
3069
|
writer_1.addEventListener("backpressure", function (e) {
|
|
2914
3070
|
var d = e.detail || {};
|
|
@@ -2930,7 +3086,7 @@
|
|
|
2930
3086
|
catch ( /* ignore ping write errors */_b) { /* ignore ping write errors */ }
|
|
2931
3087
|
});
|
|
2932
3088
|
}
|
|
2933
|
-
catch ( /* ignore addEventListener errors */
|
|
3089
|
+
catch ( /* ignore addEventListener errors */_d) { /* ignore addEventListener errors */ }
|
|
2934
3090
|
parser = new HTTP2Parser(writer_1);
|
|
2935
3091
|
parser.onGoaway = function (info) {
|
|
2936
3092
|
console.warn("[unaryCall] GOAWAY received from server", info);
|
|
@@ -2940,6 +3096,7 @@
|
|
|
2940
3096
|
}
|
|
2941
3097
|
exitFlag = true;
|
|
2942
3098
|
errMsg = "GOAWAY received: code=".concat(info.errorCode);
|
|
3099
|
+
notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete(); // 唤醒等待中的 Promise
|
|
2943
3100
|
try {
|
|
2944
3101
|
connection === null || connection === void 0 ? void 0 : connection.close();
|
|
2945
3102
|
}
|
|
@@ -2958,86 +3115,99 @@
|
|
|
2958
3115
|
parser.registerOutboundStream(streamId_1);
|
|
2959
3116
|
responseDataExpectedLength = -1; // 重置期望长度
|
|
2960
3117
|
responseBuffer = []; // 重置缓冲区
|
|
3118
|
+
headerPartialBuffer = []; // 重置跨帧头部缓冲
|
|
2961
3119
|
parser.onData = function (payload, frameHeader) {
|
|
2962
3120
|
//接收数据
|
|
2963
3121
|
if (responseDataExpectedLength === -1) {
|
|
2964
3122
|
//grpc消息头部未读取
|
|
3123
|
+
// 如果有跨帧积累的部分头字节,先与本帧 payload 合并
|
|
3124
|
+
var effectivePayload = payload;
|
|
3125
|
+
if (headerPartialBuffer.length > 0) {
|
|
3126
|
+
headerPartialBuffer.push(payload);
|
|
3127
|
+
var totalLen = headerPartialBuffer.reduce(function (s, c) { return s + c.length; }, 0);
|
|
3128
|
+
effectivePayload = new Uint8Array(totalLen);
|
|
3129
|
+
var off = 0;
|
|
3130
|
+
for (var _i = 0, headerPartialBuffer_1 = headerPartialBuffer; _i < headerPartialBuffer_1.length; _i++) {
|
|
3131
|
+
var c = headerPartialBuffer_1[_i];
|
|
3132
|
+
effectivePayload.set(c, off);
|
|
3133
|
+
off += c.length;
|
|
3134
|
+
}
|
|
3135
|
+
headerPartialBuffer = [];
|
|
3136
|
+
}
|
|
2965
3137
|
//提取gRPC消息头部
|
|
2966
|
-
if (
|
|
3138
|
+
if (effectivePayload.length < 5) {
|
|
3139
|
+
// 头部字节不足 5,先缓存,等待后续帧补全
|
|
3140
|
+
headerPartialBuffer.push(effectivePayload);
|
|
2967
3141
|
return;
|
|
2968
3142
|
}
|
|
2969
|
-
var lengthBytes =
|
|
2970
|
-
responseDataExpectedLength = new DataView(lengthBytes.buffer, lengthBytes.byteOffset).getUint32(0, false); // big-endian
|
|
2971
|
-
if (responseDataExpectedLength
|
|
2972
|
-
throw new Error("Invalid gRPC message length");
|
|
2973
|
-
}
|
|
2974
|
-
if (responseDataExpectedLength + 5 > payload.length) {
|
|
3143
|
+
var lengthBytes = effectivePayload.slice(1, 5); // 消息长度的4字节
|
|
3144
|
+
responseDataExpectedLength = new DataView(lengthBytes.buffer, lengthBytes.byteOffset).getUint32(0, false); // big-endian(getUint32 返回无符号整数,结果不会为负)
|
|
3145
|
+
if (responseDataExpectedLength + 5 > effectivePayload.length) {
|
|
2975
3146
|
// 如果当前 payload 不足以包含完整的 gRPC 消息,缓存数据
|
|
2976
|
-
var grpcData =
|
|
3147
|
+
var grpcData = effectivePayload.subarray(5);
|
|
2977
3148
|
responseBuffer.push(grpcData);
|
|
2978
3149
|
responseDataExpectedLength -= grpcData.length; // 更新期望长度
|
|
2979
3150
|
return;
|
|
2980
3151
|
}
|
|
2981
3152
|
else {
|
|
2982
|
-
//
|
|
2983
|
-
var
|
|
3153
|
+
// payload 已包含完整的 gRPC 消息体,精确截取(避免尾部多余字节污染)
|
|
3154
|
+
var msgLen = responseDataExpectedLength;
|
|
3155
|
+
var grpcData = effectivePayload.slice(5, 5 + msgLen);
|
|
2984
3156
|
responseBuffer.push(grpcData);
|
|
2985
3157
|
responseData = grpcData;
|
|
2986
3158
|
isResponseComplete = true;
|
|
2987
|
-
responseDataExpectedLength = -1;
|
|
3159
|
+
responseDataExpectedLength = -1;
|
|
3160
|
+
notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete();
|
|
2988
3161
|
}
|
|
2989
3162
|
}
|
|
2990
3163
|
else if (responseDataExpectedLength > 0) {
|
|
2991
3164
|
//grpc消息头部已读取
|
|
2992
|
-
|
|
2993
|
-
responseDataExpectedLength -= payload.length; // 更新期望长度
|
|
3165
|
+
responseDataExpectedLength -= payload.length;
|
|
2994
3166
|
if (responseDataExpectedLength <= 0) {
|
|
2995
|
-
//
|
|
3167
|
+
// 超收时截掉多余字节
|
|
3168
|
+
var exactPayload = responseDataExpectedLength < 0
|
|
3169
|
+
? payload.slice(0, payload.length + responseDataExpectedLength)
|
|
3170
|
+
: payload;
|
|
3171
|
+
responseBuffer.push(exactPayload);
|
|
2996
3172
|
responseData = new Uint8Array(responseBuffer.reduce(function (sum, chunk) { return sum + chunk.length; }, 0));
|
|
2997
3173
|
var offset = 0;
|
|
2998
|
-
for (var
|
|
2999
|
-
var chunk = responseBuffer_1[
|
|
3174
|
+
for (var _a = 0, responseBuffer_1 = responseBuffer; _a < responseBuffer_1.length; _a++) {
|
|
3175
|
+
var chunk = responseBuffer_1[_a];
|
|
3000
3176
|
responseData.set(chunk, offset);
|
|
3001
3177
|
offset += chunk.length;
|
|
3002
3178
|
}
|
|
3003
3179
|
responseDataExpectedLength = -1;
|
|
3004
|
-
isResponseComplete = true;
|
|
3180
|
+
isResponseComplete = true;
|
|
3181
|
+
notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete();
|
|
3005
3182
|
}
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
if (frameHeader && frameHeader.flags & 0x1 && !isResponseComplete) {
|
|
3009
|
-
// END_STREAM flag
|
|
3010
|
-
// 合并所有缓冲的数据
|
|
3011
|
-
var totalLength = responseBuffer.reduce(function (sum, chunk) { return sum + chunk.length; }, 0);
|
|
3012
|
-
responseData = new Uint8Array(totalLength);
|
|
3013
|
-
var offset = 0;
|
|
3014
|
-
for (var _a = 0, responseBuffer_2 = responseBuffer; _a < responseBuffer_2.length; _a++) {
|
|
3015
|
-
var chunk = responseBuffer_2[_a];
|
|
3016
|
-
responseData.set(chunk, offset);
|
|
3017
|
-
offset += chunk.length;
|
|
3183
|
+
else {
|
|
3184
|
+
responseBuffer.push(payload); // 还不完整,继续累积
|
|
3018
3185
|
}
|
|
3019
|
-
isResponseComplete = true;
|
|
3020
3186
|
}
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
isResponseComplete = true; // 设置响应完成标志
|
|
3026
|
-
if (responseBuffer.length === 0) {
|
|
3027
|
-
responseData = new Uint8Array(); // 如果没有数据,返回空数组
|
|
3028
|
-
}
|
|
3029
|
-
else {
|
|
3030
|
-
// 合并所有缓冲的数据
|
|
3031
|
-
var totalLength = responseBuffer.reduce(function (sum, chunk) { return sum + chunk.length; }, 0);
|
|
3187
|
+
// END_STREAM 兜底:数据路径已处理大多数情况;此分支仅在边缘情况下触发
|
|
3188
|
+
if (frameHeader && frameHeader.flags & 0x1 && !isResponseComplete) {
|
|
3189
|
+
if (responseBuffer.length > 0) {
|
|
3190
|
+
var totalLength = responseBuffer.reduce(function (sum, c) { return sum + c.length; }, 0);
|
|
3032
3191
|
responseData = new Uint8Array(totalLength);
|
|
3033
3192
|
var offset = 0;
|
|
3034
|
-
for (var
|
|
3035
|
-
var chunk =
|
|
3193
|
+
for (var _b = 0, responseBuffer_2 = responseBuffer; _b < responseBuffer_2.length; _b++) {
|
|
3194
|
+
var chunk = responseBuffer_2[_b];
|
|
3036
3195
|
responseData.set(chunk, offset);
|
|
3037
3196
|
offset += chunk.length;
|
|
3038
3197
|
}
|
|
3039
|
-
isResponseComplete = true;
|
|
3040
3198
|
}
|
|
3199
|
+
else {
|
|
3200
|
+
responseData = new Uint8Array(0);
|
|
3201
|
+
}
|
|
3202
|
+
isResponseComplete = true;
|
|
3203
|
+
notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete();
|
|
3204
|
+
}
|
|
3205
|
+
};
|
|
3206
|
+
parser.onEnd = function () {
|
|
3207
|
+
// 流结束时若响应未标记完成(空响应 / 纯 trailers),强制标记并唤醒等待者
|
|
3208
|
+
if (!isResponseComplete) {
|
|
3209
|
+
isResponseComplete = true;
|
|
3210
|
+
notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete();
|
|
3041
3211
|
}
|
|
3042
3212
|
};
|
|
3043
3213
|
parser.onSettings = function () {
|
|
@@ -3051,103 +3221,124 @@
|
|
|
3051
3221
|
else if (plainHeaders.get("grpc-status") !== undefined) {
|
|
3052
3222
|
exitFlag = true;
|
|
3053
3223
|
errMsg = plainHeaders.get("grpc-message") || "gRPC call failed";
|
|
3224
|
+
notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete(); // 唤醒等待中的 Promise
|
|
3054
3225
|
}
|
|
3055
3226
|
};
|
|
3056
3227
|
// 启动后台流处理,捕获任何异步错误
|
|
3057
3228
|
parser.processStream(stream).catch(function (error) {
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3229
|
+
// 若响应已完整收到(isResponseComplete=true),后置的网络层错误属于正常的
|
|
3230
|
+
// 连接拆除过程(如服务端 RST、连接关闭),不影响已成功的调用结果,静默忽略。
|
|
3231
|
+
// 若响应尚未完成,才记录错误并唤醒等待者,触发超时/错误路径。
|
|
3232
|
+
if (!isResponseComplete) {
|
|
3233
|
+
console.error('Error in processStream:', error);
|
|
3234
|
+
exitFlag = true;
|
|
3235
|
+
if (!errMsg) {
|
|
3236
|
+
errMsg = error instanceof Error ? error.message : 'Stream processing failed';
|
|
3237
|
+
}
|
|
3238
|
+
notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete(); // 流处理异常也需唤醒等待者
|
|
3062
3239
|
}
|
|
3063
3240
|
});
|
|
3064
3241
|
preface = Http2Frame.createPreface();
|
|
3065
3242
|
return [4 /*yield*/, writer_1.write(preface)];
|
|
3066
3243
|
case 9:
|
|
3067
|
-
|
|
3244
|
+
_c.sent();
|
|
3068
3245
|
settingFrme = Http2Frame.createSettingsFrame();
|
|
3069
3246
|
return [4 /*yield*/, writer_1.write(settingFrme)];
|
|
3070
3247
|
case 10:
|
|
3071
|
-
|
|
3248
|
+
_c.sent();
|
|
3072
3249
|
// 等待对端 SETTINGS 或 ACK,择一即可,避免偶发握手竞态
|
|
3250
|
+
// 注意:未胜出的 promise 内部有超时定时器,它们最终会 reject。
|
|
3251
|
+
// 必须绑定 .catch(…) 消除错误,否则在 Node.js 新版本中会导致 UnhandledPromiseRejection 崩溃。
|
|
3073
3252
|
return [4 /*yield*/, Promise.race([
|
|
3074
|
-
parser.waitForPeerSettings(1000),
|
|
3075
|
-
parser.waitForSettingsAck(),
|
|
3253
|
+
parser.waitForPeerSettings(1000).catch(function () { }),
|
|
3254
|
+
parser.waitForSettingsAck().catch(function () { }),
|
|
3076
3255
|
new Promise(function (res) { return setTimeout(res, 300); }),
|
|
3077
3256
|
])];
|
|
3078
3257
|
case 11:
|
|
3079
3258
|
// 等待对端 SETTINGS 或 ACK,择一即可,避免偶发握手竞态
|
|
3080
|
-
|
|
3081
|
-
|
|
3259
|
+
// 注意:未胜出的 promise 内部有超时定时器,它们最终会 reject。
|
|
3260
|
+
// 必须绑定 .catch(…) 消除错误,否则在 Node.js 新版本中会导致 UnhandledPromiseRejection 崩溃。
|
|
3261
|
+
_c.sent();
|
|
3262
|
+
headerFrame = Http2Frame.createHeadersFrame(streamId_1, method, true, this.token, this.getAuthority());
|
|
3082
3263
|
return [4 /*yield*/, writer_1.write(headerFrame)];
|
|
3083
3264
|
case 12:
|
|
3084
|
-
|
|
3265
|
+
_c.sent();
|
|
3085
3266
|
dataFrames = Http2Frame.createDataFrames(streamId_1, requestData, true);
|
|
3086
3267
|
frameSendTimeout = timeout > 0 ? timeout : DEFAULT_SEND_WINDOW_TIMEOUT;
|
|
3087
3268
|
_i = 0, dataFrames_1 = dataFrames;
|
|
3088
|
-
|
|
3269
|
+
_c.label = 13;
|
|
3089
3270
|
case 13:
|
|
3090
3271
|
if (!(_i < dataFrames_1.length)) return [3 /*break*/, 16];
|
|
3091
3272
|
df = dataFrames_1[_i];
|
|
3092
3273
|
return [4 /*yield*/, this.sendFrameWithFlowControl(parser, streamId_1, df, writer_1, undefined, frameSendTimeout)];
|
|
3093
3274
|
case 14:
|
|
3094
|
-
|
|
3095
|
-
|
|
3275
|
+
_c.sent();
|
|
3276
|
+
_c.label = 15;
|
|
3096
3277
|
case 15:
|
|
3097
3278
|
_i++;
|
|
3098
3279
|
return [3 /*break*/, 13];
|
|
3099
3280
|
case 16:
|
|
3100
|
-
// 等待responseData
|
|
3281
|
+
// 等待 responseData 不为空,或超时(事件驱动,不轮询)
|
|
3101
3282
|
return [4 /*yield*/, new Promise(function (resolve, reject) {
|
|
3283
|
+
if (isResponseComplete || exitFlag) {
|
|
3284
|
+
resolve();
|
|
3285
|
+
return;
|
|
3286
|
+
}
|
|
3102
3287
|
var t = setTimeout(function () {
|
|
3288
|
+
notifyResponseComplete = null;
|
|
3103
3289
|
reject(new Error("gRPC response timeout"));
|
|
3104
3290
|
}, timeout);
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
resolve(responseData);
|
|
3110
|
-
}
|
|
3111
|
-
else {
|
|
3112
|
-
setTimeout(checkResponse, 50);
|
|
3113
|
-
}
|
|
3291
|
+
notifyResponseComplete = function () {
|
|
3292
|
+
clearTimeout(t);
|
|
3293
|
+
notifyResponseComplete = null;
|
|
3294
|
+
resolve();
|
|
3114
3295
|
};
|
|
3115
|
-
checkResponse();
|
|
3116
3296
|
})];
|
|
3117
3297
|
case 17:
|
|
3118
|
-
// 等待responseData
|
|
3119
|
-
|
|
3120
|
-
|
|
3298
|
+
// 等待 responseData 不为空,或超时(事件驱动,不轮询)
|
|
3299
|
+
_c.sent();
|
|
3300
|
+
_c.label = 18;
|
|
3121
3301
|
case 18:
|
|
3122
|
-
|
|
3302
|
+
_c.trys.push([18, 20, , 21]);
|
|
3123
3303
|
return [4 /*yield*/, writer_1.flush(timeout)];
|
|
3124
3304
|
case 19:
|
|
3125
|
-
|
|
3305
|
+
_c.sent();
|
|
3126
3306
|
return [3 /*break*/, 21];
|
|
3127
3307
|
case 20:
|
|
3128
|
-
|
|
3308
|
+
_c.sent();
|
|
3129
3309
|
return [3 /*break*/, 21];
|
|
3130
3310
|
case 21: return [4 /*yield*/, writer_1.end()];
|
|
3131
3311
|
case 22:
|
|
3132
|
-
|
|
3133
|
-
return [3 /*break*/,
|
|
3312
|
+
_c.sent();
|
|
3313
|
+
return [3 /*break*/, 29];
|
|
3134
3314
|
case 23:
|
|
3135
|
-
err_3 =
|
|
3315
|
+
err_3 = _c.sent();
|
|
3136
3316
|
console.error("unaryCall error:", err_3);
|
|
3137
3317
|
throw err_3;
|
|
3138
3318
|
case 24:
|
|
3139
|
-
|
|
3140
|
-
|
|
3319
|
+
// 必须先 abort writer(立即强制停止 pushable + stream),再 close stream。
|
|
3320
|
+
// 若顺序颠倒:stream.close() 会等待服务端半关闭确认,网络异常时永久挂住,
|
|
3321
|
+
// 导致 writer.abort() 永远不执行 → watchdog 定时器 / pushable 泄漏。
|
|
3322
|
+
// writer.abort() 内部幂等,成功路径下 writer.end() 已调用 cleanup(),安全。
|
|
3323
|
+
writerRef === null || writerRef === void 0 ? void 0 : writerRef.abort('unaryCall cleanup');
|
|
3324
|
+
if (!stream) return [3 /*break*/, 28];
|
|
3325
|
+
_c.label = 25;
|
|
3141
3326
|
case 25:
|
|
3142
|
-
|
|
3143
|
-
|
|
3327
|
+
_c.trys.push([25, 27, , 28]);
|
|
3328
|
+
return [4 /*yield*/, stream.close()];
|
|
3144
3329
|
case 26:
|
|
3330
|
+
_c.sent();
|
|
3331
|
+
return [3 /*break*/, 28];
|
|
3332
|
+
case 27:
|
|
3333
|
+
_c.sent();
|
|
3334
|
+
return [3 /*break*/, 28];
|
|
3335
|
+
case 28:
|
|
3145
3336
|
if (streamSlotAcquired && state) {
|
|
3146
3337
|
state.activeStreams = Math.max(0, state.activeStreams - 1);
|
|
3147
3338
|
this.notifyStreamSlotAvailable(state);
|
|
3148
3339
|
}
|
|
3149
3340
|
return [7 /*endfinally*/];
|
|
3150
|
-
case
|
|
3341
|
+
case 29:
|
|
3151
3342
|
if (exitFlag) {
|
|
3152
3343
|
throw new Error(errMsg);
|
|
3153
3344
|
}
|
|
@@ -3176,7 +3367,7 @@
|
|
|
3176
3367
|
*/
|
|
3177
3368
|
Libp2pGrpcClient.prototype.Call = function (method_1, requestData_1) {
|
|
3178
3369
|
return __awaiter(this, arguments, void 0, function (method, requestData, timeout, mode, onDataCallback, dataSourceCallback, onEndCallback, onErrorCallback, context, options) {
|
|
3179
|
-
var internalController, timeoutHandle, stream, profile, useFlowControl, cancelOperation, timeoutPromise, operationPromise, error_1;
|
|
3370
|
+
var internalController, timeoutHandle, stream, contextAbortHandler, profile, useFlowControl, cancelOperation, timeoutPromise, operationPromise, error_1;
|
|
3180
3371
|
var _this = this;
|
|
3181
3372
|
var _a;
|
|
3182
3373
|
if (timeout === void 0) { timeout = 30000; }
|
|
@@ -3203,17 +3394,16 @@
|
|
|
3203
3394
|
};
|
|
3204
3395
|
// 如果提供了外部信号,监听它
|
|
3205
3396
|
if (context === null || context === void 0 ? void 0 : context.signal) {
|
|
3206
|
-
//
|
|
3397
|
+
// 如果外部信号已经触发中止,立即返回——避免启动 IIFE 后在 catch 中再次调用 onErrorCallback
|
|
3207
3398
|
if (context.signal.aborted) {
|
|
3208
3399
|
if (onErrorCallback) {
|
|
3209
3400
|
onErrorCallback(new Error("Operation aborted by context"));
|
|
3210
3401
|
}
|
|
3211
|
-
cancelOperation
|
|
3402
|
+
return [2 /*return*/, cancelOperation];
|
|
3212
3403
|
}
|
|
3213
|
-
// 监听外部的abort
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
});
|
|
3404
|
+
// 监听外部的abort事件(保存引用以便后续移除,防止内存泄漏)
|
|
3405
|
+
contextAbortHandler = function () { cancelOperation(); };
|
|
3406
|
+
context.signal.addEventListener("abort", contextAbortHandler);
|
|
3217
3407
|
}
|
|
3218
3408
|
timeoutPromise = new Promise(function (_, reject) {
|
|
3219
3409
|
timeoutHandle = setTimeout(function () {
|
|
@@ -3222,58 +3412,83 @@
|
|
|
3222
3412
|
}, timeout);
|
|
3223
3413
|
});
|
|
3224
3414
|
operationPromise = (function () { return __awaiter(_this, void 0, void 0, function () {
|
|
3225
|
-
var
|
|
3415
|
+
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;
|
|
3226
3416
|
var _this = this;
|
|
3227
|
-
var
|
|
3228
|
-
var
|
|
3229
|
-
return __generator(this, function (
|
|
3230
|
-
switch (
|
|
3417
|
+
var _h, e_1, _j, _k;
|
|
3418
|
+
var _l, _m, _o;
|
|
3419
|
+
return __generator(this, function (_p) {
|
|
3420
|
+
switch (_p.label) {
|
|
3231
3421
|
case 0:
|
|
3232
|
-
|
|
3422
|
+
errorCallbackFired = false;
|
|
3423
|
+
reportError = function (err) {
|
|
3424
|
+
if (errorCallbackFired)
|
|
3425
|
+
return;
|
|
3426
|
+
errorCallbackFired = true;
|
|
3427
|
+
internalController.abort();
|
|
3428
|
+
if (onErrorCallback)
|
|
3429
|
+
onErrorCallback(err);
|
|
3430
|
+
};
|
|
3431
|
+
msgChunks = [];
|
|
3432
|
+
msgTotalLen = 0;
|
|
3233
3433
|
expectedMessageLength = -1;
|
|
3434
|
+
flattenMsgBuffer = function () {
|
|
3435
|
+
if (msgChunks.length === 0)
|
|
3436
|
+
return new Uint8Array(0);
|
|
3437
|
+
if (msgChunks.length === 1)
|
|
3438
|
+
return msgChunks[0];
|
|
3439
|
+
var out = new Uint8Array(msgTotalLen);
|
|
3440
|
+
var off = 0;
|
|
3441
|
+
for (var _i = 0, msgChunks_1 = msgChunks; _i < msgChunks_1.length; _i++) {
|
|
3442
|
+
var c = msgChunks_1[_i];
|
|
3443
|
+
out.set(c, off);
|
|
3444
|
+
off += c.length;
|
|
3445
|
+
}
|
|
3446
|
+
return out;
|
|
3447
|
+
};
|
|
3234
3448
|
hpack = new HPACK();
|
|
3235
3449
|
connection = null;
|
|
3236
3450
|
connectionKey = null;
|
|
3237
3451
|
state = null;
|
|
3238
3452
|
streamSlotAcquired = false;
|
|
3239
|
-
|
|
3453
|
+
writer = null;
|
|
3454
|
+
_p.label = 1;
|
|
3240
3455
|
case 1:
|
|
3241
|
-
|
|
3456
|
+
_p.trys.push([1, 49, 50, 64]);
|
|
3242
3457
|
// 检查是否已经中止
|
|
3243
3458
|
if (internalController.signal.aborted) {
|
|
3244
3459
|
throw new Error("Operation aborted");
|
|
3245
3460
|
}
|
|
3246
3461
|
if (!(options === null || options === void 0 ? void 0 : options.freshConnection)) return [3 /*break*/, 5];
|
|
3247
|
-
|
|
3462
|
+
_p.label = 2;
|
|
3248
3463
|
case 2:
|
|
3249
|
-
|
|
3464
|
+
_p.trys.push([2, 4, , 5]);
|
|
3250
3465
|
this.connectionPool.delete(this.peerAddr.toString());
|
|
3251
3466
|
return [4 /*yield*/, this.node.hangUp(this.peerAddr)];
|
|
3252
3467
|
case 3:
|
|
3253
|
-
|
|
3468
|
+
_p.sent();
|
|
3254
3469
|
console.warn("[Call] hangUp existing connection before dialing due to freshConnection=true");
|
|
3255
3470
|
return [3 /*break*/, 5];
|
|
3256
3471
|
case 4:
|
|
3257
|
-
err_4 =
|
|
3472
|
+
err_4 = _p.sent();
|
|
3258
3473
|
console.warn("[Call] hangUp failed or not supported, proceeding to dial", err_4);
|
|
3259
3474
|
return [3 /*break*/, 5];
|
|
3260
3475
|
case 5: return [4 /*yield*/, this.acquireConnection(Boolean(options === null || options === void 0 ? void 0 : options.freshConnection))];
|
|
3261
3476
|
case 6:
|
|
3262
|
-
connection =
|
|
3477
|
+
connection = _p.sent();
|
|
3263
3478
|
connectionKey = this.peerAddr.toString();
|
|
3264
3479
|
state = this.getConnectionState(connection);
|
|
3265
3480
|
if (!state) return [3 /*break*/, 10];
|
|
3266
|
-
|
|
3481
|
+
_p.label = 7;
|
|
3267
3482
|
case 7:
|
|
3268
|
-
|
|
3483
|
+
_p.trys.push([7, 9, , 10]);
|
|
3269
3484
|
return [4 /*yield*/, this.waitForStreamSlot(state, internalController.signal, timeout)];
|
|
3270
3485
|
case 8:
|
|
3271
|
-
|
|
3486
|
+
_p.sent();
|
|
3272
3487
|
state.activeStreams += 1;
|
|
3273
3488
|
streamSlotAcquired = true;
|
|
3274
3489
|
return [3 /*break*/, 10];
|
|
3275
3490
|
case 9:
|
|
3276
|
-
err_5 =
|
|
3491
|
+
err_5 = _p.sent();
|
|
3277
3492
|
console.warn("[Call] waiting for stream slot failed:", err_5);
|
|
3278
3493
|
throw err_5;
|
|
3279
3494
|
case 10: return [4 /*yield*/, connection.newStream(this.protocol, {
|
|
@@ -3282,23 +3497,23 @@
|
|
|
3282
3497
|
negotiateFully: false,
|
|
3283
3498
|
})];
|
|
3284
3499
|
case 11:
|
|
3285
|
-
stream =
|
|
3500
|
+
stream = _p.sent();
|
|
3286
3501
|
streamManager = this.getStreamManagerFor(connection);
|
|
3287
3502
|
return [4 /*yield*/, streamManager.getNextAppLevelStreamId()];
|
|
3288
3503
|
case 12:
|
|
3289
|
-
streamId_2 =
|
|
3290
|
-
|
|
3504
|
+
streamId_2 = _p.sent();
|
|
3505
|
+
writer = new StreamWriter(stream, {
|
|
3291
3506
|
bufferSize: 16 * 1024 * 1024,
|
|
3292
3507
|
});
|
|
3293
3508
|
try {
|
|
3294
|
-
|
|
3509
|
+
writer.addEventListener("backpressure", function (e) {
|
|
3295
3510
|
var d = e.detail || {};
|
|
3296
3511
|
console.warn("[stream ".concat(streamId_2, "] backpressure current=").concat(d.currentSize, " avg=").concat(d.averageSize, " threshold=").concat(d.threshold));
|
|
3297
3512
|
});
|
|
3298
|
-
|
|
3513
|
+
writer.addEventListener("drain", function () {
|
|
3299
3514
|
// drain event - no action needed
|
|
3300
3515
|
});
|
|
3301
|
-
|
|
3516
|
+
writer.addEventListener("stalled", function (e) {
|
|
3302
3517
|
var _a;
|
|
3303
3518
|
var d = e.detail || {};
|
|
3304
3519
|
console.warn("[stream ".concat(streamId_2, "] stalled queue=").concat(d.queueSize, " drained=").concat(d.drained, " since=").concat(d.sinceMs, "ms \u2014 sending PING"));
|
|
@@ -3306,13 +3521,13 @@
|
|
|
3306
3521
|
var payload = new Uint8Array(8);
|
|
3307
3522
|
(_a = crypto.getRandomValues) === null || _a === void 0 ? void 0 : _a.call(crypto, payload);
|
|
3308
3523
|
var ping = Http2Frame.createFrame(0x6, 0x0, 0, payload);
|
|
3309
|
-
|
|
3524
|
+
writer.write(ping);
|
|
3310
3525
|
}
|
|
3311
3526
|
catch ( /* ignore ping write errors */_b) { /* ignore ping write errors */ }
|
|
3312
3527
|
});
|
|
3313
3528
|
}
|
|
3314
|
-
catch ( /* ignore addEventListener errors */
|
|
3315
|
-
parser_1 = new HTTP2Parser(
|
|
3529
|
+
catch ( /* ignore addEventListener errors */_q) { /* ignore addEventListener errors */ }
|
|
3530
|
+
parser_1 = new HTTP2Parser(writer, {
|
|
3316
3531
|
compatibilityMode: !useFlowControl,
|
|
3317
3532
|
});
|
|
3318
3533
|
parser_1.onGoaway = function (info) {
|
|
@@ -3323,10 +3538,8 @@
|
|
|
3323
3538
|
if (state) {
|
|
3324
3539
|
_this.rejectStreamWaiters(state, new Error("Connection received GOAWAY"));
|
|
3325
3540
|
}
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
}
|
|
3329
|
-
internalController.abort();
|
|
3541
|
+
// reportError 统一完成:标记已报错 + abort + 触发回调(幂等,不会重复触发)
|
|
3542
|
+
reportError(new Error("GOAWAY received: code=".concat(info.errorCode)));
|
|
3330
3543
|
try {
|
|
3331
3544
|
connection === null || connection === void 0 ? void 0 : connection.close();
|
|
3332
3545
|
}
|
|
@@ -3351,7 +3564,7 @@
|
|
|
3351
3564
|
switch (_a.label) {
|
|
3352
3565
|
case 0:
|
|
3353
3566
|
if (!useFlowControl) return [3 /*break*/, 2];
|
|
3354
|
-
return [4 /*yield*/, this.sendFrameWithFlowControl(parser_1, streamId_2, frame,
|
|
3567
|
+
return [4 /*yield*/, this.sendFrameWithFlowControl(parser_1, streamId_2, frame, writer, internalController.signal, sendWindowTimeout_1)];
|
|
3355
3568
|
case 1:
|
|
3356
3569
|
_a.sent();
|
|
3357
3570
|
return [3 /*break*/, 4];
|
|
@@ -3359,7 +3572,7 @@
|
|
|
3359
3572
|
if (internalController.signal.aborted) {
|
|
3360
3573
|
throw new Error("Operation aborted");
|
|
3361
3574
|
}
|
|
3362
|
-
return [4 /*yield*/,
|
|
3575
|
+
return [4 /*yield*/, writer.write(frame)];
|
|
3363
3576
|
case 3:
|
|
3364
3577
|
_a.sent();
|
|
3365
3578
|
_a.label = 4;
|
|
@@ -3390,51 +3603,44 @@
|
|
|
3390
3603
|
}); };
|
|
3391
3604
|
// 在各个回调中检查是否已中止
|
|
3392
3605
|
parser_1.onData = function (payload) { return __awaiter(_this, void 0, void 0, function () {
|
|
3393
|
-
var
|
|
3606
|
+
var flat, lengthBytes, flat, completeMessage, remaining;
|
|
3394
3607
|
return __generator(this, function (_a) {
|
|
3395
|
-
|
|
3396
|
-
if (internalController.signal.aborted) {
|
|
3608
|
+
if (internalController.signal.aborted)
|
|
3397
3609
|
return [2 /*return*/];
|
|
3398
|
-
}
|
|
3399
3610
|
try {
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
messageBuffer = newBuffer;
|
|
3611
|
+
// 追加到分段列表,O(1),不拷贝历史数据
|
|
3612
|
+
msgChunks.push(payload);
|
|
3613
|
+
msgTotalLen += payload.length;
|
|
3404
3614
|
// 处理缓冲区中的完整消息
|
|
3405
|
-
while (
|
|
3406
|
-
|
|
3407
|
-
if (internalController.signal.aborted) {
|
|
3615
|
+
while (msgTotalLen > 0) {
|
|
3616
|
+
if (internalController.signal.aborted)
|
|
3408
3617
|
return [2 /*return*/];
|
|
3618
|
+
// 读取 gRPC 消息头(5字节)
|
|
3619
|
+
if (expectedMessageLength === -1 && msgTotalLen >= 5) {
|
|
3620
|
+
flat = flattenMsgBuffer();
|
|
3621
|
+
msgChunks = [flat];
|
|
3622
|
+
lengthBytes = flat.slice(1, 5);
|
|
3623
|
+
expectedMessageLength = new DataView(lengthBytes.buffer, lengthBytes.byteOffset).getUint32(0, false);
|
|
3409
3624
|
}
|
|
3410
|
-
//
|
|
3411
|
-
if (expectedMessageLength
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
// 如果知道期望长度且有足够数据
|
|
3416
|
-
if (expectedMessageLength !== -1 &&
|
|
3417
|
-
messageBuffer.length >= expectedMessageLength + 5) {
|
|
3418
|
-
completeMessage = messageBuffer.slice(5, expectedMessageLength + 5);
|
|
3419
|
-
// 调用回调处理这个完整消息
|
|
3625
|
+
// 有完整消息
|
|
3626
|
+
if (expectedMessageLength !== -1 && msgTotalLen >= expectedMessageLength + 5) {
|
|
3627
|
+
flat = flattenMsgBuffer();
|
|
3628
|
+
msgChunks = [flat];
|
|
3629
|
+
completeMessage = flat.slice(5, expectedMessageLength + 5);
|
|
3420
3630
|
onDataCallback(completeMessage);
|
|
3421
|
-
|
|
3422
|
-
|
|
3631
|
+
remaining = flat.slice(expectedMessageLength + 5);
|
|
3632
|
+
msgChunks = remaining.length > 0 ? [remaining] : [];
|
|
3633
|
+
msgTotalLen = remaining.length;
|
|
3423
3634
|
expectedMessageLength = -1;
|
|
3424
3635
|
}
|
|
3425
3636
|
else {
|
|
3426
|
-
// 没有足够数据构成完整消息,等待更多数据
|
|
3427
3637
|
break;
|
|
3428
3638
|
}
|
|
3429
3639
|
}
|
|
3430
3640
|
}
|
|
3431
3641
|
catch (error) {
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
}
|
|
3435
|
-
else {
|
|
3436
|
-
throw error;
|
|
3437
|
-
}
|
|
3642
|
+
// reportError 统一报错并中止,防止 onEndCallback 在数据处理异常后仍被调用
|
|
3643
|
+
reportError(error);
|
|
3438
3644
|
}
|
|
3439
3645
|
return [2 /*return*/];
|
|
3440
3646
|
});
|
|
@@ -3444,7 +3650,7 @@
|
|
|
3444
3650
|
if (internalController.signal.aborted)
|
|
3445
3651
|
return;
|
|
3446
3652
|
var ackSettingFrame = Http2Frame.createSettingsAckFrame();
|
|
3447
|
-
|
|
3653
|
+
writer.write(ackSettingFrame);
|
|
3448
3654
|
};
|
|
3449
3655
|
parser_1.onHeaders = function (headers) {
|
|
3450
3656
|
// 检查是否已中止
|
|
@@ -3454,20 +3660,16 @@
|
|
|
3454
3660
|
if (plainHeaders.get("grpc-status") === "0") ;
|
|
3455
3661
|
else if (plainHeaders.get("grpc-status") !== undefined) {
|
|
3456
3662
|
var errMsg = plainHeaders.get("grpc-message") || "gRPC call failed";
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
onErrorCallback(err);
|
|
3460
|
-
}
|
|
3461
|
-
else {
|
|
3462
|
-
throw err;
|
|
3463
|
-
}
|
|
3663
|
+
// reportError 统一完成:标记已报错 + abort + 触发回调(幂等,不会重复触发)
|
|
3664
|
+
reportError(new Error(errMsg));
|
|
3464
3665
|
}
|
|
3465
3666
|
};
|
|
3466
3667
|
// 启动后台流处理
|
|
3467
3668
|
parser_1.processStream(stream).catch(function (error) {
|
|
3468
|
-
|
|
3469
|
-
if (
|
|
3470
|
-
|
|
3669
|
+
// abort() 触发的清理错误属于预期行为,不打印错误日志,不重复触发回调
|
|
3670
|
+
if (!internalController.signal.aborted) {
|
|
3671
|
+
console.error('Error in processStream:', error);
|
|
3672
|
+
reportError(error);
|
|
3471
3673
|
}
|
|
3472
3674
|
});
|
|
3473
3675
|
// 检查是否已中止
|
|
@@ -3475,56 +3677,52 @@
|
|
|
3475
3677
|
throw new Error("Operation aborted");
|
|
3476
3678
|
}
|
|
3477
3679
|
preface = Http2Frame.createPreface();
|
|
3478
|
-
return [4 /*yield*/,
|
|
3680
|
+
return [4 /*yield*/, writer.write(preface)];
|
|
3479
3681
|
case 13:
|
|
3480
|
-
|
|
3682
|
+
_p.sent();
|
|
3481
3683
|
// 检查是否已中止
|
|
3482
3684
|
if (internalController.signal.aborted) {
|
|
3483
3685
|
throw new Error("Operation aborted");
|
|
3484
3686
|
}
|
|
3485
3687
|
settingFrame = Http2Frame.createSettingsFrame();
|
|
3486
|
-
return [4 /*yield*/,
|
|
3688
|
+
return [4 /*yield*/, writer.write(settingFrame)];
|
|
3487
3689
|
case 14:
|
|
3488
|
-
|
|
3690
|
+
_p.sent();
|
|
3489
3691
|
// 检查是否已中止
|
|
3490
3692
|
if (internalController.signal.aborted) {
|
|
3491
3693
|
throw new Error("Operation aborted");
|
|
3492
3694
|
}
|
|
3493
3695
|
return [4 /*yield*/, Promise.race([
|
|
3494
|
-
parser_1.waitForPeerSettings(1000),
|
|
3495
|
-
parser_1.waitForSettingsAck(),
|
|
3696
|
+
parser_1.waitForPeerSettings(1000).catch(function () { }),
|
|
3697
|
+
parser_1.waitForSettingsAck().catch(function () { }),
|
|
3496
3698
|
new Promise(function (res) { return setTimeout(res, 300); }),
|
|
3497
3699
|
])];
|
|
3498
3700
|
case 15:
|
|
3499
|
-
|
|
3701
|
+
_p.sent();
|
|
3500
3702
|
// 检查是否已中止
|
|
3501
3703
|
if (internalController.signal.aborted) {
|
|
3502
3704
|
throw new Error("Operation aborted");
|
|
3503
3705
|
}
|
|
3504
|
-
|
|
3505
|
-
if (internalController.signal.aborted) {
|
|
3506
|
-
throw new Error("Operation aborted");
|
|
3507
|
-
}
|
|
3508
|
-
headerFrame = Http2Frame.createHeadersFrame(streamId_2, method, true, this.token);
|
|
3706
|
+
headerFrame = Http2Frame.createHeadersFrame(streamId_2, method, true, this.token, this.getAuthority());
|
|
3509
3707
|
if (!(mode === "unary" || mode === "server-streaming")) return [3 /*break*/, 18];
|
|
3510
|
-
return [4 /*yield*/,
|
|
3708
|
+
return [4 /*yield*/, writer.write(headerFrame)];
|
|
3511
3709
|
case 16:
|
|
3512
|
-
|
|
3710
|
+
_p.sent();
|
|
3513
3711
|
dfs = Http2Frame.createDataFrames(streamId_2, requestData, true);
|
|
3514
3712
|
return [4 /*yield*/, writeDataFrames_1(dfs)];
|
|
3515
3713
|
case 17:
|
|
3516
|
-
|
|
3714
|
+
_p.sent();
|
|
3517
3715
|
// 检查是否已中止
|
|
3518
3716
|
if (internalController.signal.aborted) {
|
|
3519
3717
|
throw new Error("Operation aborted");
|
|
3520
3718
|
}
|
|
3521
|
-
return [3 /*break*/,
|
|
3719
|
+
return [3 /*break*/, 45];
|
|
3522
3720
|
case 18:
|
|
3523
3721
|
if (!((mode === "client-streaming" || mode === "bidirectional") &&
|
|
3524
|
-
dataSourceCallback)) return [3 /*break*/,
|
|
3525
|
-
return [4 /*yield*/,
|
|
3722
|
+
dataSourceCallback)) return [3 /*break*/, 45];
|
|
3723
|
+
return [4 /*yield*/, writer.write(headerFrame)];
|
|
3526
3724
|
case 19:
|
|
3527
|
-
|
|
3725
|
+
_p.sent();
|
|
3528
3726
|
// 检查是否已中止
|
|
3529
3727
|
if (internalController.signal.aborted) {
|
|
3530
3728
|
throw new Error("Operation aborted");
|
|
@@ -3533,12 +3731,23 @@
|
|
|
3533
3731
|
dfs0 = Http2Frame.createDataFrames(streamId_2, requestData, false);
|
|
3534
3732
|
return [4 /*yield*/, writeDataFrames_1(dfs0)];
|
|
3535
3733
|
case 20:
|
|
3536
|
-
|
|
3537
|
-
|
|
3734
|
+
_p.sent();
|
|
3735
|
+
_p.label = 21;
|
|
3538
3736
|
case 21:
|
|
3539
3737
|
batchSize_1 = (options === null || options === void 0 ? void 0 : options.batchSize) || 10;
|
|
3540
3738
|
processingQueue_1 = [];
|
|
3739
|
+
batchDoneWaiters_1 = [];
|
|
3541
3740
|
isProcessing_1 = false;
|
|
3741
|
+
_notifyBatchDone_1 = function () {
|
|
3742
|
+
var ws = batchDoneWaiters_1.splice(0);
|
|
3743
|
+
for (var _i = 0, ws_1 = ws; _i < ws_1.length; _i++) {
|
|
3744
|
+
var fn = ws_1[_i];
|
|
3745
|
+
try {
|
|
3746
|
+
fn();
|
|
3747
|
+
}
|
|
3748
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
3749
|
+
}
|
|
3750
|
+
};
|
|
3542
3751
|
processNextBatch_1 = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
3543
3752
|
var currentBatch, _i, currentBatch_1, item, frames_2, item, frames1, error_3;
|
|
3544
3753
|
return __generator(this, function (_a) {
|
|
@@ -3599,10 +3808,13 @@
|
|
|
3599
3808
|
case 10:
|
|
3600
3809
|
isProcessing_1 = false;
|
|
3601
3810
|
// 如果队列中还有数据,继续处理
|
|
3602
|
-
if (processingQueue_1.length > 0 &&
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3811
|
+
if (processingQueue_1.length > 0 && !internalController.signal.aborted) {
|
|
3812
|
+
// 直接递归调用(已是 async,自动让出事件循环)
|
|
3813
|
+
processNextBatch_1().catch(function (err) { console.error("Error in processNextBatch:", err); });
|
|
3814
|
+
}
|
|
3815
|
+
else {
|
|
3816
|
+
// 队列清空,唤醒等待者
|
|
3817
|
+
_notifyBatchDone_1();
|
|
3606
3818
|
}
|
|
3607
3819
|
return [7 /*endfinally*/];
|
|
3608
3820
|
case 11: return [2 /*return*/];
|
|
@@ -3625,20 +3837,20 @@
|
|
|
3625
3837
|
}
|
|
3626
3838
|
});
|
|
3627
3839
|
};
|
|
3628
|
-
|
|
3840
|
+
_p.label = 22;
|
|
3629
3841
|
case 22:
|
|
3630
|
-
|
|
3631
|
-
|
|
3842
|
+
_p.trys.push([22, 36, , 37]);
|
|
3843
|
+
_p.label = 23;
|
|
3632
3844
|
case 23:
|
|
3633
|
-
|
|
3845
|
+
_p.trys.push([23, 29, 30, 35]);
|
|
3634
3846
|
_a = true, _b = __asyncValues(dataSourceCallback());
|
|
3635
|
-
|
|
3847
|
+
_p.label = 24;
|
|
3636
3848
|
case 24: return [4 /*yield*/, _b.next()];
|
|
3637
3849
|
case 25:
|
|
3638
|
-
if (!(_c =
|
|
3639
|
-
|
|
3850
|
+
if (!(_c = _p.sent(), _h = _c.done, !_h)) return [3 /*break*/, 28];
|
|
3851
|
+
_k = _c.value;
|
|
3640
3852
|
_a = false;
|
|
3641
|
-
chunkOrChunks =
|
|
3853
|
+
chunkOrChunks = _k;
|
|
3642
3854
|
// 检查是否已中止
|
|
3643
3855
|
if (internalController.signal.aborted) {
|
|
3644
3856
|
throw new Error("Operation aborted");
|
|
@@ -3653,23 +3865,23 @@
|
|
|
3653
3865
|
return [4 /*yield*/, Promise.all(addPromises)];
|
|
3654
3866
|
case 26:
|
|
3655
3867
|
// 等待当前批次的chunks被添加到队列(不等待处理完成)
|
|
3656
|
-
|
|
3657
|
-
|
|
3868
|
+
_p.sent();
|
|
3869
|
+
_p.label = 27;
|
|
3658
3870
|
case 27:
|
|
3659
3871
|
_a = true;
|
|
3660
3872
|
return [3 /*break*/, 24];
|
|
3661
3873
|
case 28: return [3 /*break*/, 35];
|
|
3662
3874
|
case 29:
|
|
3663
|
-
e_1_1 =
|
|
3875
|
+
e_1_1 = _p.sent();
|
|
3664
3876
|
e_1 = { error: e_1_1 };
|
|
3665
3877
|
return [3 /*break*/, 35];
|
|
3666
3878
|
case 30:
|
|
3667
|
-
|
|
3668
|
-
if (!(!_a && !
|
|
3669
|
-
return [4 /*yield*/,
|
|
3879
|
+
_p.trys.push([30, , 33, 34]);
|
|
3880
|
+
if (!(!_a && !_h && (_j = _b.return))) return [3 /*break*/, 32];
|
|
3881
|
+
return [4 /*yield*/, _j.call(_b)];
|
|
3670
3882
|
case 31:
|
|
3671
|
-
|
|
3672
|
-
|
|
3883
|
+
_p.sent();
|
|
3884
|
+
_p.label = 32;
|
|
3673
3885
|
case 32: return [3 /*break*/, 34];
|
|
3674
3886
|
case 33:
|
|
3675
3887
|
if (e_1) throw e_1.error;
|
|
@@ -3677,7 +3889,7 @@
|
|
|
3677
3889
|
case 34: return [7 /*endfinally*/];
|
|
3678
3890
|
case 35: return [3 /*break*/, 37];
|
|
3679
3891
|
case 36:
|
|
3680
|
-
error_2 =
|
|
3892
|
+
error_2 = _p.sent();
|
|
3681
3893
|
remainingQueue = processingQueue_1.splice(0);
|
|
3682
3894
|
remainingQueue.forEach(function (item) {
|
|
3683
3895
|
try {
|
|
@@ -3688,81 +3900,95 @@
|
|
|
3688
3900
|
}
|
|
3689
3901
|
});
|
|
3690
3902
|
throw error_2;
|
|
3691
|
-
case 37:
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
throw new Error("Operation aborted");
|
|
3699
|
-
}
|
|
3700
|
-
// 防止无限等待
|
|
3701
|
-
if (Date.now() - queueWaitStart > maxQueueWaitMs) {
|
|
3702
|
-
remainingQueue = processingQueue_1.splice(0);
|
|
3703
|
-
remainingQueue.forEach(function (item) {
|
|
3704
|
-
try {
|
|
3705
|
-
item.reject(new Error("Queue wait timeout"));
|
|
3903
|
+
case 37:
|
|
3904
|
+
// 等待所有剩余的数据处理完成(事件驱动,无 10ms 轮询)
|
|
3905
|
+
return [4 /*yield*/, new Promise(function (resolve, reject) {
|
|
3906
|
+
var check = function () {
|
|
3907
|
+
if (internalController.signal.aborted) {
|
|
3908
|
+
reject(new Error("Operation aborted"));
|
|
3909
|
+
return;
|
|
3706
3910
|
}
|
|
3707
|
-
|
|
3708
|
-
|
|
3911
|
+
if (processingQueue_1.length === 0 && !isProcessing_1) {
|
|
3912
|
+
resolve();
|
|
3913
|
+
return;
|
|
3709
3914
|
}
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3915
|
+
// processNextBatch 结束时会通知这里
|
|
3916
|
+
batchDoneWaiters_1.push(check);
|
|
3917
|
+
};
|
|
3918
|
+
check();
|
|
3919
|
+
})];
|
|
3920
|
+
case 38:
|
|
3921
|
+
// 等待所有剩余的数据处理完成(事件驱动,无 10ms 轮询)
|
|
3922
|
+
_p.sent();
|
|
3718
3923
|
// 检查是否已中止
|
|
3719
3924
|
if (internalController.signal.aborted) {
|
|
3720
3925
|
throw new Error("Operation aborted");
|
|
3721
3926
|
}
|
|
3722
|
-
finalFrame = Http2Frame.
|
|
3927
|
+
finalFrame = Http2Frame.createFrame(0x0, 0x01, streamId_2, new Uint8Array(0));
|
|
3723
3928
|
return [4 /*yield*/, writeFrame_1(finalFrame)];
|
|
3929
|
+
case 39:
|
|
3930
|
+
_p.sent();
|
|
3931
|
+
_p.label = 40;
|
|
3932
|
+
case 40:
|
|
3933
|
+
_p.trys.push([40, 42, , 43]);
|
|
3934
|
+
return [4 /*yield*/, writer.flush(timeout)];
|
|
3724
3935
|
case 41:
|
|
3725
|
-
|
|
3726
|
-
|
|
3936
|
+
_p.sent();
|
|
3937
|
+
return [3 /*break*/, 43];
|
|
3727
3938
|
case 42:
|
|
3728
|
-
|
|
3729
|
-
return [
|
|
3730
|
-
case 43:
|
|
3731
|
-
_o.sent();
|
|
3732
|
-
return [3 /*break*/, 45];
|
|
3939
|
+
_p.sent();
|
|
3940
|
+
return [3 /*break*/, 43];
|
|
3941
|
+
case 43: return [4 /*yield*/, writer.end()];
|
|
3733
3942
|
case 44:
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
case 45:
|
|
3737
|
-
case 46:
|
|
3738
|
-
_o.sent();
|
|
3739
|
-
_o.label = 47;
|
|
3740
|
-
case 47:
|
|
3943
|
+
_p.sent();
|
|
3944
|
+
_p.label = 45;
|
|
3945
|
+
case 45:
|
|
3741
3946
|
// 检查是否已中止
|
|
3742
3947
|
if (internalController.signal.aborted) {
|
|
3743
3948
|
throw new Error("Operation aborted");
|
|
3744
3949
|
}
|
|
3950
|
+
if (!!internalController.signal.aborted) return [3 /*break*/, 48];
|
|
3745
3951
|
return [4 /*yield*/, parser_1.waitForEndOfStream(0)];
|
|
3746
|
-
case
|
|
3747
|
-
|
|
3748
|
-
|
|
3952
|
+
case 46:
|
|
3953
|
+
_p.sent();
|
|
3954
|
+
// Yield one microtask tick so that processStream.catch (which calls
|
|
3955
|
+
// reportError + internalController.abort()) has a chance to run before
|
|
3956
|
+
// we check abort status. Without this yield, if the stream died
|
|
3957
|
+
// unexpectedly (network error), onEndCallback and onErrorCallback
|
|
3958
|
+
// could both fire because _notifyEndOfStream() is called in
|
|
3959
|
+
// processStream's catch block before the re-throw schedules the
|
|
3960
|
+
// .catch handler as a microtask.
|
|
3961
|
+
return [4 /*yield*/, Promise.resolve()];
|
|
3962
|
+
case 47:
|
|
3963
|
+
// Yield one microtask tick so that processStream.catch (which calls
|
|
3964
|
+
// reportError + internalController.abort()) has a chance to run before
|
|
3965
|
+
// we check abort status. Without this yield, if the stream died
|
|
3966
|
+
// unexpectedly (network error), onEndCallback and onErrorCallback
|
|
3967
|
+
// could both fire because _notifyEndOfStream() is called in
|
|
3968
|
+
// processStream's catch block before the re-throw schedules the
|
|
3969
|
+
// .catch handler as a microtask.
|
|
3970
|
+
_p.sent();
|
|
3971
|
+
if (!internalController.signal.aborted && onEndCallback) {
|
|
3749
3972
|
onEndCallback();
|
|
3750
3973
|
}
|
|
3751
|
-
|
|
3974
|
+
_p.label = 48;
|
|
3975
|
+
case 48: return [3 /*break*/, 64];
|
|
3752
3976
|
case 49:
|
|
3753
|
-
err_6 =
|
|
3977
|
+
err_6 = _p.sent();
|
|
3754
3978
|
// 如果是由于取消导致的错误,使用特定的错误消息
|
|
3755
3979
|
if (internalController.signal.aborted &&
|
|
3756
3980
|
err_6 instanceof Error &&
|
|
3757
3981
|
err_6.message === "Operation aborted") {
|
|
3758
|
-
|
|
3982
|
+
// onHeaders / onGoaway / processStream 错误已通过 reportError 处理,
|
|
3983
|
+
// 此处仅在回调尚未触发时才报告(外部取消/超时场景)
|
|
3984
|
+
if (!errorCallbackFired && onErrorCallback) {
|
|
3759
3985
|
onErrorCallback(new Error("Operation cancelled by user"));
|
|
3760
3986
|
}
|
|
3761
3987
|
}
|
|
3762
|
-
else if (onErrorCallback) {
|
|
3988
|
+
else if (!errorCallbackFired && onErrorCallback) {
|
|
3763
3989
|
onErrorCallback(err_6);
|
|
3764
3990
|
}
|
|
3765
|
-
else {
|
|
3991
|
+
else if (!errorCallbackFired) {
|
|
3766
3992
|
if (err_6 instanceof Error) {
|
|
3767
3993
|
console.error("asyncCall error:", err_6.message);
|
|
3768
3994
|
}
|
|
@@ -3773,45 +3999,57 @@
|
|
|
3773
3999
|
return [3 /*break*/, 64];
|
|
3774
4000
|
case 50:
|
|
3775
4001
|
clearTimeout(timeoutHandle);
|
|
4002
|
+
// 移除外部 abort 监听器,防止 AbortController 复用时触发迟到的 cancelOperation()
|
|
4003
|
+
if (contextAbortHandler && (context === null || context === void 0 ? void 0 : context.signal)) {
|
|
4004
|
+
context.signal.removeEventListener("abort", contextAbortHandler);
|
|
4005
|
+
}
|
|
4006
|
+
// 首先标记操作已结束(正常或异常),确保 processStream.catch 不会把
|
|
4007
|
+
// writer.abort() 产生的 'Call cleanup' 错误误判为真实错误并触发 onErrorCallback。
|
|
4008
|
+
// internalController.abort() 是幂等的,重复调用安全。
|
|
4009
|
+
internalController.abort();
|
|
4010
|
+
// 必须先 abort writer(立即强制停止 pushable + stream),再 close stream。
|
|
4011
|
+
// 若顺序颠倒:stream.close() 等待服务端半关闭确认,网络异常时永久挂住,
|
|
4012
|
+
// writer.abort() 永远不执行 → watchdog / pushable 泄漏。
|
|
4013
|
+
// abort() 内部幂等,重复调用安全。
|
|
4014
|
+
writer === null || writer === void 0 ? void 0 : writer.abort('Call cleanup');
|
|
3776
4015
|
if (!stream) return [3 /*break*/, 54];
|
|
3777
|
-
|
|
4016
|
+
_p.label = 51;
|
|
3778
4017
|
case 51:
|
|
3779
|
-
|
|
4018
|
+
_p.trys.push([51, 53, , 54]);
|
|
3780
4019
|
return [4 /*yield*/, stream.close()];
|
|
3781
4020
|
case 52:
|
|
3782
|
-
|
|
4021
|
+
_p.sent();
|
|
3783
4022
|
return [3 /*break*/, 54];
|
|
3784
4023
|
case 53:
|
|
3785
|
-
|
|
3786
|
-
console.error("Error closing stream:", err_7);
|
|
4024
|
+
_p.sent();
|
|
3787
4025
|
return [3 /*break*/, 54];
|
|
3788
4026
|
case 54:
|
|
3789
4027
|
if (!(options === null || options === void 0 ? void 0 : options.freshConnection)) return [3 /*break*/, 63];
|
|
3790
|
-
|
|
4028
|
+
_p.label = 55;
|
|
3791
4029
|
case 55:
|
|
3792
|
-
|
|
3793
|
-
conns = ((
|
|
4030
|
+
_p.trys.push([55, 62, , 63]);
|
|
4031
|
+
conns = ((_m = (_l = this.node).getConnections) === null || _m === void 0 ? void 0 : _m.call(_l, this.peerAddr)) || [];
|
|
3794
4032
|
_i = 0, conns_1 = conns;
|
|
3795
|
-
|
|
4033
|
+
_p.label = 56;
|
|
3796
4034
|
case 56:
|
|
3797
4035
|
if (!(_i < conns_1.length)) return [3 /*break*/, 61];
|
|
3798
4036
|
c = conns_1[_i];
|
|
3799
|
-
|
|
4037
|
+
_p.label = 57;
|
|
3800
4038
|
case 57:
|
|
3801
|
-
|
|
3802
|
-
return [4 /*yield*/, ((
|
|
4039
|
+
_p.trys.push([57, 59, , 60]);
|
|
4040
|
+
return [4 /*yield*/, ((_o = c.close) === null || _o === void 0 ? void 0 : _o.call(c))];
|
|
3803
4041
|
case 58:
|
|
3804
|
-
|
|
4042
|
+
_p.sent();
|
|
3805
4043
|
return [3 /*break*/, 60];
|
|
3806
4044
|
case 59:
|
|
3807
|
-
|
|
4045
|
+
_p.sent();
|
|
3808
4046
|
return [3 /*break*/, 60];
|
|
3809
4047
|
case 60:
|
|
3810
4048
|
_i++;
|
|
3811
4049
|
return [3 /*break*/, 56];
|
|
3812
4050
|
case 61: return [3 /*break*/, 63];
|
|
3813
4051
|
case 62:
|
|
3814
|
-
|
|
4052
|
+
_p.sent();
|
|
3815
4053
|
return [3 /*break*/, 63];
|
|
3816
4054
|
case 63:
|
|
3817
4055
|
if (streamSlotAcquired && state) {
|