grpc-libp2p-client 0.0.38 → 0.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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
  }
@@ -2136,13 +2245,14 @@
2136
2245
  };
2137
2246
  };
2138
2247
  // 简单的卡顿看门狗:当队列长期高位且 bytesDrained 无进展时发出 stalled 事件
2248
+ // 使用递归 setTimeout 而非 setInterval,避免标签页后台恢复时回调堆积导致 Violation
2139
2249
  StreamWriter.prototype.startWatchdog = function (intervalMs, stallMs) {
2140
2250
  var _this = this;
2141
2251
  if (intervalMs === void 0) { intervalMs = 500; }
2142
2252
  if (stallMs === void 0) { stallMs = 1500; }
2143
2253
  if (this.watchdogTimer)
2144
2254
  return;
2145
- this.watchdogTimer = setInterval(function () {
2255
+ var tick = function () {
2146
2256
  if (_this.abortController.signal.aborted)
2147
2257
  return;
2148
2258
  var baseThreshold = _this.options.bufferSize * 0.7;
@@ -2153,7 +2263,13 @@
2153
2263
  if (!_this.stallStartAt)
2154
2264
  _this.stallStartAt = now;
2155
2265
  if (now - _this.stallStartAt >= stallMs) {
2156
- _this.dispatchEvent(new CustomEvent('stalled', { detail: { queueSize: q, drained: _this.bytesDrained, sinceMs: now - _this.stallStartAt } }));
2266
+ // 异步触发事件,让当前 tick 立即返回,避免同步事件处理器阻塞主线程
2267
+ var detail_1 = { queueSize: q, drained: _this.bytesDrained, sinceMs: now - _this.stallStartAt };
2268
+ setTimeout(function () {
2269
+ if (!_this.abortController.signal.aborted) {
2270
+ _this.dispatchEvent(new CustomEvent('stalled', { detail: detail_1 }));
2271
+ }
2272
+ }, 0);
2157
2273
  // 避免持续触发,推进起点
2158
2274
  _this.stallStartAt = now;
2159
2275
  }
@@ -2168,7 +2284,10 @@
2168
2284
  // 队列回落,重置
2169
2285
  _this.stallStartAt = 0;
2170
2286
  }
2171
- }, intervalMs);
2287
+ // 本次 tick 完成后再安排下一次,不会因主线程繁忙而堆积
2288
+ _this.watchdogTimer = setTimeout(tick, intervalMs);
2289
+ };
2290
+ this.watchdogTimer = setTimeout(tick, intervalMs);
2172
2291
  };
