@@ -41,6 +41,7 @@ import { isMessageOfType, MessageType, createMessageOfType } from 'vs/workbench/
4141import { ILabelService } from 'vs/platform/label/common/label' ;
4242import { URI } from 'vs/base/common/uri' ;
4343import { Schemas } from 'vs/base/common/network' ;
44+ import { onUnexpectedError } from 'vs/base/common/errors' ;
4445
4546export interface IExtensionHostStarter {
4647 readonly onCrashed : Event < [ number , string ] > ;
@@ -316,9 +317,9 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
316317 } ) ;
317318 }
318319
319- private _tryExtHostHandshake ( ) : TPromise < IMessagePassingProtocol > {
320+ private _tryExtHostHandshake ( ) : Promise < IMessagePassingProtocol > {
320321
321- return new TPromise < IMessagePassingProtocol > ( ( resolve , reject ) => {
322+ return new Promise < IMessagePassingProtocol > ( ( resolve , reject ) => {
322323
323324 // Wait for the extension host to connect to our named pipe
324325 // and wrap the socket in the message passing protocol
@@ -340,7 +341,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
340341
341342 // 1) wait for the incoming `ready` event and send the initialization data.
342343 // 2) wait for the incoming `initialized` event.
343- return new TPromise < IMessagePassingProtocol > ( ( resolve , reject ) => {
344+ return new Promise < IMessagePassingProtocol > ( ( resolve , reject ) => {
344345
345346 let handle = setTimeout ( ( ) => {
346347 reject ( 'timeout' ) ;
@@ -363,7 +364,10 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
363364 disposable . dispose ( ) ;
364365
365366 // release this promise
366- resolve ( protocol ) ;
367+ // using a buffered message protocol here because between now
368+ // and the first time a `then` executes some messages might be lost
369+ // unless we immediately register a listener for `onMessage`.
370+ resolve ( new BufferedMessagePassingProtocol ( protocol ) ) ;
367371 return ;
368372 }
369373
@@ -530,3 +534,57 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
530534 }
531535 }
532536}
537+
538+ /**
539+ * Will ensure no messages are lost from creation time until the first user of onMessage comes in.
540+ */
541+ class BufferedMessagePassingProtocol implements IMessagePassingProtocol {
542+
543+ private readonly _actual : IMessagePassingProtocol ;
544+ private _bufferedMessagesListener : IDisposable ;
545+ private _bufferedMessages : Buffer [ ] ;
546+
547+ constructor ( actual : IMessagePassingProtocol ) {
548+ this . _actual = actual ;
549+ this . _bufferedMessages = [ ] ;
550+ this . _bufferedMessagesListener = this . _actual . onMessage ( ( buff ) => this . _bufferedMessages . push ( buff ) ) ;
551+ }
552+
553+ public send ( buffer : Buffer ) : void {
554+ this . _actual . send ( buffer ) ;
555+ }
556+
557+ public onMessage ( listener : ( e : Buffer ) => any , thisArgs ?: any , disposables ?: IDisposable [ ] ) : IDisposable {
558+ if ( ! this . _bufferedMessages ) {
559+ // second caller gets nothing
560+ return this . _actual . onMessage ( listener , thisArgs , disposables ) ;
561+ }
562+
563+ // prepare result
564+ const result = this . _actual . onMessage ( listener , thisArgs , disposables ) ;
565+
566+ // stop listening to buffered messages
567+ this . _bufferedMessagesListener . dispose ( ) ;
568+
569+ // capture buffered messages
570+ const bufferedMessages = this . _bufferedMessages ;
571+ this . _bufferedMessages = null ;
572+
573+ // it is important to deliver these messages after this call, but before
574+ // other messages have a chance to be received (to guarantee in order delivery)
575+ // that's why we're using here nextTick and not other types of timeouts
576+ process . nextTick ( ( ) => {
577+ // deliver buffered messages
578+ while ( bufferedMessages . length > 0 ) {
579+ const msg = bufferedMessages . shift ( ) ;
580+ try {
581+ listener . call ( thisArgs , msg ) ;
582+ } catch ( e ) {
583+ onUnexpectedError ( e ) ;
584+ }
585+ }
586+ } ) ;
587+
588+ return result ;
589+ }
590+ }
0 commit comments