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/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 >> bits) & 0xFF);
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
- current = (current << (8 - bits)) | ((1 << (8 - bits)) - 1);
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 _c = this.decodeLiteralHeaderWithoutIndexing(buffer, index), name_4 = _c[0], value = _c[1], newIndex = _c[2];
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 _d = this.decodeLiteralHeaderWithoutIndexing(buffer, index), name_5 = _d[0], value = _d[1], newIndex = _d[2];
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.staticTable[staticIndex];
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), staticIndex = _a[0], nameIndex = _a[1];
605
- index = nameIndex;
618
+ var _a = this.decodeInteger(buffer, index, 6), nameIndex = _a[0], nextIndex = _a[1];
619
+ index = nextIndex;
606
620
  var name;
607
- if (staticIndex > 0) {
608
- var headerField = this.staticTable[staticIndex];
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
- return this.decodeLiteralHeaderWithIndexing(buffer, index);
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
- _a[SETTINGS_PARAMETERS.ENABLE_PUSH] = 1,
744
+ // gRPC 客户端不使用 Server Push,禁用以避免无效的 PUSH_PROMISE 处理
745
+ _a[SETTINGS_PARAMETERS.ENABLE_PUSH] = 0,
715
746
  _a[SETTINGS_PARAMETERS.MAX_CONCURRENT_STREAMS] = 100,
716
- _a[SETTINGS_PARAMETERS.INITIAL_WINDOW_SIZE] = 16 << 10,
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
- // HTTP/2 帧头为 9 字节
783
- var maxDataPerFrame = maxFrameSize - 9;
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': 'localhost',
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
- this.buffer = new Uint8Array(0);
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
- console.error("Error processing stream:", error_1);
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
- // 原作者之前的 O(N) 内存拷贝优化被保留,去掉了存在 onEnd 竞态的 setTimeout
1048
- var newBuffer = new Uint8Array(this.buffer.length + newData.length);
1049
- newBuffer.set(this.buffer);
1050
- newBuffer.set(newData, this.buffer.length);
1051
- this.buffer = newBuffer;
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 (this.buffer.length - readOffset >= 9) {
1150
+ while (flat.length - readOffset >= 9) {
1055
1151
  // 判断是否有HTTP/2前导
1056
- if (this.buffer.length - readOffset >= 24 && this.isHttp2Preface(this.buffer.subarray(readOffset))) {
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(this.buffer.subarray(readOffset));
1159
+ var frameHeader = this._parseFrameHeader(flat.subarray(readOffset));
1064
1160
  var totalFrameLength = 9 + frameHeader.length;
1065
1161
  // 检查是否有完整的帧
1066
- if (this.buffer.length - readOffset < totalFrameLength) {
1162
+ if (flat.length - readOffset < totalFrameLength) {
1067
1163
  break;
1068
1164
  }
1069
- // 获取完整帧数据
1070
- var frameData = this.buffer.subarray(readOffset, readOffset + totalFrameLength);
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
- this.buffer = this.buffer.slice(readOffset);
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
- // 移除之前的 for await 循环代码
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 interval = setInterval(function () {
1104
- if (_this.settingsAckReceived) {
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
- clearInterval(interval);
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
- // 等待接收来自对端的 SETTINGS(非 ACK
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 interval = setInterval(function () {
1126
- if (_this.peerSettingsReceived) {
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
- clearInterval(interval);
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
- // 等待可用发送窗口(两个窗口都需要 >0)
1169
- HTTP2Parser.prototype.waitForSendWindow = function (streamId_1) {
1170
- return __awaiter(this, arguments, void 0, function (streamId, minBytes, timeoutMs) {
1171
- var start;
1172
- var _this = this;
1173
- if (minBytes === void 0) { minBytes = 1; }
1174
- if (timeoutMs === void 0) { timeoutMs = 30000; }
1175
- return __generator(this, function (_a) {
1176
- start = Date.now();
1177
- return [2 /*return*/, new Promise(function (resolve, reject) {
1178
- var interval = null;
1179
- var settled = false;
1180
- var check = function () {
1181
- var _a = _this.getSendWindows(streamId), conn = _a.conn, stream = _a.stream;
1182
- if (conn >= minBytes && stream >= minBytes) {
1183
- if (!settled) {
1184
- settled = true;
1185
- if (interval) {
1186
- clearInterval(interval);
1187
- interval = null;
1188
- }
1189
- resolve();
1190
- }
1191
- return true;
1192
- }
1193
- if (Date.now() - start > timeoutMs) {
1194
- if (!settled) {
1195
- settled = true;
1196
- if (interval) {
1197
- clearInterval(interval);
1198
- interval = null;
1199
- }
1200
- reject(new Error('Send window wait timeout'));
1201
- }
1202
- return true;
1203
- }
1204
- return false;
1205
- };
1206
- if (check())
1207
- return;
1208
- var tick = function () {
1209
- if (!check()) ;
1210
- };
1211
- var wake = function () { tick(); };
1212
- // 简单的等待模型:依赖 WINDOW_UPDATE 到达时调用 wake
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, waiters, streamWindowUpdate, connWindowUpdate, inc, cur, waiters, info, body, view, lastStreamId, errorCode;
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 (_f) {
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.settingsAckReceived = true;
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.peerSettingsReceived = true;
1288
- waiters = this.sendWindowWaiters.splice(0);
1289
- waiters.forEach(function (fn) { try {
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
- try {
1304
- // 更新流级别的窗口
1305
- if (frameHeader.streamId !== 0) {
1306
- streamWindowUpdate = Http2Frame.createWindowUpdateFrame(frameHeader.streamId, (_a = frameHeader.length) !== null && _a !== void 0 ? _a : 0);
1307
- this.writer.write(streamWindowUpdate);
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.endFlag = true;
1319
- if (this.onEnd) {
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.endFlag = true;
1334
- if (this.onEnd) {
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
- inc = this.parseWindowUpdateFrame(frameData, frameHeader).windowSizeIncrement;
1452
+ result = this.handleWindowUpdateFrame(frameHeader, frameData);
1453
+ // 更新发送方向窗口(对端的接收窗口)
1346
1454
  if (frameHeader.streamId === 0) {
1347
- this.sendConnWindow += inc;
1455
+ this.sendConnWindow += result.windowSizeIncrement;
1348
1456
  }
1349
1457
  else {
1350
- cur = (_c = this.sendStreamWindows.get(frameHeader.streamId)) !== null && _c !== void 0 ? _c : this.peerInitialStreamWindow;
1351
- this.sendStreamWindows.set(frameHeader.streamId, cur + inc);
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
- catch (e) {
1358
- console.debug('waiter error', e);
1359
- } });
1461
+ this._wakeWindowWaiters();
1360
1462
  }
1361
- catch ( /* ignore WINDOW_UPDATE parse errors */_g) { /* 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 */_h) { /* ignore GOAWAY parse errors */ }
1485
+ catch ( /* ignore GOAWAY parse errors */_k) { /* ignore GOAWAY parse errors */ }
1384
1486
  try {
1385
- (_d = this.onGoaway) === null || _d === void 0 ? void 0 : _d.call(this, info !== null && info !== void 0 ? info : {});
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
- (_e = this.onEnd) === null || _e === void 0 ? void 0 : _e.call(this);
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.endFlag = true;
1405
- if (this.onEnd) {
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
- var streamId = (buffer[5] << 24) | (buffer[6] << 16) | (buffer[7] << 8) | buffer[8];
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
- // 如果是0 ,则不设置超时
1459
- var timeout = null;
1460
- if (waitTime > 0) {
1461
- timeout = setTimeout(function () {
1462
- clearInterval(interval);
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
- // Check interval for real-time endFlag monitoring
1467
- var checkInterval = 100; // Check every 100 milliseconds
1468
- // Set an interval to check the endFlag regularly
1469
- var interval = setInterval(function () {
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
- // 等待 drain 事件
2020
- return [4 /*yield*/, this.stream.onDrain()];
2111
+ // 传入 abort signal,当流被 abort 时 onDrain() 会立即 reject,
2112
+ // 避免在 abort 路径下永久挂住
2113
+ return [4 /*yield*/, this.stream.onDrain({ signal: this.abortController.signal })];
2021
2114
  case 5:
2022
- // 等待 drain 事件
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: return [2 /*return*/];
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 < buffer.byteLength)) return [3 /*break*/, 4];
2248
- end = Math.min(offset + this.options.chunkSize, buffer.byteLength);
2249
- chunk = new Uint8Array(end - offset);
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, 5, , 8]);
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
- return [4 /*yield*/, new Promise(function (resolve, reject) {
2292
- try {
2293
- _this.p.push(chunk);
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*/, 7];
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 6:
2407
+ case 5:
2309
2408
  _a.sent();
2310
2409
  return [2 /*return*/, this.retryableWrite(chunk, attempt + 1)];
2311
- case 7: throw err_3;
2312
- case 8: return [2 /*return*/];
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 currentSize, baseThreshold, criticalThreshold, pressure, waitTime, retryCount, maxRetries, now;
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
- currentSize = this.queueSize;
2324
- baseThreshold = this.options.bufferSize * 0.7 // 降低基础阈值,更早检测
2325
- ;
2326
- criticalThreshold = this.options.bufferSize * 0.9 // 临界阈值
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
- else {
2357
- // 轻度背压:短时间等待
2358
- waitTime = Math.min(20, pressure * 30);
2359
- }
2360
- retryCount = 0;
2361
- maxRetries = 3;
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 (!(this.queueSize >= baseThreshold && retryCount < maxRetries)) return [3 /*break*/, 3];
2365
- if (this.abortController.signal.aborted)
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
- retryCount++;
2371
- // 动态调整等待时间
2372
- waitTime = Math.min(waitTime * 1.5, 100);
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.forEach(function () {
2509
- // 这些任务的 Promise 会在执行时因为检查到 aborted 而被拒绝
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 (_a) {
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 start;
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
- if (this.queueSize <= 0 && !this.isProcessingQueue && this.writeQueue.length === 0)
2540
- return [2 /*return*/];
2541
- if (Date.now() - start > timeoutMs) {
2542
- console.warn("Stream writer: flush timeout with ".concat(this.queueSize, " bytes still queued"));
2543
- return [2 /*return*/];
2544
- }
2545
- return [4 /*yield*/, new Promise(function (r) { return setTimeout(r, 10); })];
2546
- case 2:
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 [3 /*break*/, 1];
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 (_b) {
2864
- switch (_b.label) {
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
- _b.label = 1;
3033
+ writerRef = null;
3034
+ _c.label = 1;
2878
3035
  case 1:
2879
- _b.trys.push([1, 23, 24, 27]);
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 = _b.sent();
3040
+ connection = _c.sent();
2884
3041
  connectionKey_1 = this.peerAddr.toString();
2885
3042
  state = this.getConnectionState(connection);
2886
- _b.label = 3;
3043
+ _c.label = 3;
2887
3044
  case 3:
2888
- _b.trys.push([3, 5, , 6]);
3045
+ _c.trys.push([3, 5, , 6]);
2889
3046
  return [4 /*yield*/, this.waitForStreamSlot(state, undefined, timeout)];
2890
3047
  case 4:
2891
- _b.sent();
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 = _b.sent();
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 = _b.sent();
3061
+ stream = _c.sent();
2905
3062
  streamManager = this.getStreamManagerFor(connection);
2906
3063
  return [4 /*yield*/, streamManager.getNextAppLevelStreamId()];
2907
3064
  case 8:
2908
- streamId_1 = _b.sent();
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 */_c) { /* 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 (payload.length < 5) {
3140
+ if (effectivePayload.length < 5) {
3141
+ // 头部字节不足 5,先缓存,等待后续帧补全
3142
+ headerPartialBuffer.push(effectivePayload);
2967
3143
  return;
2968
3144
  }
2969
- var lengthBytes = payload.slice(1, 5); // 消息长度的4字节
2970
- responseDataExpectedLength = new DataView(lengthBytes.buffer, lengthBytes.byteOffset).getUint32(0, false); // big-endian
2971
- if (responseDataExpectedLength < 0) {
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 = payload.subarray(5);
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
- // 如果当前 payload 足以包含完整的 gRPC 消息,重置缓冲区
2983
- var grpcData = payload.subarray(5); // 提取完整的 gRPC 消息
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
- responseBuffer.push(payload); // 将数据添加到缓冲区
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 _i = 0, responseBuffer_1 = responseBuffer; _i < responseBuffer_1.length; _i++) {
2999
- var chunk = responseBuffer_1[_i];
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
- // 检查是否是流的最后一个帧(END_STREAM 标志)
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
- parser.onEnd = function () {
3023
- //接收结束
3024
- if (!isResponseComplete) {
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 _i = 0, responseBuffer_3 = responseBuffer; _i < responseBuffer_3.length; _i++) {
3035
- var chunk = responseBuffer_3[_i];
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
- _b.sent();
3241
+ _c.sent();
3068
3242
  settingFrme = Http2Frame.createSettingsFrame();
3069
3243
  return [4 /*yield*/, writer_1.write(settingFrme)];
3070
3244
  case 10:
3071
- _b.sent();
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
- _b.sent();
3081
- headerFrame = Http2Frame.createHeadersFrame(streamId_1, method, true, this.token);
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
- _b.sent();
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
- _b.label = 13;
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
- _b.sent();
3095
- _b.label = 15;
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
- var checkResponse = function () {
3106
- if (isResponseComplete || exitFlag) {
3107
- // 使用新的完成标志
3108
- clearTimeout(t);
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
- _b.sent();
3120
- _b.label = 18;
3295
+ // 等待 responseData 不为空,或超时(事件驱动,不轮询)
3296
+ _c.sent();
3297
+ _c.label = 18;
3121
3298
  case 18:
3122
- _b.trys.push([18, 20, , 21]);
3299
+ _c.trys.push([18, 20, , 21]);
3123
3300
  return [4 /*yield*/, writer_1.flush(timeout)];
3124
3301
  case 19:
3125
- _b.sent();
3302
+ _c.sent();
3126
3303
  return [3 /*break*/, 21];
3127
3304
  case 20:
3128
- _b.sent();
3305
+ _c.sent();
3129
3306
  return [3 /*break*/, 21];
3130
3307
  case 21: return [4 /*yield*/, writer_1.end()];
3131
3308
  case 22:
3132
- _b.sent();
3133
- return [3 /*break*/, 27];
3309
+ _c.sent();
3310
+ return [3 /*break*/, 29];
3134
3311
  case 23:
3135
- err_3 = _b.sent();
3312
+ err_3 = _c.sent();
3136
3313
  console.error("unaryCall error:", err_3);
3137
3314
  throw err_3;
3138
3315
  case 24:
3139
- if (!stream) return [3 /*break*/, 26];
3140
- return [4 /*yield*/, stream.close()];
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
- _b.sent();
3143
- _b.label = 26;
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 27:
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
- context.signal.addEventListener("abort", function () {
3215
- cancelOperation();
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 messageBuffer, expectedMessageLength, hpack, connection, connectionKey, state, streamSlotAcquired, err_4, err_5, streamManager, streamId_2, writer_2, parser_1, sendWindowTimeout_1, writeFrame_1, writeDataFrames_1, preface, settingFrame, headerFrame, dfs, dfs0, batchSize_1, processingQueue_1, isProcessing_1, processNextBatch_1, addToQueue_1, _a, _b, _c, chunkOrChunks, chunksToProcess, addPromises, e_1_1, error_2, remainingQueue, queueWaitStart, maxQueueWaitMs, remainingQueue, finalFrame, err_6, err_7, conns, _i, conns_1, c;
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 _g, e_1, _h, _j;
3228
- var _k, _l, _m;
3229
- return __generator(this, function (_o) {
3230
- switch (_o.label) {
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
- messageBuffer = new Uint8Array(0);
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
- _o.label = 1;
3450
+ writer = null;
3451
+ _p.label = 1;
3240
3452
  case 1:
3241
- _o.trys.push([1, 49, 50, 64]);
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
- _o.label = 2;
3459
+ _p.label = 2;
3248
3460
  case 2:
3249
- _o.trys.push([2, 4, , 5]);
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
- _o.sent();
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 = _o.sent();
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 = _o.sent();
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
- _o.label = 7;
3478
+ _p.label = 7;
3267
3479
  case 7:
3268
- _o.trys.push([7, 9, , 10]);
3480
+ _p.trys.push([7, 9, , 10]);
3269
3481
  return [4 /*yield*/, this.waitForStreamSlot(state, internalController.signal, timeout)];
3270
3482
  case 8:
3271
- _o.sent();
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 = _o.sent();
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 = _o.sent();
3497
+ stream = _p.sent();
3286
3498
  streamManager = this.getStreamManagerFor(connection);
3287
3499
  return [4 /*yield*/, streamManager.getNextAppLevelStreamId()];
3288
3500
  case 12:
3289
- streamId_2 = _o.sent();
3290
- writer_2 = new StreamWriter(stream, {
3501
+ streamId_2 = _p.sent();
3502
+ writer = new StreamWriter(stream, {
3291
3503
  bufferSize: 16 * 1024 * 1024,
3292
3504
  });
3293
3505
  try {
3294
- writer_2.addEventListener("backpressure", function (e) {
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
- writer_2.addEventListener("drain", function () {
3510
+ writer.addEventListener("drain", function () {
3299
3511
  // drain event - no action needed
3300
3512
  });
3301
- writer_2.addEventListener("stalled", function (e) {
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
- writer_2.write(ping);
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 */_p) { /* ignore addEventListener errors */ }
3315
- parser_1 = new HTTP2Parser(writer_2, {
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
- if (onErrorCallback) {
3327
- onErrorCallback(new Error("GOAWAY received: code=".concat(info.errorCode)));
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, writer_2, internalController.signal, sendWindowTimeout_1)];
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*/, writer_2.write(frame)];
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 newBuffer, lengthBytes, completeMessage;
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
- newBuffer = new Uint8Array(messageBuffer.length + payload.length);
3401
- newBuffer.set(messageBuffer);
3402
- newBuffer.set(payload, messageBuffer.length);
3403
- messageBuffer = newBuffer;
3608
+ // 追加到分段列表,O(1),不拷贝历史数据
3609
+ msgChunks.push(payload);
3610
+ msgTotalLen += payload.length;
3404
3611
  // 处理缓冲区中的完整消息
3405
- while (messageBuffer.length > 0) {
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 === -1 && messageBuffer.length >= 5) {
3412
- lengthBytes = messageBuffer.slice(1, 5);
3413
- expectedMessageLength = new DataView(lengthBytes.buffer, lengthBytes.byteOffset).getUint32(0, false); // big-endian
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
- messageBuffer = messageBuffer.slice(expectedMessageLength + 5);
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
- if (onErrorCallback) {
3433
- onErrorCallback(error);
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
- writer_2.write(ackSettingFrame);
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
- var err = new Error(errMsg);
3458
- if (onErrorCallback) {
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
- console.error('Error in processStream:', error);
3469
- if (onErrorCallback) {
3470
- onErrorCallback(error);
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*/, writer_2.write(preface)];
3677
+ return [4 /*yield*/, writer.write(preface)];
3479
3678
  case 13:
3480
- _o.sent();
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*/, writer_2.write(settingFrame)];
3685
+ return [4 /*yield*/, writer.write(settingFrame)];
3487
3686
  case 14:
3488
- _o.sent();
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
- _o.sent();
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*/, writer_2.write(headerFrame)];
3705
+ return [4 /*yield*/, writer.write(headerFrame)];
3511
3706
  case 16:
3512
- _o.sent();
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
- _o.sent();
3711
+ _p.sent();
3517
3712
  // 检查是否已中止
3518
3713
  if (internalController.signal.aborted) {
3519
3714
  throw new Error("Operation aborted");
3520
3715
  }
3521
- return [3 /*break*/, 47];
3716
+ return [3 /*break*/, 45];
3522
3717
  case 18:
3523
3718
  if (!((mode === "client-streaming" || mode === "bidirectional") &&
3524
- dataSourceCallback)) return [3 /*break*/, 47];
3525
- return [4 /*yield*/, writer_2.write(headerFrame)];
3719
+ dataSourceCallback)) return [3 /*break*/, 45];
3720
+ return [4 /*yield*/, writer.write(headerFrame)];
3526
3721
  case 19:
3527
- _o.sent();
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
- _o.sent();
3537
- _o.label = 21;
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
- !internalController.signal.aborted) {
3604
- // 使用 setTimeout 避免阻塞,让新数据有机会加入队列
3605
- setTimeout(function () { return processNextBatch_1(); }, 0);
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
- _o.label = 22;
3837
+ _p.label = 22;
3629
3838
  case 22:
3630
- _o.trys.push([22, 36, , 37]);
3631
- _o.label = 23;
3839
+ _p.trys.push([22, 36, , 37]);
3840
+ _p.label = 23;
3632
3841
  case 23:
3633
- _o.trys.push([23, 29, 30, 35]);
3842
+ _p.trys.push([23, 29, 30, 35]);
3634
3843
  _a = true, _b = __asyncValues(dataSourceCallback());
3635
- _o.label = 24;
3844
+ _p.label = 24;
3636
3845
  case 24: return [4 /*yield*/, _b.next()];
3637
3846
  case 25:
3638
- if (!(_c = _o.sent(), _g = _c.done, !_g)) return [3 /*break*/, 28];
3639
- _j = _c.value;
3847
+ if (!(_c = _p.sent(), _h = _c.done, !_h)) return [3 /*break*/, 28];
3848
+ _k = _c.value;
3640
3849
  _a = false;
3641
- chunkOrChunks = _j;
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
- _o.sent();
3657
- _o.label = 27;
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 = _o.sent();
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
- _o.trys.push([30, , 33, 34]);
3668
- if (!(!_a && !_g && (_h = _b.return))) return [3 /*break*/, 32];
3669
- return [4 /*yield*/, _h.call(_b)];
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
- _o.sent();
3672
- _o.label = 32;
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 = _o.sent();
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
- queueWaitStart = Date.now();
3693
- maxQueueWaitMs = timeout;
3694
- _o.label = 38;
3695
- case 38:
3696
- if (!(processingQueue_1.length > 0 || isProcessing_1)) return [3 /*break*/, 40];
3697
- if (internalController.signal.aborted) {
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
- catch (err) {
3708
- console.warn("Error rejecting timeout promise:", err);
3908
+ if (processingQueue_1.length === 0 && !isProcessing_1) {
3909
+ resolve();
3910
+ return;
3709
3911
  }
3710
- });
3711
- throw new Error("Queue processing timeout");
3712
- }
3713
- return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 10); })];
3714
- case 39:
3715
- _o.sent();
3716
- return [3 /*break*/, 38];
3717
- case 40:
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.createDataFrame(streamId_2, new Uint8Array(), true);
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
- _o.sent();
3726
- _o.label = 42;
3933
+ _p.sent();
3934
+ return [3 /*break*/, 43];
3727
3935
  case 42:
3728
- _o.trys.push([42, 44, , 45]);
3729
- return [4 /*yield*/, writer_2.flush(timeout)];
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
- _o.sent();
3735
- return [3 /*break*/, 45];
3736
- case 45: return [4 /*yield*/, writer_2.end()];
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 48:
3747
- _o.sent();
3748
- if (onEndCallback) {
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
- return [3 /*break*/, 64];
3971
+ _p.label = 48;
3972
+ case 48: return [3 /*break*/, 64];
3752
3973
  case 49:
3753
- err_6 = _o.sent();
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
- if (onErrorCallback) {
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
- _o.label = 51;
4009
+ _p.label = 51;
3778
4010
  case 51:
3779
- _o.trys.push([51, 53, , 54]);
4011
+ _p.trys.push([51, 53, , 54]);
3780
4012
  return [4 /*yield*/, stream.close()];
3781
4013
  case 52:
3782
- _o.sent();
4014
+ _p.sent();
3783
4015
  return [3 /*break*/, 54];
3784
4016
  case 53:
3785
- err_7 = _o.sent();
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
- _o.label = 55;
4021
+ _p.label = 55;
3791
4022
  case 55:
3792
- _o.trys.push([55, 62, , 63]);
3793
- conns = ((_l = (_k = this.node).getConnections) === null || _l === void 0 ? void 0 : _l.call(_k, this.peerAddr)) || [];
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
- _o.label = 56;
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
- _o.label = 57;
4030
+ _p.label = 57;
3800
4031
  case 57:
3801
- _o.trys.push([57, 59, , 60]);
3802
- return [4 /*yield*/, ((_m = c.close) === null || _m === void 0 ? void 0 : _m.call(c))];
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
- _o.sent();
4035
+ _p.sent();
3805
4036
  return [3 /*break*/, 60];
3806
4037
  case 59:
3807
- _o.sent();
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
- _o.sent();
4045
+ _p.sent();
3815
4046
  return [3 /*break*/, 63];
3816
4047
  case 63:
3817
4048
  if (streamSlotAcquired && state) {