2173
2292
  StreamWriter.prototype.write = function (data) {
2174
2293
  return __awaiter(this, void 0, void 0, function () {
@@ -2227,17 +2346,17 @@
2227
2346
  };
2228
2347
  StreamWriter.prototype.writeChunks = function (buffer) {
2229
2348
  return __awaiter(this, void 0, void 0, function () {
2230
- var offset, end, chunk;
2349
+ var src, offset, end, chunk;
2231
2350
  return __generator(this, function (_a) {
2232
2351
  switch (_a.label) {
2233
2352
  case 0:
2353
+ src = new Uint8Array(buffer);
2234
2354
  offset = 0;
2235
2355
  _a.label = 1;
2236
2356
  case 1:
2237
- if (!(offset < buffer.byteLength)) return [3 /*break*/, 4];
2238
- end = Math.min(offset + this.options.chunkSize, buffer.byteLength);
2239
- chunk = new Uint8Array(end - offset);
2240
- chunk.set(new Uint8Array(buffer.slice(offset, end)));
2357
+ if (!(offset < src.byteLength)) return [3 /*break*/, 4];
2358
+ end = Math.min(offset + this.options.chunkSize, src.byteLength);
2359
+ chunk = src.subarray(offset, end);
2241
2360
  return [4 /*yield*/, this.retryableWrite(chunk)];
2242
2361
  case 2:
2243
2362
  _a.sent();
@@ -2254,7 +2373,6 @@
2254
2373
  StreamWriter.prototype.retryableWrite = function (chunk_1) {
2255
2374
  return __awaiter(this, arguments, void 0, function (chunk, attempt) {
2256
2375
  var currentSize, threshold, err_3, delay_1;
2257
- var _this = this;
2258
2376
  if (attempt === void 0) { attempt = 0; }
2259
2377
  return __generator(this, function (_a) {
2260
2378
  switch (_a.label) {
@@ -2265,7 +2383,7 @@
2265
2383
  }
2266
2384
  _a.label = 1;
2267
2385
  case 1:
2268
- _a.trys.push([1, 5, , 8]);
2386
+ _a.trys.push([1, 4, , 7]);
2269
2387
  currentSize = this.queueSize;
2270
2388
  threshold = this.options.bufferSize * 0.7;
2271
2389
  if (!(currentSize > threshold)) return [3 /*break*/, 3];
@@ -2278,94 +2396,92 @@
2278
2396
  if (this.abortController.signal.aborted) {
2279
2397
  throw new Error('Stream aborted during backpressure monitoring');
2280
2398
  }
2281
- return [4 /*yield*/, new Promise(function (resolve, reject) {
2282
- try {
2283
- _this.p.push(chunk);
2284
- }
2285
- catch (err) {
2286
- reject(err);
2287
- }
2288
- resolve();
2289
- })];
2399
+ // push 是同步操作,直接调用即可
2400
+ this.p.push(chunk);
2401
+ return [3 /*break*/, 7];
2290
2402
  case 4:
2291
- _a.sent();
2292
- return [3 /*break*/, 8];
2293
- case 5:
2294
2403
  err_3 = _a.sent();
2295
- if (!(attempt < this.options.retries)) return [3 /*break*/, 7];
2404
+ if (!(!this.abortController.signal.aborted && attempt < this.options.retries)) return [3 /*break*/, 6];
2296
2405
  delay_1 = this.calculateRetryDelay(attempt);
2297
2406
  return [4 /*yield*/, new Promise(function (r) { return setTimeout(r, delay_1); })];
2298
- case 6:
2407
+ case 5:
2299
2408
  _a.sent();
2300
2409
  return [2 /*return*/, this.retryableWrite(chunk, attempt + 1)];
2301
- case 7: throw err_3;
2302
- case 8: return [2 /*return*/];
2410
+ case 6: throw err_3;
2411
+ case 7: return [2 /*return*/];
2303
2412
  }
2304
2413
  });
2305
2414
  });
2306
2415
  };
2307
2416
  StreamWriter.prototype.monitorBackpressure = function () {
2308
2417
  return __awaiter(this, void 0, void 0, function () {
2309
- var 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;
2310
2420
  return __generator(this, function (_a) {
2311
2421
  switch (_a.label) {
2312
2422
  case 0:
2313
- currentSize = this.queueSize;
2314
- baseThreshold = this.options.bufferSize * 0.7 // 降低基础阈值,更早检测
2315
- ;
2316
- criticalThreshold = this.options.bufferSize * 0.9 // 临界阈值
2317
- ;
2318
- // 快速路径:无背压时直接返回
2319
- if (currentSize < baseThreshold) {
2423
+ baseThreshold = this.options.bufferSize * 0.7;
2424
+ criticalThreshold = this.options.bufferSize * 0.9;
2425
+ // 快速路径
2426
+ if (this.queueSize < baseThreshold) {
2320
2427
  if (this.isBackpressure) {
2321
2428
  this.isBackpressure = false;
2322
- this.dispatchBackpressureEvent({
2323
- currentSize: currentSize,
2324
- averageSize: this.getAverageQueueSize(),
2325
- threshold: baseThreshold,
2326
- waitingTime: 0
2327
- });
2429
+ this.dispatchBackpressureEvent({ currentSize: this.queueSize, averageSize: this.getAverageQueueSize(), threshold: baseThreshold, waitingTime: 0 });
2328
2430
  }
2329
2431
  return [2 /*return*/];
2330
2432
  }
2331
- // 进入背压状态
2332
2433
  if (!this.isBackpressure) {
2333
2434
  this.isBackpressure = true;
2334
- this.dispatchBackpressureEvent({
2335
- currentSize: currentSize,
2336
- averageSize: this.getAverageQueueSize(),
2337
- threshold: baseThreshold,
2338
- waitingTime: 0
2339
- });
2435
+ this.dispatchBackpressureEvent({ currentSize: this.queueSize, averageSize: this.getAverageQueueSize(), threshold: baseThreshold, waitingTime: 0 });
2340
2436
  }
2341
- pressure = currentSize / this.options.bufferSize;
2342
- if (currentSize >= criticalThreshold) {
2343
- // 临界状态:长时间等待
2344
- waitTime = 50 + Math.min(200, pressure * 100);
2345
- }
2346
- else {
2347
- // 轻度背压:短时间等待
2348
- waitTime = Math.min(20, pressure * 30);
2349
- }
2350
- retryCount = 0;
2351
- 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;
2352
2469
  _a.label = 1;
2353
2470
  case 1:
2354
- if (!(this.queueSize >= baseThreshold && retryCount < maxRetries)) return [3 /*break*/, 3];
2355
- if (this.abortController.signal.aborted)
2356
- return [3 /*break*/, 3];
2357
- return [4 /*yield*/, new Promise(function (r) { return setTimeout(r, waitTime); })];
2471
+ if (!(i < maxRounds)) return [3 /*break*/, 4];
2472
+ return [5 /*yield**/, _loop_1(i)];
2358
2473
  case 2:
2359
- _a.sent();
2360
- retryCount++;
2361
- // 动态调整等待时间
2362
- waitTime = Math.min(waitTime * 1.5, 100);
2363
- return [3 /*break*/, 1];
2474
+ state_1 = _a.sent();
2475
+ if (state_1 === "break")
2476
+ return [3 /*break*/, 4];
2477
+ _a.label = 3;
2364
2478
  case 3:
2365
- // 如果仍然背压但达到最大重试次数,记录警告但继续执行
2479
+ i++;
2480
+ return [3 /*break*/, 1];
2481
+ case 4:
2366
2482
  if (this.queueSize >= baseThreshold) {
2367
2483
  now = Date.now();
2368
- if (now - this.lastBpWarnAt > 1000) { // 节流警告
2484
+ if (now - this.lastBpWarnAt > 1000) {
2369
2485
  this.lastBpWarnAt = now;
2370
2486
  console.warn("Stream writer: High backpressure detected (".concat(this.queueSize, " bytes), continuing anyway"));
2371
2487
  }
@@ -2493,19 +2609,31 @@
2493
2609
  if (!this.abortController.signal.aborted) {
2494
2610
  this.abortController.abort();
2495
2611
  }
2496
- // 立即拒绝所有待处理的写入任务,避免它们继续执行
2612
+ // 执行所有待处理的写入任务:它们会检查 signal.aborted 并立即 resolve,
2613
+ // 不执行的话调用方的 Promise 会永远挂住
2497
2614
  var pendingTasks = this.writeQueue.splice(0);
2498
- pendingTasks.forEach(function () {
2499
- // 这些任务的 Promise 会在执行时因为检查到 aborted 而被拒绝
2500
- });
2615
+ for (var _i = 0, pendingTasks_1 = pendingTasks; _i < pendingTasks_1.length; _i++) {
2616
+ var task = pendingTasks_1[_i];
2617
+ task().catch(function () { });
2618
+ }
2619
+ // 唤醒所有 drainWaiters(flush / monitorBackpressure 中的等待者),
2620
+ // 让它们检查 signal.aborted 并立即 resolve,不必等到各自的超时
2621
+ var ws = this.drainWaiters.splice(0);
2622
+ for (var _a = 0, ws_2 = ws; _a < ws_2.length; _a++) {
2623
+ var fn = ws_2[_a];
2624
+ try {
2625
+ fn();
2626
+ }
2627
+ catch ( /* ignore */_b) { /* ignore */ }
2628
+ }
2501
2629
  try {
2502
2630
  this.p.end();
2503
2631
  }
2504
- catch (_a) {
2632
+ catch (_c) {
2505
2633
  // Ignore errors when ending pushable
2506
2634
  }
2507
2635
  if (this.watchdogTimer) {
2508
- clearInterval(this.watchdogTimer);
2636
+ clearTimeout(this.watchdogTimer);
2509
2637
  this.watchdogTimer = undefined;
2510
2638
  }
2511
2639
  };
@@ -2513,30 +2641,49 @@
2513
2641
  // 默认超时 10s,避免无限等待
2514
2642
  StreamWriter.prototype.flush = function () {
2515
2643
  return __awaiter(this, arguments, void 0, function (timeoutMs) {
2516
- var start;
2644
+ var _this = this;
2517
2645
  if (timeoutMs === void 0) { timeoutMs = 10000; }
2518
2646
  return __generator(this, function (_a) {
2519
2647
  switch (_a.label) {
2520
2648
  case 0:
2521
- start = Date.now();
2522
2649
  // 快速路径
2523
2650
  if (this.queueSize <= 0 && !this.isProcessingQueue && this.writeQueue.length === 0)
2524
2651
  return [2 /*return*/];
2525
- _a.label = 1;
2526
- case 1:
2527
2652
  if (this.abortController.signal.aborted)
2528
2653
  return [2 /*return*/];
2529
- if (this.queueSize <= 0 && !this.isProcessingQueue && this.writeQueue.length === 0)
2530
- return [2 /*return*/];
2531
- if (Date.now() - start > timeoutMs) {
2532
- console.warn("Stream writer: flush timeout with ".concat(this.queueSize, " bytes still queued"));
2533
- return [2 /*return*/];
2534
- }
2535
- return [4 /*yield*/, new Promise(function (r) { return setTimeout(r, 10); })];
2536
- 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:
2537
2685
  _a.sent();
2538
- return [3 /*break*/, 1];
2539
- case 3: return [2 /*return*/];
2686
+ return [2 /*return*/];
2540
2687
  }
2541
2688
  });
2542
2689
  });
@@ -2845,45 +2992,65 @@
2845
2992
  Libp2pGrpcClient.prototype.setToken = function (token) {
2846
2993
  this.token = token;
2847
2994
  };
2995
+ /** 从 peerAddr 提取 HTTP/2 :authority 字段(host:port 格式) */
2996
+ Libp2pGrpcClient.prototype.getAuthority = function () {
2997
+ try {
2998
+ var addr = this.peerAddr.toString();
2999
+ var ip4 = addr.match(/\/ip4\/(\d[\d.]+)\/tcp\/(\d+)/);
3000
+ if (ip4)
3001
+ return "".concat(ip4[1], ":").concat(ip4[2]);
3002
+ var ip6 = addr.match(/\/ip6\/([^/]+)\/tcp\/(\d+)/);
3003
+ if (ip6)
3004
+ return "[".concat(ip6[1], "]:").concat(ip6[2]);
3005
+ var dns = addr.match(/\/dns(?:4|6)?\/([.\w-]+)\/tcp\/(\d+)/);
3006
+ if (dns)
3007
+ return "".concat(dns[1], ":").concat(dns[2]);
3008
+ }
3009
+ catch ( /* ignore */_a) { /* ignore */ }
3010
+ return 'localhost';
3011
+ };
2848
3012
  Libp2pGrpcClient.prototype.unaryCall = function (method_1, requestData_1) {
2849
3013
  return __awaiter(this, arguments, void 0, function (method, requestData, timeout) {
2850
- var stream, responseData, responseBuffer, responseDataExpectedLength, hpack, exitFlag, errMsg, isResponseComplete, connection, state, streamSlotAcquired, connectionKey_1, err_2, streamManager, streamId_1, writer_1, parser, preface, settingFrme, headerFrame, dataFrames, frameSendTimeout, _i, dataFrames_1, df, err_3;
3014
+ var stream, responseData, responseBuffer, responseDataExpectedLength, headerPartialBuffer, hpack, exitFlag, errMsg, isResponseComplete, notifyResponseComplete, connection, state, streamSlotAcquired, writerRef, connectionKey_1, err_2, streamManager, streamId_1, writer_1, parser, preface, settingFrme, headerFrame, dataFrames, frameSendTimeout, _i, dataFrames_1, df, err_3;
2851
3015
  var _this = this;
2852
3016
  if (timeout === void 0) { timeout = 30000; }
2853
- return __generator(this, function (_b) {
2854
- switch (_b.label) {
3017
+ return __generator(this, function (_c) {
3018
+ switch (_c.label) {
2855
3019
  case 0:
2856
3020
  stream = null;
2857
3021
  responseData = null;
2858
3022
  responseBuffer = [];
2859
3023
  responseDataExpectedLength = -1;
3024
+ headerPartialBuffer = [];
2860
3025
  hpack = new HPACK();
2861
3026
  exitFlag = false;
2862
3027
  errMsg = "";
2863
3028
  isResponseComplete = false;
3029
+ notifyResponseComplete = null;
2864
3030
  connection = null;
2865
3031
  state = null;
2866
3032
  streamSlotAcquired = false;
2867
- _b.label = 1;
3033
+ writerRef = null;
3034
+ _c.label = 1;
2868
3035
  case 1:
2869
- _b.trys.push([1, 23, 24, 27]);
3036
+ _c.trys.push([1, 23, 24, 29]);
2870
3037
  return [4 /*yield*/, this.acquireConnection(false)];
2871
3038
  case 2:
2872
3039
  // const stream = await this.node.dialProtocol(this.peerAddr, this.protocol)
2873
- connection = _b.sent();
3040
+ connection = _c.sent();
2874
3041
  connectionKey_1 = this.peerAddr.toString();
2875
3042
  state = this.getConnectionState(connection);
2876
- _b.label = 3;
3043
+ _c.label = 3;
2877
3044
  case 3:
2878
- _b.trys.push([3, 5, , 6]);
3045
+ _c.trys.push([3, 5, , 6]);
2879
3046
  return [4 /*yield*/, this.waitForStreamSlot(state, undefined, timeout)];
2880
3047
  case 4:
2881
- _b.sent();
3048
+ _c.sent();
2882
3049
  state.activeStreams += 1;
2883
3050
  streamSlotAcquired = true;
2884
3051
  return [3 /*break*/, 6];
2885
3052
  case 5:
2886
- err_2 = _b.sent();
3053
+ err_2 = _c.sent();
2887
3054
  console.warn("[unaryCall] waiting for stream slot failed:", err_2);
2888
3055
  throw err_2;
2889
3056
  case 6: return [4 /*yield*/, connection.newStream(this.protocol, {
@@ -2891,14 +3058,15 @@
2891
3058
  negotiateFully: false,
2892
3059
  })];
2893
3060
  case 7:
2894
- stream = _b.sent();
3061
+ stream = _c.sent();
2895
3062
  streamManager = this.getStreamManagerFor(connection);
2896
3063
  return [4 /*yield*/, streamManager.getNextAppLevelStreamId()];
2897
3064
  case 8:
2898
- streamId_1 = _b.sent();
3065
+ streamId_1 = _c.sent();
2899
3066
  writer_1 = new StreamWriter(stream, {
2900
3067
  bufferSize: 16 * 1024 * 1024,
2901
3068
  });
3069
+ writerRef = writer_1;
2902
3070
  try {
2903
3071
  writer_1.addEventListener("backpressure", function (e) {
2904
3072
  var d = e.detail || {};
@@ -2920,7 +3088,7 @@
2920
3088
  catch ( /* ignore ping write errors */_b) { /* ignore ping write errors */ }
2921
3089
  });
2922
3090
  }
2923
- catch ( /* ignore addEventListener errors */_c) { /* ignore addEventListener errors */ }
3091
+ catch ( /* ignore addEventListener errors */_d) { /* ignore addEventListener errors */ }
2924
3092
  parser = new HTTP2Parser(writer_1);
2925
3093
  parser.onGoaway = function (info) {
2926
3094
  console.warn("[unaryCall] GOAWAY received from server", info);
@@ -2930,6 +3098,7 @@
2930
3098
  }
2931
3099
  exitFlag = true;
2932
3100
  errMsg = "GOAWAY received: code=".concat(info.errorCode);
3101
+ notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete(); // 唤醒等待中的 Promise
2933
3102
  try {
2934
3103
  connection === null || connection === void 0 ? void 0 : connection.close();
2935
3104
  }
@@ -2948,86 +3117,99 @@
2948
3117
  parser.registerOutboundStream(streamId_1);
2949
3118
  responseDataExpectedLength = -1; // 重置期望长度
2950
3119
  responseBuffer = []; // 重置缓冲区
3120
+ headerPartialBuffer = []; // 重置跨帧头部缓冲
2951
3121
  parser.onData = function (payload, frameHeader) {
2952
3122
  //接收数据
2953
3123
  if (responseDataExpectedLength === -1) {
2954
3124
  //grpc消息头部未读取
3125
+ // 如果有跨帧积累的部分头字节,先与本帧 payload 合并
3126
+ var effectivePayload = payload;
3127
+ if (headerPartialBuffer.length > 0) {
3128
+ headerPartialBuffer.push(payload);
3129
+ var totalLen = headerPartialBuffer.reduce(function (s, c) { return s + c.length; }, 0);
3130
+ effectivePayload = new Uint8Array(totalLen);
3131
+ var off = 0;
3132
+ for (var _i = 0, headerPartialBuffer_1 = headerPartialBuffer; _i < headerPartialBuffer_1.length; _i++) {
3133
+ var c = headerPartialBuffer_1[_i];
3134
+ effectivePayload.set(c, off);
3135
+ off += c.length;
3136
+ }
3137
+ headerPartialBuffer = [];
3138
+ }
2955
3139
  //提取gRPC消息头部
2956
- if (payload.length < 5) {
3140
+ if (effectivePayload.length < 5) {
3141
+ // 头部字节不足 5,先缓存,等待后续帧补全
3142
+ headerPartialBuffer.push(effectivePayload);
2957
3143
  return;
2958
3144
  }
2959
- var lengthBytes = payload.slice(1, 5); // 消息长度的4字节
2960
- responseDataExpectedLength = new DataView(lengthBytes.buffer, lengthBytes.byteOffset).getUint32(0, false); // big-endian
2961
- if (responseDataExpectedLength < 0) {
2962
- throw new Error("Invalid gRPC message length");
2963
- }
2964
- if (responseDataExpectedLength + 5 > payload.length) {
3145
+ var lengthBytes = effectivePayload.slice(1, 5); // 消息长度的4字节
3146
+ responseDataExpectedLength = new DataView(lengthBytes.buffer, lengthBytes.byteOffset).getUint32(0, false); // big-endian(getUint32 返回无符号整数,结果不会为负)
3147
+ if (responseDataExpectedLength + 5 > effectivePayload.length) {
2965
3148
  // 如果当前 payload 不足以包含完整的 gRPC 消息,缓存数据
2966
- var grpcData = payload.subarray(5);
3149
+ var grpcData = effectivePayload.subarray(5);
2967
3150
  responseBuffer.push(grpcData);
2968
3151
  responseDataExpectedLength -= grpcData.length; // 更新期望长度
2969
3152
  return;
2970
3153
  }
2971
3154
  else {
2972
- // 如果当前 payload 足以包含完整的 gRPC 消息,重置缓冲区
2973
- var grpcData = payload.subarray(5); // 提取完整的 gRPC 消息
3155
+ // payload 已包含完整的 gRPC 消息体,精确截取(避免尾部多余字节污染)
3156
+ var msgLen = responseDataExpectedLength;
3157
+ var grpcData = effectivePayload.slice(5, 5 + msgLen);
2974
3158
  responseBuffer.push(grpcData);
2975
3159
  responseData = grpcData;
2976
3160
  isResponseComplete = true;
2977
- responseDataExpectedLength = -1; // 重置期望长度
3161
+ responseDataExpectedLength = -1;
3162
+ notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete();
2978
3163
  }
2979
3164
  }
2980
3165
  else if (responseDataExpectedLength > 0) {
2981
3166
  //grpc消息头部已读取
2982
- responseBuffer.push(payload); // 将数据添加到缓冲区
2983
- responseDataExpectedLength -= payload.length; // 更新期望长度
3167
+ responseDataExpectedLength -= payload.length;
2984
3168
  if (responseDataExpectedLength <= 0) {
2985
- // 如果缓冲区中的数据已经完全处理,重置缓冲区
3169
+ // 超收时截掉多余字节
3170
+ var exactPayload = responseDataExpectedLength < 0
3171
+ ? payload.slice(0, payload.length + responseDataExpectedLength)
3172
+ : payload;
3173
+ responseBuffer.push(exactPayload);
2986
3174
  responseData = new Uint8Array(responseBuffer.reduce(function (sum, chunk) { return sum + chunk.length; }, 0));
2987
3175
  var offset = 0;
2988
- for (var _i = 0, responseBuffer_1 = responseBuffer; _i < responseBuffer_1.length; _i++) {
2989
- var chunk = responseBuffer_1[_i];
3176
+ for (var _a = 0, responseBuffer_1 = responseBuffer; _a < responseBuffer_1.length; _a++) {
3177
+ var chunk = responseBuffer_1[_a];
2990
3178
  responseData.set(chunk, offset);
2991
3179
  offset += chunk.length;
2992
3180
  }
2993
3181
  responseDataExpectedLength = -1;
2994
- isResponseComplete = true; // 设置响应完成标志
3182
+ isResponseComplete = true;
3183
+ notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete();
2995
3184
  }
2996
- }
2997
- // 检查是否是流的最后一个帧(END_STREAM 标志)
2998
- if (frameHeader && frameHeader.flags & 0x1 && !isResponseComplete) {
2999
- // END_STREAM flag
3000
- // 合并所有缓冲的数据
3001
- var totalLength = responseBuffer.reduce(function (sum, chunk) { return sum + chunk.length; }, 0);
3002
- responseData = new Uint8Array(totalLength);
3003
- var offset = 0;
3004
- for (var _a = 0, responseBuffer_2 = responseBuffer; _a < responseBuffer_2.length; _a++) {
3005
- var chunk = responseBuffer_2[_a];
3006
- responseData.set(chunk, offset);
3007
- offset += chunk.length;
3185
+ else {
3186
+ responseBuffer.push(payload); // 还不完整,继续累积
3008
3187
  }
3009
- isResponseComplete = true;
3010
3188
  }
3011
- };
3012
- parser.onEnd = function () {
3013
- //接收结束
3014
- if (!isResponseComplete) {
3015
- isResponseComplete = true; // 设置响应完成标志
3016
- if (responseBuffer.length === 0) {
3017
- responseData = new Uint8Array(); // 如果没有数据,返回空数组
3018
- }
3019
- else {
3020
- // 合并所有缓冲的数据
3021
- var totalLength = responseBuffer.reduce(function (sum, chunk) { return sum + chunk.length; }, 0);
3189
+ // END_STREAM 兜底:数据路径已处理大多数情况;此分支仅在边缘情况下触发
3190
+ if (frameHeader && frameHeader.flags & 0x1 && !isResponseComplete) {
3191
+ if (responseBuffer.length > 0) {
3192
+ var totalLength = responseBuffer.reduce(function (sum, c) { return sum + c.length; }, 0);
3022
3193
  responseData = new Uint8Array(totalLength);
3023
3194
  var offset = 0;
3024
- for (var _i = 0, responseBuffer_3 = responseBuffer; _i < responseBuffer_3.length; _i++) {
3025
- var chunk = responseBuffer_3[_i];
3195
+ for (var _b = 0, responseBuffer_2 = responseBuffer; _b < responseBuffer_2.length; _b++) {
3196
+ var chunk = responseBuffer_2[_b];
3026
3197
  responseData.set(chunk, offset);
3027
3198
  offset += chunk.length;
3028
3199
  }
3029
- isResponseComplete = true;
3030
3200
  }
3201
+ else {
3202
+ responseData = new Uint8Array(0);
3203
+ }
3204
+ isResponseComplete = true;
3205
+ notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete();
3206
+ }
3207
+ };
3208
+ parser.onEnd = function () {
3209
+ // 流结束时若响应未标记完成(空响应 / 纯 trailers),强制标记并唤醒等待者
3210
+ if (!isResponseComplete) {
3211
+ isResponseComplete = true;
3212
+ notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete();
3031
3213
  }
3032
3214
  };
3033
3215
  parser.onSettings = function () {
@@ -3041,6 +3223,7 @@
3041
3223
  else if (plainHeaders.get("grpc-status") !== undefined) {
3042
3224
  exitFlag = true;
3043
3225
  errMsg = plainHeaders.get("grpc-message") || "gRPC call failed";
3226
+ notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete(); // 唤醒等待中的 Promise
3044
3227
  }
3045
3228
  };
3046
3229
  // 启动后台流处理,捕获任何异步错误
@@ -3050,94 +3233,109 @@
3050
3233
  if (!errMsg) {
3051
3234
  errMsg = error instanceof Error ? error.message : 'Stream processing failed';
3052
3235
  }
3236
+ notifyResponseComplete === null || notifyResponseComplete === void 0 ? void 0 : notifyResponseComplete(); // 流处理异常也需唤醒等待者
3053
3237
  });
3054
3238
  preface = Http2Frame.createPreface();
3055
3239
  return [4 /*yield*/, writer_1.write(preface)];
3056
3240
  case 9:
3057
- _b.sent();
3241
+ _c.sent();
3058
3242
  settingFrme = Http2Frame.createSettingsFrame();
3059
3243
  return [4 /*yield*/, writer_1.write(settingFrme)];
3060
3244
  case 10:
3061
- _b.sent();
3245
+ _c.sent();
3062
3246
  // 等待对端 SETTINGS 或 ACK,择一即可,避免偶发握手竞态
3247
+ // 注意:未胜出的 promise 内部有超时定时器,它们最终会 reject。
3248
+ // 必须绑定 .catch(…) 消除错误,否则在 Node.js 新版本中会导致 UnhandledPromiseRejection 崩溃。
3063
3249
  return [4 /*yield*/, Promise.race([
3064
- parser.waitForPeerSettings(1000),
3065
- parser.waitForSettingsAck(),
3250
+ parser.waitForPeerSettings(1000).catch(function () { }),
3251
+ parser.waitForSettingsAck().catch(function () { }),
3066
3252
  new Promise(function (res) { return setTimeout(res, 300); }),
3067
3253
  ])];
3068
3254
  case 11:
3069
3255
  // 等待对端 SETTINGS 或 ACK,择一即可,避免偶发握手竞态
3070
- _b.sent();
3071
- 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());
3072
3260
  return [4 /*yield*/, writer_1.write(headerFrame)];
3073
3261
  case 12:
3074
- _b.sent();
3262
+ _c.sent();
3075
3263
  dataFrames = Http2Frame.createDataFrames(streamId_1, requestData, true);
3076
3264
  frameSendTimeout = timeout > 0 ? timeout : DEFAULT_SEND_WINDOW_TIMEOUT;
3077
3265
  _i = 0, dataFrames_1 = dataFrames;
3078
- _b.label = 13;
3266
+ _c.label = 13;
3079
3267
  case 13:
3080
3268
  if (!(_i < dataFrames_1.length)) return [3 /*break*/, 16];
3081
3269
  df = dataFrames_1[_i];
3082
3270
  return [4 /*yield*/, this.sendFrameWithFlowControl(parser, streamId_1, df, writer_1, undefined, frameSendTimeout)];
3083
3271
  case 14:
3084
- _b.sent();
3085
- _b.label = 15;
3272
+ _c.sent();
3273
+ _c.label = 15;
3086
3274
  case 15:
3087
3275
  _i++;
3088
3276
  return [3 /*break*/, 13];
3089
3277
  case 16:
3090
- // 等待responseData 不为空,或超时
3278
+ // 等待 responseData 不为空,或超时(事件驱动,不轮询)
3091
3279
  return [4 /*yield*/, new Promise(function (resolve, reject) {
3280
+ if (isResponseComplete || exitFlag) {
3281
+ resolve();
3282
+ return;
3283
+ }
3092
3284
  var t = setTimeout(function () {
3285
+ notifyResponseComplete = null;
3093
3286
  reject(new Error("gRPC response timeout"));
3094
3287
  }, timeout);
3095
- var checkResponse = function () {
3096
- if (isResponseComplete || exitFlag) {
3097
- // 使用新的完成标志
3098
- clearTimeout(t);
3099
- resolve(responseData);
3100
- }
3101
- else {
3102
- setTimeout(checkResponse, 50);
3103
- }
3288
+ notifyResponseComplete = function () {
3289
+ clearTimeout(t);
3290
+ notifyResponseComplete = null;
3291
+ resolve();
3104
3292
  };
3105
- checkResponse();
3106
3293
  })];
3107
3294
  case 17:
3108
- // 等待responseData 不为空,或超时
3109
- _b.sent();
3110
- _b.label = 18;
3295
+ // 等待 responseData 不为空,或超时(事件驱动,不轮询)
3296
+ _c.sent();
3297
+ _c.label = 18;
3111
3298
  case 18:
3112
- _b.trys.push([18, 20, , 21]);
3299
+ _c.trys.push([18, 20, , 21]);
3113
3300
  return [4 /*yield*/, writer_1.flush(timeout)];
3114
3301
  case 19:
3115
- _b.sent();
3302
+ _c.sent();
3116
3303
  return [3 /*break*/, 21];
3117
3304
  case 20:
3118
- _b.sent();
3305
+ _c.sent();
3119
3306
  return [3 /*break*/, 21];
3120
3307
  case 21: return [4 /*yield*/, writer_1.end()];
3121
3308
  case 22:
3122
- _b.sent();
3123
- return [3 /*break*/, 27];
3309
+ _c.sent();
3310
+ return [3 /*break*/, 29];
3124
3311
  case 23:
3125
- err_3 = _b.sent();
3312
+ err_3 = _c.sent();
3126
3313
  console.error("unaryCall error:", err_3);
3127
3314
  throw err_3;
3128
3315
  case 24:
3129
- if (!stream) return [3 /*break*/, 26];
3130
- 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;
3131
3323
  case 25:
3132
- _b.sent();
3133
- _b.label = 26;
3324
+ _c.trys.push([25, 27, , 28]);
3325
+ return [4 /*yield*/, stream.close()];
3134
3326
  case 26:
3327
+ _c.sent();
3328
+ return [3 /*break*/, 28];
3329
+ case 27:
3330
+ _c.sent();
3331
+ return [3 /*break*/, 28];
3332
+ case 28:
3135
3333
  if (streamSlotAcquired && state) {
3136
3334
  state.activeStreams = Math.max(0, state.activeStreams - 1);
3137
3335
  this.notifyStreamSlotAvailable(state);
3138
3336
  }
3139
3337
  return [7 /*endfinally*/];
3140
- case 27:
3338
+ case 29:
3141
3339
  if (exitFlag) {
3142
3340
  throw new Error(errMsg);
3143
3341
  }
@@ -3166,7 +3364,7 @@
3166
3364
  */
3167
3365
  Libp2pGrpcClient.prototype.Call = function (method_1, requestData_1) {
3168
3366
  return __awaiter(this, arguments, void 0, function (method, requestData, timeout, mode, onDataCallback, dataSourceCallback, onEndCallback, onErrorCallback, context, options) {
3169
- var internalController, timeoutHandle, stream, profile, useFlowControl, cancelOperation, timeoutPromise, operationPromise, error_1;
3367
+ var internalController, timeoutHandle, stream, contextAbortHandler, profile, useFlowControl, cancelOperation, timeoutPromise, operationPromise, error_1;
3170
3368
  var _this = this;
3171
3369
  var _a;
3172
3370
  if (timeout === void 0) { timeout = 30000; }
@@ -3193,17 +3391,16 @@
3193
3391
  };
3194
3392
  // 如果提供了外部信号,监听它
3195
3393
  if (context === null || context === void 0 ? void 0 : context.signal) {
3196
- // 如果外部信号已经触发中止,立即返回
3394
+ // 如果外部信号已经触发中止,立即返回——避免启动 IIFE 后在 catch 中再次调用 onErrorCallback
3197
3395
  if (context.signal.aborted) {
3198
3396
  if (onErrorCallback) {
3199
3397
  onErrorCallback(new Error("Operation aborted by context"));
3200
3398
  }
3201
- cancelOperation();
3399
+ return [2 /*return*/, cancelOperation];
3202
3400
  }
3203
- // 监听外部的abort事件
3204
- context.signal.addEventListener("abort", function () {
3205
- cancelOperation();
3206
- });
3401
+ // 监听外部的abort事件(保存引用以便后续移除,防止内存泄漏)
3402
+ contextAbortHandler = function () { cancelOperation(); };
3403
+ context.signal.addEventListener("abort", contextAbortHandler);
3207
3404
  }
3208
3405
  timeoutPromise = new Promise(function (_, reject) {
3209
3406
  timeoutHandle = setTimeout(function () {
@@ -3212,58 +3409,83 @@
3212
3409
  }, timeout);
3213
3410
  });
3214
3411
  operationPromise = (function () { return __awaiter(_this, void 0, void 0, function () {
3215
- var 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;
3216
3413
  var _this = this;
3217
- var _g, e_1, _h, _j;
3218
- var _k, _l, _m;
3219
- return __generator(this, function (_o) {
3220
- 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) {
3221
3418
  case 0:
3222
- 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;
3223
3430
  expectedMessageLength = -1;
3431
+ flattenMsgBuffer = function () {
3432
+ if (msgChunks.length === 0)
3433
+ return new Uint8Array(0);
3434
+ if (msgChunks.length === 1)
3435
+ return msgChunks[0];
3436
+ var out = new Uint8Array(msgTotalLen);
3437
+ var off = 0;
3438
+ for (var _i = 0, msgChunks_1 = msgChunks; _i < msgChunks_1.length; _i++) {
3439
+ var c = msgChunks_1[_i];
3440
+ out.set(c, off);
3441
+ off += c.length;
3442
+ }
3443
+ return out;
3444
+ };
3224
3445
  hpack = new HPACK();
3225
3446
  connection = null;
3226
3447
  connectionKey = null;
3227
3448
  state = null;
3228
3449
  streamSlotAcquired = false;
3229
- _o.label = 1;
3450
+ writer = null;
3451
+ _p.label = 1;
3230
3452
  case 1:
3231
- _o.trys.push([1, 49, 50, 64]);
3453
+ _p.trys.push([1, 49, 50, 64]);
3232
3454
  // 检查是否已经中止
3233
3455
  if (internalController.signal.aborted) {
3234
3456
  throw new Error("Operation aborted");
3235
3457
  }
3236
3458
  if (!(options === null || options === void 0 ? void 0 : options.freshConnection)) return [3 /*break*/, 5];
3237
- _o.label = 2;
3459
+ _p.label = 2;
3238
3460
  case 2:
3239
- _o.trys.push([2, 4, , 5]);
3461
+ _p.trys.push([2, 4, , 5]);
3240
3462
  this.connectionPool.delete(this.peerAddr.toString());
3241
3463
  return [4 /*yield*/, this.node.hangUp(this.peerAddr)];
3242
3464
  case 3:
3243
- _o.sent();
3465
+ _p.sent();
3244
3466
  console.warn("[Call] hangUp existing connection before dialing due to freshConnection=true");
3245
3467
  return [3 /*break*/, 5];
3246
3468
  case 4:
3247
- err_4 = _o.sent();
3469
+ err_4 = _p.sent();
3248
3470
  console.warn("[Call] hangUp failed or not supported, proceeding to dial", err_4);
3249
3471
  return [3 /*break*/, 5];
3250
3472
  case 5: return [4 /*yield*/, this.acquireConnection(Boolean(options === null || options === void 0 ? void 0 : options.freshConnection))];
3251
3473
  case 6:
3252
- connection = _o.sent();
3474
+ connection = _p.sent();
3253
3475
  connectionKey = this.peerAddr.toString();
3254
3476
  state = this.getConnectionState(connection);
3255
3477
  if (!state) return [3 /*break*/, 10];
3256
- _o.label = 7;
3478
+ _p.label = 7;
3257
3479
  case 7:
3258
- _o.trys.push([7, 9, , 10]);
3480
+ _p.trys.push([7, 9, , 10]);
3259
3481
  return [4 /*yield*/, this.waitForStreamSlot(state, internalController.signal, timeout)];
3260
3482
  case 8:
3261
- _o.sent();
3483
+ _p.sent();
3262
3484
  state.activeStreams += 1;
3263
3485
  streamSlotAcquired = true;
3264
3486
  return [3 /*break*/, 10];
3265
3487
  case 9:
3266
- err_5 = _o.sent();
3488
+ err_5 = _p.sent();
3267
3489
  console.warn("[Call] waiting for stream slot failed:", err_5);
3268
3490
  throw err_5;
3269
3491
  case 10: return [4 /*yield*/, connection.newStream(this.protocol, {
@@ -3272,23 +3494,23 @@
3272
3494
  negotiateFully: false,
3273
3495
  })];
3274
3496
  case 11:
3275
- stream = _o.sent();
3497
+ stream = _p.sent();
3276
3498
  streamManager = this.getStreamManagerFor(connection);
3277
3499
  return [4 /*yield*/, streamManager.getNextAppLevelStreamId()];
3278
3500
  case 12:
3279
- streamId_2 = _o.sent();
3280
- writer_2 = new StreamWriter(stream, {
3501
+ streamId_2 = _p.sent();
3502
+ writer = new StreamWriter(stream, {
3281
3503
  bufferSize: 16 * 1024 * 1024,
3282
3504
  });
3283
3505
  try {
3284
- writer_2.addEventListener("backpressure", function (e) {
3506
+ writer.addEventListener("backpressure", function (e) {
3285
3507
  var d = e.detail || {};
3286
3508
  console.warn("[stream ".concat(streamId_2, "] backpressure current=").concat(d.currentSize, " avg=").concat(d.averageSize, " threshold=").concat(d.threshold));
3287
3509
  });
3288
- writer_2.addEventListener("drain", function () {
3510
+ writer.addEventListener("drain", function () {
3289
3511
  // drain event - no action needed
3290
3512
  });
3291
- writer_2.addEventListener("stalled", function (e) {
3513
+ writer.addEventListener("stalled", function (e) {
3292
3514
  var _a;
3293
3515
  var d = e.detail || {};
3294
3516
  console.warn("[stream ".concat(streamId_2, "] stalled queue=").concat(d.queueSize, " drained=").concat(d.drained, " since=").concat(d.sinceMs, "ms \u2014 sending PING"));
@@ -3296,13 +3518,13 @@
3296
3518
  var payload = new Uint8Array(8);
3297
3519
  (_a = crypto.getRandomValues) === null || _a === void 0 ? void 0 : _a.call(crypto, payload);
3298
3520
  var ping = Http2Frame.createFrame(0x6, 0x0, 0, payload);
3299
- writer_2.write(ping);
3521
+ writer.write(ping);
3300
3522
  }
3301
3523
  catch ( /* ignore ping write errors */_b) { /* ignore ping write errors */ }
3302
3524
  });
3303
3525
  }
3304
- catch ( /* ignore addEventListener errors */_p) { /* ignore addEventListener errors */ }
3305
- parser_1 = new HTTP2Parser(writer_2, {
3526
+ catch ( /* ignore addEventListener errors */_q) { /* ignore addEventListener errors */ }
3527
+ parser_1 = new HTTP2Parser(writer, {
3306
3528
  compatibilityMode: !useFlowControl,
3307
3529
  });
3308
3530
  parser_1.onGoaway = function (info) {
@@ -3313,10 +3535,8 @@
3313
3535
  if (state) {
3314
3536
  _this.rejectStreamWaiters(state, new Error("Connection received GOAWAY"));
3315
3537
  }
3316
- if (onErrorCallback) {
3317
- onErrorCallback(new Error("GOAWAY received: code=".concat(info.errorCode)));
3318
- }
3319
- internalController.abort();
3538
+ // reportError 统一完成:标记已报错 + abort + 触发回调(幂等,不会重复触发)
3539
+ reportError(new Error("GOAWAY received: code=".concat(info.errorCode)));
3320
3540
  try {
3321
3541
  connection === null || connection === void 0 ? void 0 : connection.close();
3322
3542
  }
@@ -3341,7 +3561,7 @@
3341
3561
  switch (_a.label) {
3342
3562
  case 0:
3343
3563
  if (!useFlowControl) return [3 /*break*/, 2];
3344
- return [4 /*yield*/, this.sendFrameWithFlowControl(parser_1, streamId_2, frame, writer_2, internalController.signal, sendWindowTimeout_1)];
3564
+ return [4 /*yield*/, this.sendFrameWithFlowControl(parser_1, streamId_2, frame, writer, internalController.signal, sendWindowTimeout_1)];
3345
3565
  case 1:
3346
3566
  _a.sent();
3347
3567
  return [3 /*break*/, 4];
@@ -3349,7 +3569,7 @@
3349
3569
  if (internalController.signal.aborted) {
3350
3570
  throw new Error("Operation aborted");
3351
3571
  }
3352
- return [4 /*yield*/, writer_2.write(frame)];
3572
+ return [4 /*yield*/, writer.write(frame)];
3353
3573
  case 3:
3354
3574
  _a.sent();
3355
3575
  _a.label = 4;
@@ -3380,51 +3600,44 @@
3380
3600
  }); };
3381
3601
  // 在各个回调中检查是否已中止
3382
3602
  parser_1.onData = function (payload) { return __awaiter(_this, void 0, void 0, function () {
3383
- var newBuffer, lengthBytes, completeMessage;
3603
+ var flat, lengthBytes, flat, completeMessage, remaining;
3384
3604
  return __generator(this, function (_a) {
3385
- // 检查是否已中止
3386
- if (internalController.signal.aborted) {
3605
+ if (internalController.signal.aborted)
3387
3606
  return [2 /*return*/];
3388
- }
3389
3607
  try {
3390
- newBuffer = new Uint8Array(messageBuffer.length + payload.length);
3391
- newBuffer.set(messageBuffer);
3392
- newBuffer.set(payload, messageBuffer.length);
3393
- messageBuffer = newBuffer;
3608
+ // 追加到分段列表,O(1),不拷贝历史数据
3609
+ msgChunks.push(payload);
3610
+ msgTotalLen += payload.length;
3394
3611
  // 处理缓冲区中的完整消息
3395
- while (messageBuffer.length > 0) {
3396
- // 如果已经中止,停止处理
3397
- if (internalController.signal.aborted) {
3612
+ while (msgTotalLen > 0) {
3613
+ if (internalController.signal.aborted)
3398
3614
  return [2 /*return*/];
3615
+ // 读取 gRPC 消息头(5字节)
3616
+ if (expectedMessageLength === -1 && msgTotalLen >= 5) {
3617
+ flat = flattenMsgBuffer();
3618
+ msgChunks = [flat];
3619
+ lengthBytes = flat.slice(1, 5);
3620
+ expectedMessageLength = new DataView(lengthBytes.buffer, lengthBytes.byteOffset).getUint32(0, false);
3399
3621
  }
3400
- // 如果还没有读取消息长度,且缓冲区有足够数据
3401
- if (expectedMessageLength === -1 && messageBuffer.length >= 5) {
3402
- lengthBytes = messageBuffer.slice(1, 5);
3403
- expectedMessageLength = new DataView(lengthBytes.buffer, lengthBytes.byteOffset).getUint32(0, false); // big-endian
3404
- }
3405
- // 如果知道期望长度且有足够数据
3406
- if (expectedMessageLength !== -1 &&
3407
- messageBuffer.length >= expectedMessageLength + 5) {
3408
- completeMessage = messageBuffer.slice(5, expectedMessageLength + 5);
3409
- // 调用回调处理这个完整消息
3622
+ // 有完整消息
3623
+ if (expectedMessageLength !== -1 && msgTotalLen >= expectedMessageLength + 5) {
3624
+ flat = flattenMsgBuffer();
3625
+ msgChunks = [flat];
3626
+ completeMessage = flat.slice(5, expectedMessageLength + 5);
3410
3627
  onDataCallback(completeMessage);
3411
- // 移除已处理的消息,保留剩余数据
3412
- messageBuffer = messageBuffer.slice(expectedMessageLength + 5);
3628
+ remaining = flat.slice(expectedMessageLength + 5);
3629
+ msgChunks = remaining.length > 0 ? [remaining] : [];
3630
+ msgTotalLen = remaining.length;
3413
3631
  expectedMessageLength = -1;
3414
3632
  }
3415
3633
  else {
3416
- // 没有足够数据构成完整消息,等待更多数据
3417
3634
  break;
3418
3635
  }
3419
3636
  }
3420
3637
  }
3421
3638
  catch (error) {
3422
- if (onErrorCallback) {
3423
- onErrorCallback(error);
3424
- }
3425
- else {
3426
- throw error;
3427
- }
3639
+ // reportError 统一报错并中止,防止 onEndCallback 在数据处理异常后仍被调用
3640
+ reportError(error);
3428
3641
  }
3429
3642
  return [2 /*return*/];
3430
3643
  });
@@ -3434,7 +3647,7 @@
3434
3647
  if (internalController.signal.aborted)
3435
3648
  return;
3436
3649
  var ackSettingFrame = Http2Frame.createSettingsAckFrame();
3437
- writer_2.write(ackSettingFrame);
3650
+ writer.write(ackSettingFrame);
3438
3651
  };
3439
3652
  parser_1.onHeaders = function (headers) {
3440
3653
  // 检查是否已中止
@@ -3444,20 +3657,16 @@
3444
3657
  if (plainHeaders.get("grpc-status") === "0") ;
3445
3658
  else if (plainHeaders.get("grpc-status") !== undefined) {
3446
3659
  var errMsg = plainHeaders.get("grpc-message") || "gRPC call failed";
3447
- var err = new Error(errMsg);
3448
- if (onErrorCallback) {
3449
- onErrorCallback(err);
3450
- }
3451
- else {
3452
- throw err;
3453
- }
3660
+ // reportError 统一完成:标记已报错 + abort + 触发回调(幂等,不会重复触发)
3661
+ reportError(new Error(errMsg));
3454
3662
  }
3455
3663
  };
3456
3664
  // 启动后台流处理
3457
3665
  parser_1.processStream(stream).catch(function (error) {
3458
- console.error('Error in processStream:', error);
3459
- if (onErrorCallback) {
3460
- onErrorCallback(error);
3666
+ // abort() 触发的清理错误属于预期行为,不打印错误日志,不重复触发回调
3667
+ if (!internalController.signal.aborted) {
3668
+ console.error('Error in processStream:', error);
3669
+ reportError(error);
3461
3670
  }
3462
3671
  });
3463
3672
  // 检查是否已中止
@@ -3465,56 +3674,52 @@
3465
3674
  throw new Error("Operation aborted");
3466
3675
  }
3467
3676
  preface = Http2Frame.createPreface();
3468
- return [4 /*yield*/, writer_2.write(preface)];
3677
+ return [4 /*yield*/, writer.write(preface)];
3469
3678
  case 13:
3470
- _o.sent();
3679
+ _p.sent();
3471
3680
  // 检查是否已中止
3472
3681
  if (internalController.signal.aborted) {
3473
3682
  throw new Error("Operation aborted");
3474
3683
  }
3475
3684
  settingFrame = Http2Frame.createSettingsFrame();
3476
- return [4 /*yield*/, writer_2.write(settingFrame)];
3685
+ return [4 /*yield*/, writer.write(settingFrame)];
3477
3686
  case 14:
3478
- _o.sent();
3687
+ _p.sent();
3479
3688
  // 检查是否已中止
3480
3689
  if (internalController.signal.aborted) {
3481
3690
  throw new Error("Operation aborted");
3482
3691
  }
3483
3692
  return [4 /*yield*/, Promise.race([
3484
- parser_1.waitForPeerSettings(1000),
3485
- parser_1.waitForSettingsAck(),
3693
+ parser_1.waitForPeerSettings(1000).catch(function () { }),
3694
+ parser_1.waitForSettingsAck().catch(function () { }),
3486
3695
  new Promise(function (res) { return setTimeout(res, 300); }),
3487
3696
  ])];
3488
3697
  case 15:
3489
- _o.sent();
3698
+ _p.sent();
3490
3699
  // 检查是否已中止
3491
3700
  if (internalController.signal.aborted) {
3492
3701
  throw new Error("Operation aborted");
3493
3702
  }
3494
- // 检查是否已中止
3495
- if (internalController.signal.aborted) {
3496
- throw new Error("Operation aborted");
3497
- }
3498
- headerFrame = Http2Frame.createHeadersFrame(streamId_2, method, true, this.token);
3703
+ headerFrame = Http2Frame.createHeadersFrame(streamId_2, method, true, this.token, this.getAuthority());
3499
3704
  if (!(mode === "unary" || mode === "server-streaming")) return [3 /*break*/, 18];
3500
- return [4 /*yield*/, writer_2.write(headerFrame)];
3705
+ return [4 /*yield*/, writer.write(headerFrame)];
3501
3706
  case 16:
3502
- _o.sent();
3707
+ _p.sent();
3503
3708
  dfs = Http2Frame.createDataFrames(streamId_2, requestData, true);
3504
3709
  return [4 /*yield*/, writeDataFrames_1(dfs)];
3505
3710
  case 17:
3506
- _o.sent();
3711
+ _p.sent();
3507
3712
  // 检查是否已中止
3508
3713
  if (internalController.signal.aborted) {
3509
3714
  throw new Error("Operation aborted");
3510
3715
  }
3511
- return [3 /*break*/, 47];
3716
+ return [3 /*break*/, 45];
3512
3717
  case 18:
3513
3718
  if (!((mode === "client-streaming" || mode === "bidirectional") &&
3514
- dataSourceCallback)) return [3 /*break*/, 47];
3515
- return [4 /*yield*/, writer_2.write(headerFrame)];
3719
+ dataSourceCallback)) return [3 /*break*/, 45];
3720
+ return [4 /*yield*/, writer.write(headerFrame)];
3516
3721
  case 19:
3517
- _o.sent();
3722
+ _p.sent();
3518
3723
  // 检查是否已中止
3519
3724
  if (internalController.signal.aborted) {
3520
3725
  throw new Error("Operation aborted");
@@ -3523,12 +3728,23 @@
3523
3728
  dfs0 = Http2Frame.createDataFrames(streamId_2, requestData, false);
3524
3729
  return [4 /*yield*/, writeDataFrames_1(dfs0)];
3525
3730
  case 20:
3526
- _o.sent();
3527
- _o.label = 21;
3731
+ _p.sent();
3732
+ _p.label = 21;
3528
3733
  case 21:
3529
3734
  batchSize_1 = (options === null || options === void 0 ? void 0 : options.batchSize) || 10;
3530
3735
  processingQueue_1 = [];
3736
+ batchDoneWaiters_1 = [];
3531
3737
  isProcessing_1 = false;
3738
+ _notifyBatchDone_1 = function () {
3739
+ var ws = batchDoneWaiters_1.splice(0);
3740
+ for (var _i = 0, ws_1 = ws; _i < ws_1.length; _i++) {
3741
+ var fn = ws_1[_i];
3742
+ try {
3743
+ fn();
3744
+ }
3745
+ catch ( /* ignore */_a) { /* ignore */ }
3746
+ }
3747
+ };
3532
3748
  processNextBatch_1 = function () { return __awaiter(_this, void 0, void 0, function () {
3533
3749
  var currentBatch, _i, currentBatch_1, item, frames_2, item, frames1, error_3;
3534
3750
  return __generator(this, function (_a) {
@@ -3589,10 +3805,13 @@
3589
3805
  case 10:
3590
3806
  isProcessing_1 = false;
3591
3807
  // 如果队列中还有数据,继续处理
3592
- if (processingQueue_1.length > 0 &&
3593
- !internalController.signal.aborted) {
3594
- // 使用 setTimeout 避免阻塞,让新数据有机会加入队列
3595
- 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();
3596
3815
  }
3597
3816
  return [7 /*endfinally*/];
3598
3817
  case 11: return [2 /*return*/];
@@ -3615,20 +3834,20 @@
3615
3834
  }
3616
3835
  });
3617
3836
  };
3618
- _o.label = 22;
3837
+ _p.label = 22;
3619
3838
  case 22:
3620
- _o.trys.push([22, 36, , 37]);
3621
- _o.label = 23;
3839
+ _p.trys.push([22, 36, , 37]);
3840
+ _p.label = 23;
3622
3841
  case 23:
3623
- _o.trys.push([23, 29, 30, 35]);
3842
+ _p.trys.push([23, 29, 30, 35]);
3624
3843
  _a = true, _b = __asyncValues(dataSourceCallback());
3625
- _o.label = 24;
3844
+ _p.label = 24;
3626
3845
  case 24: return [4 /*yield*/, _b.next()];
3627
3846
  case 25:
3628
- if (!(_c = _o.sent(), _g = _c.done, !_g)) return [3 /*break*/, 28];
3629
- _j = _c.value;
3847
+ if (!(_c = _p.sent(), _h = _c.done, !_h)) return [3 /*break*/, 28];
3848
+ _k = _c.value;
3630
3849
  _a = false;
3631
- chunkOrChunks = _j;
3850
+ chunkOrChunks = _k;
3632
3851
  // 检查是否已中止
3633
3852
  if (internalController.signal.aborted) {
3634
3853
  throw new Error("Operation aborted");
@@ -3643,23 +3862,23 @@
3643
3862
  return [4 /*yield*/, Promise.all(addPromises)];
3644
3863
  case 26:
3645
3864
  // 等待当前批次的chunks被添加到队列(不等待处理完成)
3646
- _o.sent();
3647
- _o.label = 27;
3865
+ _p.sent();
3866
+ _p.label = 27;
3648
3867
  case 27:
3649
3868
  _a = true;
3650
3869
  return [3 /*break*/, 24];
3651
3870
  case 28: return [3 /*break*/, 35];
3652
3871
  case 29:
3653
- e_1_1 = _o.sent();
3872
+ e_1_1 = _p.sent();
3654
3873
  e_1 = { error: e_1_1 };
3655
3874
  return [3 /*break*/, 35];
3656
3875
  case 30:
3657
- _o.trys.push([30, , 33, 34]);
3658
- if (!(!_a && !_g && (_h = _b.return))) return [3 /*break*/, 32];
3659
- 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)];
3660
3879
  case 31:
3661
- _o.sent();
3662
- _o.label = 32;
3880
+ _p.sent();
3881
+ _p.label = 32;
3663
3882
  case 32: return [3 /*break*/, 34];
3664
3883
  case 33:
3665
3884
  if (e_1) throw e_1.error;
@@ -3667,7 +3886,7 @@
3667
3886
  case 34: return [7 /*endfinally*/];
3668
3887
  case 35: return [3 /*break*/, 37];
3669
3888
  case 36:
3670
- error_2 = _o.sent();
3889
+ error_2 = _p.sent();
3671
3890
  remainingQueue = processingQueue_1.splice(0);
3672
3891
  remainingQueue.forEach(function (item) {
3673
3892
  try {
@@ -3678,81 +3897,95 @@
3678
3897
  }
3679
3898
  });
3680
3899
  throw error_2;
3681
- case 37:
3682
- queueWaitStart = Date.now();
3683
- maxQueueWaitMs = timeout;
3684
- _o.label = 38;
3685
- case 38:
3686
- if (!(processingQueue_1.length > 0 || isProcessing_1)) return [3 /*break*/, 40];
3687
- if (internalController.signal.aborted) {
3688
- throw new Error("Operation aborted");
3689
- }
3690
- // 防止无限等待
3691
- if (Date.now() - queueWaitStart > maxQueueWaitMs) {
3692
- remainingQueue = processingQueue_1.splice(0);
3693
- remainingQueue.forEach(function (item) {
3694
- try {
3695
- item.reject(new Error("Queue wait timeout"));
3900
+ case 37:
3901
+ // 等待所有剩余的数据处理完成(事件驱动,无 10ms 轮询)
3902
+ return [4 /*yield*/, new Promise(function (resolve, reject) {
3903
+ var check = function () {
3904
+ if (internalController.signal.aborted) {
3905
+ reject(new Error("Operation aborted"));
3906
+ return;
3696
3907
  }
3697
- catch (err) {
3698
- console.warn("Error rejecting timeout promise:", err);
3908
+ if (processingQueue_1.length === 0 && !isProcessing_1) {
3909
+ resolve();
3910
+ return;
3699
3911
  }
3700
- });
3701
- throw new Error("Queue processing timeout");
3702
- }
3703
- return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 10); })];
3704
- case 39:
3705
- _o.sent();
3706
- return [3 /*break*/, 38];
3707
- case 40:
3912
+ // processNextBatch 结束时会通知这里
3913
+ batchDoneWaiters_1.push(check);
3914
+ };
3915
+ check();
3916
+ })];
3917
+ case 38:
3918
+ // 等待所有剩余的数据处理完成(事件驱动,无 10ms 轮询)
3919
+ _p.sent();
3708
3920
  // 检查是否已中止
3709
3921
  if (internalController.signal.aborted) {
3710
3922
  throw new Error("Operation aborted");
3711
3923
  }
3712
- finalFrame = Http2Frame.createDataFrame(streamId_2, new Uint8Array(), true);
3924
+ finalFrame = Http2Frame.createFrame(0x0, 0x01, streamId_2, new Uint8Array(0));
3713
3925
  return [4 /*yield*/, writeFrame_1(finalFrame)];
3926
+ case 39:
3927
+ _p.sent();
3928
+ _p.label = 40;
3929
+ case 40:
3930
+ _p.trys.push([40, 42, , 43]);
3931
+ return [4 /*yield*/, writer.flush(timeout)];
3714
3932
  case 41:
3715
- _o.sent();
3716
- _o.label = 42;
3933
+ _p.sent();
3934
+ return [3 /*break*/, 43];
3717
3935
  case 42:
3718
- _o.trys.push([42, 44, , 45]);
3719
- return [4 /*yield*/, writer_2.flush(timeout)];
3720
- case 43:
3721
- _o.sent();
3722
- return [3 /*break*/, 45];
3936
+ _p.sent();
3937
+ return [3 /*break*/, 43];
3938
+ case 43: return [4 /*yield*/, writer.end()];
3723
3939
  case 44:
3724
- _o.sent();
3725
- return [3 /*break*/, 45];
3726
- case 45: return [4 /*yield*/, writer_2.end()];
3727
- case 46:
3728
- _o.sent();
3729
- _o.label = 47;
3730
- case 47:
3940
+ _p.sent();
3941
+ _p.label = 45;
3942
+ case 45:
3731
3943
  // 检查是否已中止
3732
3944
  if (internalController.signal.aborted) {
3733
3945
  throw new Error("Operation aborted");
3734
3946
  }
3947
+ if (!!internalController.signal.aborted) return [3 /*break*/, 48];
3735
3948
  return [4 /*yield*/, parser_1.waitForEndOfStream(0)];
3736
- case 48:
3737
- _o.sent();
3738
- 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) {
3739
3969
  onEndCallback();
3740
3970
  }
3741
- return [3 /*break*/, 64];
3971
+ _p.label = 48;
3972
+ case 48: return [3 /*break*/, 64];
3742
3973
  case 49:
3743
- err_6 = _o.sent();
3974
+ err_6 = _p.sent();
3744
3975
  // 如果是由于取消导致的错误,使用特定的错误消息
3745
3976
  if (internalController.signal.aborted &&
3746
3977
  err_6 instanceof Error &&
3747
3978
  err_6.message === "Operation aborted") {
3748
- if (onErrorCallback) {
3979
+ // onHeaders / onGoaway / processStream 错误已通过 reportError 处理,
3980
+ // 此处仅在回调尚未触发时才报告(外部取消/超时场景)
3981
+ if (!errorCallbackFired && onErrorCallback) {
3749
3982
  onErrorCallback(new Error("Operation cancelled by user"));
3750
3983
  }
3751
3984
  }
3752
- else if (onErrorCallback) {
3985
+ else if (!errorCallbackFired && onErrorCallback) {
3753
3986
  onErrorCallback(err_6);
3754
3987
  }
3755
- else {
3988
+ else if (!errorCallbackFired) {
3756
3989
  if (err_6 instanceof Error) {
3757
3990
  console.error("asyncCall error:", err_6.message);
3758
3991
  }
@@ -3763,45 +3996,53 @@
3763
3996
  return [3 /*break*/, 64];
3764
3997
  case 50:
3765
3998
  clearTimeout(timeoutHandle);
3999
+ // 移除外部 abort 监听器,防止 AbortController 复用时触发迟到的 cancelOperation()
4000
+ if (contextAbortHandler && (context === null || context === void 0 ? void 0 : context.signal)) {
4001
+ context.signal.removeEventListener("abort", contextAbortHandler);
4002
+ }
4003
+ // 必须先 abort writer(立即强制停止 pushable + stream),再 close stream。
4004
+ // 若顺序颠倒:stream.close() 等待服务端半关闭确认,网络异常时永久挂住,
4005
+ // writer.abort() 永远不执行 → watchdog / pushable 泄漏。
4006
+ // abort() 内部幂等,重复调用安全。
4007
+ writer === null || writer === void 0 ? void 0 : writer.abort('Call cleanup');
3766
4008
  if (!stream) return [3 /*break*/, 54];
3767
- _o.label = 51;
4009
+ _p.label = 51;
3768
4010
  case 51:
3769
- _o.trys.push([51, 53, , 54]);
4011
+ _p.trys.push([51, 53, , 54]);
3770
4012
  return [4 /*yield*/, stream.close()];
3771
4013
  case 52:
3772
- _o.sent();
4014
+ _p.sent();
3773
4015
  return [3 /*break*/, 54];
3774
4016
  case 53:
3775
- err_7 = _o.sent();
3776
- console.error("Error closing stream:", err_7);
4017
+ _p.sent();
3777
4018
  return [3 /*break*/, 54];
3778
4019
  case 54:
3779
4020
  if (!(options === null || options === void 0 ? void 0 : options.freshConnection)) return [3 /*break*/, 63];
3780
- _o.label = 55;
4021
+ _p.label = 55;
3781
4022
  case 55:
3782
- _o.trys.push([55, 62, , 63]);
3783
- 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)) || [];
3784
4025
  _i = 0, conns_1 = conns;
3785
- _o.label = 56;
4026
+ _p.label = 56;
3786
4027
  case 56:
3787
4028
  if (!(_i < conns_1.length)) return [3 /*break*/, 61];
3788
4029
  c = conns_1[_i];
3789
- _o.label = 57;
4030
+ _p.label = 57;
3790
4031
  case 57:
3791
- _o.trys.push([57, 59, , 60]);
3792
- 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))];
3793
4034
  case 58:
3794
- _o.sent();
4035
+ _p.sent();
3795
4036
  return [3 /*break*/, 60];
3796
4037
  case 59:
3797
- _o.sent();
4038
+ _p.sent();
3798
4039
  return [3 /*break*/, 60];
3799
4040
  case 60:
3800
4041
  _i++;
3801
4042
  return [3 /*break*/, 56];
3802
4043
  case 61: return [3 /*break*/, 63];
3803
4044
  case 62:
3804
- _o.sent();
4045
+ _p.sent();
3805
4046
  return [3 /*break*/, 63];
3806
4047
  case 63:
3807
4048
  if (streamSlotAcquired && state) {