diff --git a/arduino-ide-extension/src/node/core-service-impl.ts b/arduino-ide-extension/src/node/core-service-impl.ts index 00d6ca5ed..412e64807 100644 --- a/arduino-ide-extension/src/node/core-service-impl.ts +++ b/arduino-ide-extension/src/node/core-service-impl.ts @@ -25,7 +25,9 @@ import { firstToUpperCase, firstToLowerCase } from '../common/utils'; import { Port } from './cli-protocol/cc/arduino/cli/commands/v1/port_pb'; import { nls } from '@theia/core'; import { MonitorManager } from './monitor-manager'; +import { SimpleBuffer } from './utils/simple-buffer'; +const FLUSH_OUTPUT_MESSAGES_TIMEOUT_MS = 32; @injectable() export class CoreServiceImpl extends CoreClientAware implements CoreService { @inject(ResponseService) @@ -73,18 +75,25 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService { this.mergeSourceOverrides(compileReq, options); const result = client.compile(compileReq); + + const compileBuffer = new SimpleBuffer( + this.flushOutputPanelMessages.bind(this), + FLUSH_OUTPUT_MESSAGES_TIMEOUT_MS + ); try { await new Promise((resolve, reject) => { result.on('data', (cr: CompileResponse) => { - this.responseService.appendToOutput({ - chunk: Buffer.from(cr.getOutStream_asU8()).toString(), - }); - this.responseService.appendToOutput({ - chunk: Buffer.from(cr.getErrStream_asU8()).toString(), - }); + compileBuffer.addChunk(cr.getOutStream_asU8()); + compileBuffer.addChunk(cr.getErrStream_asU8()); + }); + result.on('error', (error) => { + compileBuffer.clearFlushInterval(); + reject(error); + }); + result.on('end', () => { + compileBuffer.clearFlushInterval(); + resolve(); }); - result.on('error', (error) => reject(error)); - result.on('end', () => resolve()); }); this.responseService.appendToOutput({ chunk: '\n--------------------------\nCompilation complete.\n', @@ -174,18 +183,24 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService { const result = responseHandler(client, req); + const uploadBuffer = new SimpleBuffer( + this.flushOutputPanelMessages.bind(this), + FLUSH_OUTPUT_MESSAGES_TIMEOUT_MS + ); try { await new Promise((resolve, reject) => { result.on('data', (resp: UploadResponse) => { - this.responseService.appendToOutput({ - chunk: Buffer.from(resp.getOutStream_asU8()).toString(), - }); - this.responseService.appendToOutput({ - chunk: Buffer.from(resp.getErrStream_asU8()).toString(), - }); + uploadBuffer.addChunk(resp.getOutStream_asU8()); + uploadBuffer.addChunk(resp.getErrStream_asU8()); + }); + result.on('error', (error) => { + uploadBuffer.clearFlushInterval(); + reject(error); + }); + result.on('end', () => { + uploadBuffer.clearFlushInterval(); + resolve(); }); - result.on('error', (error) => reject(error)); - result.on('end', () => resolve()); }); this.responseService.appendToOutput({ chunk: @@ -238,18 +253,25 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService { burnReq.setVerify(options.verify); burnReq.setVerbose(options.verbose); const result = client.burnBootloader(burnReq); + + const bootloaderBuffer = new SimpleBuffer( + this.flushOutputPanelMessages.bind(this), + FLUSH_OUTPUT_MESSAGES_TIMEOUT_MS + ); try { await new Promise((resolve, reject) => { result.on('data', (resp: BurnBootloaderResponse) => { - this.responseService.appendToOutput({ - chunk: Buffer.from(resp.getOutStream_asU8()).toString(), - }); - this.responseService.appendToOutput({ - chunk: Buffer.from(resp.getErrStream_asU8()).toString(), - }); + bootloaderBuffer.addChunk(resp.getOutStream_asU8()); + bootloaderBuffer.addChunk(resp.getErrStream_asU8()); + }); + result.on('error', (error) => { + bootloaderBuffer.clearFlushInterval(); + reject(error); + }); + result.on('end', () => { + bootloaderBuffer.clearFlushInterval(); + resolve(); }); - result.on('error', (error) => reject(error)); - result.on('end', () => resolve()); }); } catch (e) { const errorMessage = nls.localize( @@ -281,4 +303,10 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService { } } } + + private flushOutputPanelMessages(chunk: string): void { + this.responseService.appendToOutput({ + chunk, + }); + } } diff --git a/arduino-ide-extension/src/node/utils/simple-buffer.ts b/arduino-ide-extension/src/node/utils/simple-buffer.ts new file mode 100644 index 000000000..3f5acd506 --- /dev/null +++ b/arduino-ide-extension/src/node/utils/simple-buffer.ts @@ -0,0 +1,31 @@ +export class SimpleBuffer { + private chunks: Uint8Array[] = []; + + private flushInterval?: NodeJS.Timeout; + + constructor(onFlush: (chunk: string) => void, flushTimeout: number) { + this.flushInterval = setInterval(() => { + if (this.chunks.length > 0) { + const chunkString = Buffer.concat(this.chunks).toString(); + this.clearChunks(); + + onFlush(chunkString); + } + }, flushTimeout); + } + + public addChunk(chunk: Uint8Array): void { + this.chunks.push(chunk); + } + + private clearChunks(): void { + this.chunks = []; + } + + public clearFlushInterval(): void { + this.clearChunks(); + + clearInterval(this.flushInterval); + this.flushInterval = undefined; + } +}