parent
1ab6a5219d
commit
4e84e698cd
@ -0,0 +1,57 @@ |
||||
import {EventEmitter} from 'events'; |
||||
import { StringDecoder } from 'string_decoder'; |
||||
// Max duration to batch session data before sending it to the renderer process.
|
||||
const BATCH_DURATION_MS = 16; |
||||
|
||||
// Max size of a session data batch. Note that this value can be exceeded by ~4k
|
||||
// (chunk sizes seem to be 4k at the most)
|
||||
const BATCH_MAX_SIZE = 200 * 1024; |
||||
|
||||
// Data coming from the pty is sent to the renderer process for further
|
||||
// vt parsing and rendering. This class batches data to minimize the number of
|
||||
// IPC calls. It also reduces GC pressure and CPU cost: each chunk is prefixed
|
||||
// with the window ID which is then stripped on the renderer process and this
|
||||
// overhead is reduced with batching.
|
||||
export class DataBatcher extends EventEmitter { |
||||
uid: number; |
||||
decoder: StringDecoder; |
||||
data!: string; |
||||
timeout!: NodeJS.Timeout | null; |
||||
constructor(uid: number) { |
||||
super(); |
||||
this.uid = uid; |
||||
this.decoder = new StringDecoder('utf8'); |
||||
|
||||
this.reset(); |
||||
} |
||||
|
||||
reset() { |
||||
this.data = ''; |
||||
this.timeout = null; |
||||
} |
||||
|
||||
write(chunk: Buffer) { |
||||
if (this.data.length + chunk.length >= BATCH_MAX_SIZE) { |
||||
// We've reached the max batch size. Flush it and start another one
|
||||
if (this.timeout) { |
||||
clearTimeout(this.timeout); |
||||
this.timeout = null; |
||||
} |
||||
this.flush(); |
||||
} |
||||
|
||||
this.data += this.decoder.write(chunk); |
||||
|
||||
if (!this.timeout) { |
||||
this.timeout = setTimeout(() => this.flush(), BATCH_DURATION_MS); |
||||
} |
||||
} |
||||
|
||||
flush() { |
||||
// Reset before emitting to allow for potential reentrancy
|
||||
const data = this.data; |
||||
this.reset(); |
||||
|
||||
this.emit('flush', data, this.uid); |
||||
} |
||||
} |
Loading…
Reference in new issue