11import {
2- CommandRegistry ,
2+ ApplicationError ,
33 Disposable ,
44 Emitter ,
55 MessageService ,
66 nls ,
77} from '@theia/core' ;
8+ import { Deferred } from '@theia/core/lib/common/promise-util' ;
89import { inject , injectable } from '@theia/core/shared/inversify' ;
10+ import { NotificationManager } from '@theia/messages/lib/browser/notifications-manager' ;
11+ import { MessageType } from '@theia/core/lib/common/message-service-protocol' ;
912import { Board , Port } from '../common/protocol' ;
1013import {
1114 Monitor ,
@@ -23,21 +26,31 @@ import { BoardsServiceProvider } from './boards/boards-service-provider';
2326export class MonitorManagerProxyClientImpl
2427 implements MonitorManagerProxyClient
2528{
29+ @inject ( MessageService )
30+ private readonly messageService : MessageService ;
31+ // This is necessary to call the backend methods from the frontend
32+ @inject ( MonitorManagerProxyFactory )
33+ private readonly server : MonitorManagerProxyFactory ;
34+ @inject ( BoardsServiceProvider )
35+ private readonly boardsServiceProvider : BoardsServiceProvider ;
36+ @inject ( NotificationManager )
37+ private readonly notificationManager : NotificationManager ;
38+
2639 // When pluggable monitor messages are received from the backend
2740 // this event is triggered.
2841 // Ideally a frontend component is connected to this event
2942 // to update the UI.
30- protected readonly onMessagesReceivedEmitter = new Emitter < {
43+ private readonly onMessagesReceivedEmitter = new Emitter < {
3144 messages : string [ ] ;
3245 } > ( ) ;
3346 readonly onMessagesReceived = this . onMessagesReceivedEmitter . event ;
3447
35- protected readonly onMonitorSettingsDidChangeEmitter =
48+ private readonly onMonitorSettingsDidChangeEmitter =
3649 new Emitter < MonitorSettings > ( ) ;
3750 readonly onMonitorSettingsDidChange =
3851 this . onMonitorSettingsDidChangeEmitter . event ;
3952
40- protected readonly onMonitorShouldResetEmitter = new Emitter ( ) ;
53+ private readonly onMonitorShouldResetEmitter = new Emitter < void > ( ) ;
4154 readonly onMonitorShouldReset = this . onMonitorShouldResetEmitter . event ;
4255
4356 // WebSocket used to handle pluggable monitor communication between
@@ -51,29 +64,16 @@ export class MonitorManagerProxyClientImpl
5164 return this . wsPort ;
5265 }
5366
54- constructor (
55- @inject ( MessageService )
56- protected messageService : MessageService ,
57-
58- // This is necessary to call the backend methods from the frontend
59- @inject ( MonitorManagerProxyFactory )
60- protected server : MonitorManagerProxyFactory ,
61-
62- @inject ( CommandRegistry )
63- protected readonly commandRegistry : CommandRegistry ,
64-
65- @inject ( BoardsServiceProvider )
66- protected readonly boardsServiceProvider : BoardsServiceProvider
67- ) { }
68-
6967 /**
7068 * Connects a localhost WebSocket using the specified port.
7169 * @param addressPort port of the WebSocket
7270 */
7371 async connect ( addressPort : number ) : Promise < void > {
74- if ( ! ! this . webSocket ) {
75- if ( this . wsPort === addressPort ) return ;
76- else this . disconnect ( ) ;
72+ if ( this . webSocket ) {
73+ if ( this . wsPort === addressPort ) {
74+ return ;
75+ }
76+ this . disconnect ( ) ;
7777 }
7878 try {
7979 this . webSocket = new WebSocket ( `ws://localhost:${ addressPort } ` ) ;
@@ -87,6 +87,9 @@ export class MonitorManagerProxyClientImpl
8787 return ;
8888 }
8989
90+ const opened = new Deferred < void > ( ) ;
91+ this . webSocket . onopen = ( ) => opened . resolve ( ) ;
92+ this . webSocket . onerror = ( ) => opened . reject ( ) ;
9093 this . webSocket . onmessage = ( message ) => {
9194 const parsedMessage = JSON . parse ( message . data ) ;
9295 if ( Array . isArray ( parsedMessage ) )
@@ -99,19 +102,26 @@ export class MonitorManagerProxyClientImpl
99102 }
100103 } ;
101104 this . wsPort = addressPort ;
105+ return opened . promise ;
102106 }
103107
104108 /**
105109 * Disconnects the WebSocket if connected.
106110 */
107111 disconnect ( ) : void {
108- if ( ! this . webSocket ) return ;
112+ if ( ! this . webSocket ) {
113+ return ;
114+ }
109115 this . onBoardsConfigChanged ?. dispose ( ) ;
110116 this . onBoardsConfigChanged = undefined ;
111117 try {
112- this . webSocket ? .close ( ) ;
118+ this . webSocket . close ( ) ;
113119 this . webSocket = undefined ;
114- } catch {
120+ } catch ( err ) {
121+ console . error (
122+ 'Could not close the websocket connection for the monitor.' ,
123+ err
124+ ) ;
115125 this . messageService . error (
116126 nls . localize (
117127 'arduino/monitor/unableToCloseWebSocket' ,
@@ -126,6 +136,7 @@ export class MonitorManagerProxyClientImpl
126136 }
127137
128138 async startMonitor ( settings ?: PluggableMonitorSettings ) : Promise < void > {
139+ await this . boardsServiceProvider . reconciled ;
129140 this . lastConnectedBoard = {
130141 selectedBoard : this . boardsServiceProvider . boardsConfig . selectedBoard ,
131142 selectedPort : this . boardsServiceProvider . boardsConfig . selectedPort ,
@@ -150,11 +161,11 @@ export class MonitorManagerProxyClientImpl
150161 ? Port . keyOf ( this . lastConnectedBoard . selectedPort )
151162 : undefined )
152163 ) {
153- this . onMonitorShouldResetEmitter . fire ( null ) ;
154164 this . lastConnectedBoard = {
155165 selectedBoard : selectedBoard ,
156166 selectedPort : selectedPort ,
157167 } ;
168+ this . onMonitorShouldResetEmitter . fire ( ) ;
158169 } else {
159170 // a board is plugged and it's the same as prev, rerun "this.startMonitor" to
160171 // recreate the listener callback
@@ -167,7 +178,14 @@ export class MonitorManagerProxyClientImpl
167178 const { selectedBoard, selectedPort } =
168179 this . boardsServiceProvider . boardsConfig ;
169180 if ( ! selectedBoard || ! selectedBoard . fqbn || ! selectedPort ) return ;
170- await this . server ( ) . startMonitor ( selectedBoard , selectedPort , settings ) ;
181+ try {
182+ this . clearVisibleNotification ( ) ;
183+ await this . server ( ) . startMonitor ( selectedBoard , selectedPort , settings ) ;
184+ } catch ( err ) {
185+ const message = ApplicationError . is ( err ) ? err . message : String ( err ) ;
186+ this . previousNotificationId = this . notificationId ( message ) ;
187+ this . messageService . error ( message ) ;
188+ }
171189 }
172190
173191 getCurrentSettings ( board : Board , port : Port ) : Promise < MonitorSettings > {
@@ -199,4 +217,24 @@ export class MonitorManagerProxyClientImpl
199217 } )
200218 ) ;
201219 }
220+
221+ /**
222+ * This is the internal (Theia) ID of the notification that is currently visible.
223+ * It's stored here as a field to be able to close it before starting a new monitor connection. It's a hack.
224+ */
225+ private previousNotificationId : string | undefined ;
226+ private clearVisibleNotification ( ) : void {
227+ if ( this . previousNotificationId ) {
228+ this . notificationManager . clear ( this . previousNotificationId ) ;
229+ this . previousNotificationId = undefined ;
230+ }
231+ }
232+
233+ private notificationId ( message : string , ...actions : string [ ] ) : string {
234+ return this . notificationManager [ 'getMessageId' ] ( {
235+ text : message ,
236+ actions,
237+ type : MessageType . Error ,
238+ } ) ;
239+ }
202240}
0 commit comments