11import { ILogger } from '@theia/core' ;
22import { inject , injectable , named } from '@theia/core/shared/inversify' ;
3- import { Board , Port , Status } from '../common/protocol' ;
3+ import { Board , BoardsService , Port , Status } from '../common/protocol' ;
44import { CoreClientAware } from './core-client-provider' ;
55import { MonitorService } from './monitor-service' ;
66import { MonitorServiceFactory } from './monitor-service-factory' ;
@@ -11,16 +11,34 @@ import {
1111
1212type MonitorID = string ;
1313
14+ type UploadState = 'uploadInProgress' | 'pausedForUpload' | 'disposedForUpload' ;
15+ type MonitorIDsByUploadState = Record < UploadState , MonitorID [ ] > ;
16+ 1417export const MonitorManagerName = 'monitor-manager' ;
1518
1619@injectable ( )
1720export class MonitorManager extends CoreClientAware {
21+ @inject ( BoardsService )
22+ protected boardsService : BoardsService ;
23+ 1824 // Map of monitor services that manage the running pluggable monitors.
1925 // Each service handles the lifetime of one, and only one, monitor.
2026 // If either the board or port managed changes, a new service must
2127 // be started.
2228 private monitorServices = new Map < MonitorID , MonitorService > ( ) ;
2329
30+ private monitorIDsByUploadState : MonitorIDsByUploadState = {
31+ uploadInProgress : [ ] ,
32+ pausedForUpload : [ ] ,
33+ disposedForUpload : [ ] ,
34+ } ;
35+ 36+ private monitorServiceStartQueue : {
37+ monitorID : string ;
38+ serviceStartParams : [ Board , Port ] ;
39+ connectToClient : ( status : Status ) => void ;
40+ } [ ] = [ ] ;
41+ 2442 @inject ( MonitorServiceFactory )
2543 private monitorServiceFactory : MonitorServiceFactory ;
2644
@@ -48,6 +66,33 @@ export class MonitorManager extends CoreClientAware {
4866 return false ;
4967 }
5068
69+ private uploadIsInProgress ( ) : boolean {
70+ return this . monitorIDsByUploadState . uploadInProgress . length > 0 ;
71+ }
72+ 73+ private addToMonitorIDsByUploadState (
74+ state : UploadState ,
75+ monitorID : string
76+ ) : void {
77+ this . monitorIDsByUploadState [ state ] . push ( monitorID ) ;
78+ }
79+ 80+ private removeFromMonitorIDsByUploadState (
81+ state : UploadState ,
82+ monitorID : string
83+ ) : void {
84+ this . monitorIDsByUploadState [ state ] = this . monitorIDsByUploadState [
85+ state
86+ ] . filter ( ( id ) => id !== monitorID ) ;
87+ }
88+ 89+ private monitorIDIsInUploadState (
90+ state : UploadState ,
91+ monitorID : string
92+ ) : boolean {
93+ return this . monitorIDsByUploadState [ state ] . includes ( monitorID ) ;
94+ }
95+ 5196 /**
5297 * Start a pluggable monitor that receives and sends messages
5398 * to the specified board and port combination.
@@ -56,13 +101,34 @@ export class MonitorManager extends CoreClientAware {
56101 * @returns a Status object to know if the process has been
57102 * started or if there have been errors.
58103 */
59- async startMonitor ( board : Board , port : Port ) : Promise < Status > {
104+ async startMonitor (
105+ board : Board ,
106+ port : Port ,
107+ connectToClient : ( status : Status ) => void
108+ ) : Promise < void > {
60109 const monitorID = this . monitorID ( board , port ) ;
110+ 61111 let monitor = this . monitorServices . get ( monitorID ) ;
62112 if ( ! monitor ) {
63113 monitor = this . createMonitor ( board , port ) ;
64114 }
65- return await monitor . start ( ) ;
115+ 116+ if ( this . uploadIsInProgress ( ) ) {
117+ this . monitorServiceStartQueue = this . monitorServiceStartQueue . filter (
118+ ( request ) => request . monitorID !== monitorID
119+ ) ;
120+ 121+ this . monitorServiceStartQueue . push ( {
122+ monitorID,
123+ serviceStartParams : [ board , port ] ,
124+ connectToClient,
125+ } ) ;
126+ 127+ return ;
128+ }
129+ 130+ const result = await monitor . start ( ) ;
131+ connectToClient ( result ) ;
66132 }
67133
68134 /**
@@ -111,14 +177,18 @@ export class MonitorManager extends CoreClientAware {
111177 // to retrieve if we don't have this information.
112178 return ;
113179 }
180+ 114181 const monitorID = this . monitorID ( board , port ) ;
182+ this . addToMonitorIDsByUploadState ( 'uploadInProgress' , monitorID ) ;
183+ 115184 const monitor = this . monitorServices . get ( monitorID ) ;
116185 if ( ! monitor ) {
117186 // There's no monitor running there, bail
118187 return ;
119188 }
120- monitor . setUploadInProgress ( true ) ;
121- return await monitor . pause ( ) ;
189+ 190+ this . addToMonitorIDsByUploadState ( 'pausedForUpload' , monitorID ) ;
191+ return monitor . pause ( ) ;
122192 }
123193
124194 /**
@@ -130,19 +200,69 @@ export class MonitorManager extends CoreClientAware {
130200 * started or if there have been errors.
131201 */
132202 async notifyUploadFinished ( board ?: Board , port ?: Port ) : Promise < Status > {
133- if ( ! board || ! port ) {
134- // We have no way of knowing which monitor
135- // to retrieve if we don't have this information.
136- return Status . NOT_CONNECTED ;
203+ let status : Status = Status . NOT_CONNECTED ;
204+ let portDidChangeOnUpload = false ;
205+ 206+ // We have no way of knowing which monitor
207+ // to retrieve if we don't have this information.
208+ if ( board && port ) {
209+ const monitorID = this . monitorID ( board , port ) ;
210+ this . removeFromMonitorIDsByUploadState ( 'uploadInProgress' , monitorID ) ;
211+ 212+ const monitor = this . monitorServices . get ( monitorID ) ;
213+ if ( monitor ) {
214+ status = await monitor . start ( ) ;
215+ }
216+ 217+ // this monitorID will only be present in "disposedForUpload"
218+ // if the upload changed the board port
219+ portDidChangeOnUpload = this . monitorIDIsInUploadState (
220+ 'disposedForUpload' ,
221+ monitorID
222+ ) ;
223+ if ( portDidChangeOnUpload ) {
224+ this . removeFromMonitorIDsByUploadState ( 'disposedForUpload' , monitorID ) ;
225+ }
226+ 227+ // in case a service was paused but not disposed
228+ this . removeFromMonitorIDsByUploadState ( 'pausedForUpload' , monitorID ) ;
137229 }
138- const monitorID = this . monitorID ( board , port ) ;
139- const monitor = this . monitorServices . get ( monitorID ) ;
140- if ( ! monitor ) {
141- // There's no monitor running there, bail
142- return Status . NOT_CONNECTED ;
230+ 231+ await this . startQueuedServices ( portDidChangeOnUpload ) ;
232+ return status ;
233+ }
234+ 235+ async startQueuedServices ( portDidChangeOnUpload : boolean ) : Promise < void > {
236+ // if the port changed during upload with the monitor open, "startMonitorPendingRequests"
237+ // will include a request for our "upload port', most likely at index 0.
238+ // We remove it, as this port was to be used exclusively for the upload
239+ const queued = portDidChangeOnUpload
240+ ? this . monitorServiceStartQueue . slice ( 1 )
241+ : this . monitorServiceStartQueue ;
242+ this . monitorServiceStartQueue = [ ] ;
243+ 244+ for ( const {
245+ monitorID,
246+ serviceStartParams : [ _ , port ] ,
247+ connectToClient,
248+ } of queued ) {
249+ const boardsState = await this . boardsService . getState ( ) ;
250+ const boardIsStillOnPort = Object . keys ( boardsState )
251+ . map ( ( connection : string ) => {
252+ const portAddress = connection . split ( '|' ) [ 0 ] ;
253+ return portAddress ;
254+ } )
255+ . some ( ( portAddress : string ) => port . address === portAddress ) ;
256+ 257+ if ( boardIsStillOnPort ) {
258+ const monitorService = this . monitorServices . get ( monitorID ) ;
259+ 260+ if ( monitorService ) {
261+ const result = await monitorService . start ( ) ;
262+ connectToClient ( result ) ;
263+ }
264+ }
143265 }
144- monitor . setUploadInProgress ( false ) ;
145- return await monitor . start ( ) ;
146266 }
147267
148268 /**
@@ -202,6 +322,18 @@ export class MonitorManager extends CoreClientAware {
202322 this . monitorServices . set ( monitorID , monitor ) ;
203323 monitor . onDispose (
204324 ( ( ) => {
325+ // if a service is disposed during upload and
326+ // we paused it beforehand we know it was disposed
327+ // of because the upload changed the board port
328+ if (
329+ this . uploadIsInProgress ( ) &&
330+ this . monitorIDIsInUploadState ( 'pausedForUpload' , monitorID )
331+ ) {
332+ this . removeFromMonitorIDsByUploadState ( 'pausedForUpload' , monitorID ) ;
333+ 334+ this . addToMonitorIDsByUploadState ( 'disposedForUpload' , monitorID ) ;
335+ }
336+ 205337 this . monitorServices . delete ( monitorID ) ;
206338 } ) . bind ( this )
207339 ) ;
0 commit comments