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