-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathsyntheticEof.ts
More file actions
85 lines (69 loc) · 2.27 KB
/
syntheticEof.ts
File metadata and controls
85 lines (69 loc) · 2.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import { Transform } from 'node:stream';
import { getSyntheticEofSequence } from './index.js';
// keep in sync with lib.rs::SYNTHETIC_EOF
export const SYNTHETIC_EOF = getSyntheticEofSequence();
export const EOF_EVENT = 'synthetic-eof';
// get the longest suffix of buffer that is a prefix of SYNTHETIC_EOF
function getBufferEndPrefixLength(buffer: Buffer) {
const maxLen = Math.min(buffer.length, SYNTHETIC_EOF.length);
for (let len = maxLen; len > 0; len--) {
let match = true;
for (let i = 0; i < len; i++) {
if (buffer[buffer.length - len + i] !== SYNTHETIC_EOF[i]) {
match = false;
break;
}
}
if (match) {
return len;
}
}
return 0;
}
export class SyntheticEOFDetector extends Transform {
buffer: Buffer;
constructor(options = {}) {
super(options);
this.buffer = Buffer.alloc(0);
}
_transform(chunk: Buffer, _encoding: string, callback: () => void) {
const searchData = Buffer.concat([this.buffer, chunk]);
const eofIndex = searchData.indexOf(SYNTHETIC_EOF);
if (eofIndex !== -1) {
// found EOF - emit everything before it
if (eofIndex > 0) {
this.push(searchData.subarray(0, eofIndex));
}
this.emit(EOF_EVENT);
// emit everything after EOF (if any) and clear buffer
const afterEOF = searchData.subarray(eofIndex + SYNTHETIC_EOF.length);
if (afterEOF.length > 0) {
this.push(afterEOF);
}
this.buffer = Buffer.alloc(0);
} else {
// no EOF - buffer potential partial match at end
// get the longest suffix of buffer that is a prefix of SYNTHETIC_EOF
// and emit everything before it
// this is done for the case which the eof happened to be split across multiple chunks
const commonPrefixLen = getBufferEndPrefixLength(searchData);
if (commonPrefixLen > 0) {
const emitSize = searchData.length - commonPrefixLen;
if (emitSize > 0) {
this.push(searchData.subarray(0, emitSize));
}
this.buffer = searchData.subarray(emitSize);
} else {
this.push(searchData);
this.buffer = Buffer.alloc(0);
}
}
callback();
}
_flush(callback: () => void) {
if (this.buffer.length > 0) {
this.push(this.buffer);
}
callback();
}
}