grpc-libp2p-client 0.0.37 → 0.0.38

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.
@@ -8,22 +8,24 @@ type ParserOptions = {
8
8
  compatibilityMode?: boolean
9
9
  }
10
10
 
11
+ const HTTP2_PREFACE = new TextEncoder().encode("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n");
12
+
11
13
  export class HTTP2Parser {
12
14
  buffer: Uint8Array;
13
15
  settingsAckReceived: boolean;
14
16
  peerSettingsReceived: boolean;
15
17
  connectionWindowSize: number;
16
- streams: Map<number, any>;
18
+ streams: Map<number, unknown>;
17
19
  defaultStreamWindowSize: number;
18
20
  // 发送方向(对端的接收窗口)跟踪
19
21
  sendConnWindow: number;
20
22
  sendStreamWindows: Map<number, number>;
21
23
  peerInitialStreamWindow: number;
22
24
  private sendWindowWaiters: Array<() => void>;
23
- onSettings?: (frameHeader: any) => void;
24
- onData?: (payload: Uint8Array, frameHeader: any) => void;
25
+ onSettings?: (frameHeader: Frame) => void;
26
+ onData?: (payload: Uint8Array, frameHeader: Frame) => void;
25
27
  onEnd?: () => void;
26
- onHeaders?: (headers: Uint8Array, frameHeader: any) => void;
28
+ onHeaders?: (headers: Uint8Array, frameHeader: Frame) => void;
27
29
  onGoaway?: (info: { lastStreamId?: number; errorCode?: number }) => void;
28
30
  onSettingsParsed?: (settings: { maxConcurrentStreams?: number; initialWindowSize?: number }) => void;
29
31
  endFlag: boolean;
@@ -76,53 +78,58 @@ export class HTTP2Parser {
76
78
  }
77
79
 
78
80
  // 处理单个数据块
79
- private _processChunk(chunk: any): void {
81
+ private _processChunk(chunk: Uint8Array | { subarray(): Uint8Array }): void {
80
82
  // chunk 是 Uint8ArrayList 或 Uint8Array
81
- const newData = chunk.subarray ? chunk.subarray() : new Uint8Array(chunk);
82
-
83
- // 累积数据到buffer
83
+ const newData: Uint8Array = 'subarray' in chunk && typeof chunk.subarray === 'function'
84
+ ? chunk.subarray()
85
+ : (chunk as Uint8Array);
86
+
87
+ // 原作者之前的 O(N) 内存拷贝优化被保留,去掉了存在 onEnd 竞态的 setTimeout
84
88
  const newBuffer = new Uint8Array(this.buffer.length + newData.length);
85
89
  newBuffer.set(this.buffer);
86
90
  newBuffer.set(newData, this.buffer.length);
87
91
  this.buffer = newBuffer;
88
-
92
+
89
93
  // 持续处理所有完整的帧
90
- while (this.buffer.length >= 9) {
94
+ let readOffset = 0;
95
+ while (this.buffer.length - readOffset >= 9) {
91
96
  // 判断是否有HTTP/2前导
92
- if (this.buffer.length >= 24 && this.isHttp2Preface(this.buffer)) {
93
- this.buffer = this.buffer.slice(24);
97
+ if (this.buffer.length - readOffset >= 24 && this.isHttp2Preface(this.buffer.subarray(readOffset))) {
98
+ readOffset += 24;
94
99
  // 发送SETTINGS帧
95
100
  const settingFrame = Http2Frame.createSettingsFrame();
96
- this.writer.write(settingFrame as any);
97
- break;
101
+ this.writer.write(settingFrame);
102
+ continue;
98
103
  }
99
- const frameHeader = this._parseFrameHeader(this.buffer);
104
+
105
+ const frameHeader = this._parseFrameHeader(this.buffer.subarray(readOffset));
100
106
  const totalFrameLength = 9 + frameHeader.length;
101
107
 
102
108
  // 检查是否有完整的帧
103
- if (this.buffer.length < totalFrameLength) {
109
+ if (this.buffer.length - readOffset < totalFrameLength) {
104
110
  break;
105
111
  }
106
112
  // 获取完整帧数据
107
- const frameData = this.buffer.slice(0, totalFrameLength);
113
+ const frameData = this.buffer.subarray(readOffset, readOffset + totalFrameLength);
108
114
 
109
115
  // 处理不同类型的帧
110
116
  this._handleFrame(frameHeader, frameData).catch((err) => {
111
117
  console.error("Error handling frame:", err);
112
118
  });
113
119
 
114
- // 移除已处理的帧
115
- this.buffer = this.buffer.slice(totalFrameLength);
120
+ // 移动偏移量
121
+ readOffset += totalFrameLength;
122
+ }
123
+
124
+ if (readOffset > 0) {
125
+ this.buffer = this.buffer.slice(readOffset);
116
126
  }
117
127
  }
118
128
 
119
129
  private isHttp2Preface(buffer: Uint8Array): boolean {
120
- const PREFACE = new TextEncoder().encode(
121
- "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
122
- );
123
- if (buffer.length < PREFACE.length) return false;
124
- for (let i = 0; i < PREFACE.length; i++) {
125
- if (buffer[i] !== PREFACE[i]) return false;
130
+ if (buffer.length < HTTP2_PREFACE.length) return false;
131
+ for (let i = 0; i < HTTP2_PREFACE.length; i++) {
132
+ if (buffer[i] !== HTTP2_PREFACE[i]) return false;
126
133
  }
127
134
  return true;
128
135
  }
@@ -209,7 +216,7 @@ export class HTTP2Parser {
209
216
  async waitForSendWindow(streamId: number, minBytes: number = 1, timeoutMs: number = 30000): Promise<void> {
210
217
  const start = Date.now();
211
218
  return new Promise((resolve, reject) => {
212
- let interval: NodeJS.Timeout | null = null;
219
+ let interval: ReturnType<typeof setInterval> | null = null;
213
220
  let settled = false;
214
221
  const check = () => {
215
222
  const { conn, stream } = this.getSendWindows(streamId);
@@ -319,7 +326,7 @@ export class HTTP2Parser {
319
326
  this.peerSettingsReceived = true;
320
327
  // 唤醒等待窗口(以防部分实现通过 SETTINGS 改变有效窗口)
321
328
  const waiters = this.sendWindowWaiters.splice(0);
322
- waiters.forEach(fn => { try { fn(); } catch {} });
329
+ waiters.forEach(fn => { try { fn(); } catch (e) { console.debug('waiter error', e); } });
323
330
  }
324
331
  break;
325
332
 
@@ -336,7 +343,7 @@ export class HTTP2Parser {
336
343
  frameHeader.streamId,
337
344
  frameHeader.length ?? 0
338
345
  );
339
- this.writer.write(streamWindowUpdate as any);
346
+ this.writer.write(streamWindowUpdate);
340
347
  }
341
348
 
342
349
  // 更新连接级别的窗口
@@ -344,7 +351,7 @@ export class HTTP2Parser {
344
351
  0,
345
352
  frameHeader.length ?? 0
346
353
  );
347
- this.writer.write(connWindowUpdate as any);
354
+ this.writer.write(connWindowUpdate);
348
355
  } catch (err) {
349
356
  console.error("[HTTP2] Error sending window update:", err);
350
357
  }
@@ -381,8 +388,7 @@ export class HTTP2Parser {
381
388
  // 处理窗口更新帧
382
389
  this.handleWindowUpdateFrame(
383
390
  frameHeader,
384
- frameData,
385
- frameHeader.streamId
391
+ frameData
386
392
  );
387
393
  // 更新发送窗口(对端接收窗口)
388
394
  try {
@@ -394,8 +400,8 @@ export class HTTP2Parser {
394
400
  this.sendStreamWindows.set(frameHeader.streamId, cur + inc);
395
401
  }
396
402
  const waiters = this.sendWindowWaiters.splice(0);
397
- waiters.forEach(fn => { try { fn(); } catch {} });
398
- } catch (e) {}
403
+ waiters.forEach(fn => { try { fn(); } catch (e) { console.debug('waiter error', e); } });
404
+ } catch { /* ignore WINDOW_UPDATE parse errors */ }
399
405
  break;
400
406
  case FRAME_TYPES.PING:
401
407
  // 处理PING帧
@@ -415,7 +421,7 @@ export class HTTP2Parser {
415
421
  console.warn('[HTTP2] GOAWAY received');
416
422
  info = {};
417
423
  }
418
- } catch {}
424
+ } catch { /* ignore GOAWAY parse errors */ }
419
425
  try {
420
426
  this.onGoaway?.(info ?? {});
421
427
  } catch (err) {
@@ -473,7 +479,7 @@ export class HTTP2Parser {
473
479
  // 反馈PONG帧
474
480
  const pongFrame = Http2Frame.createPongFrame(frameData.slice(9));
475
481
  try {
476
- this.writer.write(pongFrame as any);
482
+ this.writer.write(pongFrame);
477
483
  } catch (error) {
478
484
  console.error("Error sending PONG frame:", error);
479
485
  throw error;
@@ -489,7 +495,7 @@ export class HTTP2Parser {
489
495
  return;
490
496
  }
491
497
  // 如果是0 ,则不设置超时
492
- let timeout: NodeJS.Timeout | null = null;
498
+ let timeout: ReturnType<typeof setTimeout> | null = null;
493
499
  if (waitTime > 0) {
494
500
  timeout = setTimeout(() => {
495
501
  clearInterval(interval);
@@ -561,8 +567,7 @@ export class HTTP2Parser {
561
567
  // 处理 WINDOW_UPDATE 帧
562
568
  handleWindowUpdateFrame(
563
569
  frameHeader: Frame,
564
- payload: Uint8Array,
565
- streamId: number
570
+ payload: Uint8Array
566
571
  ) {
567
572
  try {
568
573
  const windowUpdate = this.parseWindowUpdateFrame(payload, frameHeader);
@@ -41,13 +41,13 @@ export class StreamWriter {
41
41
  private lastBackpressureCheck = 0 // 添加时间戳缓存
42
42
  private bytesDrained = 0 // 统计下游实际消化的字节数
43
43
  private lastDrainEventAt = 0
44
- private watchdogTimer: any
44
+ private watchdogTimer: ReturnType<typeof setInterval> | undefined
45
45
  private stallStartAt = 0
46
46
  private lastBytesDrainedSeen = 0
47
47
  private lastBpWarnAt = 0
48
48
  private isHandlingError = false // 防止重复错误处理
49
49
 
50
- private log?: { trace?: (...args: any[]) => void }
50
+ private log?: { trace?: (...args: unknown[]) => void }
51
51
 
52
52
  constructor(
53
53
  private stream: Stream,
@@ -58,7 +58,7 @@ export class StreamWriter {
58
58
  throw new Error('StreamWriter requires a valid stream object')
59
59
  }
60
60
 
61
- this.log = { trace: (...args: any[]) => console.debug('[StreamWriter]', ...args) }
61
+ this.log = { trace: (...args: unknown[]) => console.debug('[StreamWriter]', ...args) }
62
62
 
63
63
  if (options){
64
64
  this.options = {
@@ -172,10 +172,10 @@ export class StreamWriter {
172
172
  // 等待 drain 事件
173
173
  await this.stream.onDrain()
174
174
  }
175
- } catch (err: any) {
175
+ } catch (err: unknown) {
176
176
  // Gracefully handle stream closing errors - 不要传递到 handleError
177
- const errMsg = err.message?.toLowerCase() || ''
178
- if (err.name === 'StreamStateError' ||
177
+ const errMsg = (err instanceof Error ? err.message : '').toLowerCase()
178
+ if ((err instanceof Error && err.name === 'StreamStateError') ||
179
179
  errMsg.includes('closing') ||
180
180
  errMsg.includes('closed') ||
181
181
  errMsg.includes('write to a stream that is closed')) {
@@ -188,6 +188,7 @@ export class StreamWriter {
188
188
  }
189
189
 
190
190
  private createTransform() {
191
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
191
192
  const self = this;
192
193
  return async function* (source: AsyncIterable<Uint8Array>) {
193
194
  for await (const chunk of source) {
@@ -197,8 +198,8 @@ export class StreamWriter {
197
198
  // 因此这里统计的 bytesDrained 更接近实际被 sink 消费的字节数
198
199
  try {
199
200
  // 在下游消费后再扣减待消费队列,避免误判“next 没取”
200
- if ((self.p as any)?._queueSize != null) {
201
- (self.p as any)._queueSize = Math.max(0, (self.p as any)._queueSize - chunk.byteLength)
201
+ if (self.p._queueSize != null) {
202
+ self.p._queueSize = Math.max(0, self.p._queueSize - chunk.byteLength)
202
203
  }
203
204
  self.bytesDrained += chunk.byteLength
204
205
  const now = Date.now()
@@ -245,7 +246,7 @@ export class StreamWriter {
245
246
  }, intervalMs)
246
247
  }
247
248
 
248
- async write(data: ArrayBuffer | Blob | string): Promise<void> {
249
+ async write(data: ArrayBuffer | Uint8Array | Blob | string): Promise<void> {
249
250
  // 静默处理 aborted 状态,避免在正常的流关闭场景下抛出错误
250
251
  if (this.abortController.signal.aborted) {
251
252
  return Promise.resolve()
@@ -272,9 +273,10 @@ export class StreamWriter {
272
273
  })
273
274
  }
274
275
 
275
- private async convertToBuffer(data: ArrayBuffer | Blob | string): Promise<ArrayBuffer> {
276
+ private async convertToBuffer(data: ArrayBuffer | Uint8Array | Blob | string): Promise<ArrayBuffer> {
276
277
  if (data instanceof Blob) return data.arrayBuffer()
277
- if (typeof data === 'string') return new TextEncoder().encode(data).buffer
278
+ if (typeof data === 'string') return new TextEncoder().encode(data).buffer as ArrayBuffer
279
+ if (data instanceof Uint8Array) return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) as ArrayBuffer
278
280
  return data
279
281
  }
280
282
 
@@ -438,9 +440,9 @@ export class StreamWriter {
438
440
  if (this.stream && typeof this.stream.close === 'function') {
439
441
  try {
440
442
  await this.stream.close()
441
- } catch (err: any) {
443
+ } catch (err: unknown) {
442
444
  // 忽略关闭已关闭流的错误
443
- const errMsg = err.message?.toLowerCase() || ''
445
+ const errMsg = (err instanceof Error ? err.message : '').toLowerCase()
444
446
  if (!errMsg.includes('closed') && !errMsg.includes('closing')) {
445
447
  this.log?.trace?.('Stream close error:', err)
446
448
  }
@@ -461,15 +463,16 @@ export class StreamWriter {
461
463
  // 先检查流状态,避免在已关闭的流上调用 abort
462
464
  if (this.stream && typeof this.stream.abort === 'function') {
463
465
  // 检查流的状态,避免操作已关闭的流
464
- const streamState = (this.stream as any).status || (this.stream as any).state
466
+ const streamState = (this.stream as { status?: string; state?: string }).status ||
467
+ (this.stream as { status?: string; state?: string }).state
465
468
  if (streamState !== 'closed' && streamState !== 'closing') {
466
469
  this.stream.abort(new Error(reason))
467
470
  }
468
471
  }
469
- } catch (err: any) {
472
+ } catch (err: unknown) {
470
473
  // Stream may already be closed, ignore all stream-related errors
471
474
  // 完全忽略流操作错误,避免在错误处理中再次抛出错误
472
- const errMsg = err.message?.toLowerCase() || ''
475
+ const errMsg = (err instanceof Error ? err.message : '').toLowerCase()
473
476
  if (!errMsg.includes('closed') && !errMsg.includes('closing') && !errMsg.includes('write')) {
474
477
  this.log?.trace?.('Stream abort error:', err)
475
478
  }
@@ -494,13 +497,13 @@ export class StreamWriter {
494
497
 
495
498
  // 立即拒绝所有待处理的写入任务,避免它们继续执行
496
499
  const pendingTasks = this.writeQueue.splice(0)
497
- pendingTasks.forEach(task => {
500
+ pendingTasks.forEach(() => {
498
501
  // 这些任务的 Promise 会在执行时因为检查到 aborted 而被拒绝
499
502
  })
500
503
 
501
504
  try {
502
505
  this.p.end()
503
- } catch (err) {
506
+ } catch {
504
507
  // Ignore errors when ending pushable
505
508
  }
506
509
 
@@ -526,7 +529,7 @@ export class StreamWriter {
526
529
  }
527
530
 
528
531
  // 事件系统
529
- private listeners = new Map<string, Function[]>()
532
+ private listeners = new Map<string, ((event: CustomEvent) => void)[]>()
530
533
 
531
534
  addEventListener(type: string, callback: (event: CustomEvent) => void) {
532
535
  const handlers = this.listeners.get(type) || []
@@ -10,7 +10,7 @@ type Frame = {
10
10
  type: Byte;
11
11
  flags: Byte;
12
12
  streamId: number;
13
- payload?: any;
13
+ payload?: unknown;
14
14
  }
15
15
 
16
16
  type FrameSettingPayload = { identifier: number; value: number }[]