Skip to content

Commit a54d7c8

Browse files
davegarthsimpsonAlberto Iannaccone
and
Alberto Iannaccone
authored
#1032 failing upload flag for monitor mgr (#1040)
* 1032 failing upload flag for monitor mgr * move upload failure fix logic to frontend * misc corrections * avoid starting monitor when upload is in progress * avoid starting monitor when upload is in progress * prevent monitor side effects on upload (WIP) * send upload req after notifying mgr * dispose instead of pause on upld (code not final) * Revert "dispose instead of pause on upld (code not final)" This reverts commit 2d5dff2. * force wait before upload (test) * always start queued services after uplaod finishes * test cli with monitor close delay * clean up unnecessary await(s) * remove unused dependency * revert CLI to 0.23 * use master cli for testing, await in upload finish * remove upload port from pending monitor requests * fix startQueuedServices * refinements queued monitors * clean up monitor mgr state * fix typo from prev cleanup * avoid dupl queued monitor services * variable name changes * reference latest cli commit in package.json Co-authored-by: Alberto Iannaccone <[email protected]>
1 parent 84109e4 commit a54d7c8

File tree

6 files changed

+163
-38
lines changed

6 files changed

+163
-38
lines changed

arduino-ide-extension/package.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,11 @@
156156
],
157157
"arduino": {
158158
"cli": {
159-
"version": "0.23.0"
159+
"version": {
160+
"owner": "arduino",
161+
"repo": "arduino-cli",
162+
"commitish": "c1b10f562f1e1a112e215a69b84e2f2b69e3af2d"
163+
}
160164
},
161165
"fwuploader": {
162166
"version": "2.2.0"

arduino-ide-extension/src/node/arduino-firmware-uploader-impl.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export class ArduinoFirmwareUploaderImpl implements ArduinoFirmwareUploader {
9090
} catch (e) {
9191
throw e;
9292
} finally {
93-
this.monitorManager.notifyUploadFinished(board, port);
93+
await this.monitorManager.notifyUploadFinished(board, port);
9494
return output;
9595
}
9696
}

arduino-ide-extension/src/node/core-service-impl.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
119119
return request;
120120
}
121121

122-
async upload(options: CoreService.Upload.Options): Promise<void> {
122+
upload(options: CoreService.Upload.Options): Promise<void> {
123123
return this.doUpload(
124124
options,
125125
() => new UploadRequest(),

arduino-ide-extension/src/node/monitor-manager-proxy-impl.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,14 @@ export class MonitorManagerProxyImpl implements MonitorManagerProxy {
4040
if (settings) {
4141
await this.changeMonitorSettings(board, port, settings);
4242
}
43-
const status = await this.manager.startMonitor(board, port);
44-
if (status === Status.ALREADY_CONNECTED || status === Status.OK) {
45-
// Monitor started correctly, connect it with the frontend
46-
this.client.connect(this.manager.getWebsocketAddressPort(board, port));
47-
}
43+
44+
const connectToClient = (status: Status) => {
45+
if (status === Status.ALREADY_CONNECTED || status === Status.OK) {
46+
// Monitor started correctly, connect it with the frontend
47+
this.client.connect(this.manager.getWebsocketAddressPort(board, port));
48+
}
49+
};
50+
return this.manager.startMonitor(board, port, connectToClient);
4851
}
4952

5053
/**

arduino-ide-extension/src/node/monitor-manager.ts

+148-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ILogger } from '@theia/core';
22
import { 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';
44
import { CoreClientAware } from './core-client-provider';
55
import { MonitorService } from './monitor-service';
66
import { MonitorServiceFactory } from './monitor-service-factory';
@@ -11,16 +11,34 @@ import {
1111

1212
type MonitorID = string;
1313

14+
type UploadState = 'uploadInProgress' | 'pausedForUpload' | 'disposedForUpload';
15+
type MonitorIDsByUploadState = Record<UploadState, MonitorID[]>;
16+
1417
export const MonitorManagerName = 'monitor-manager';
1518

1619
@injectable()
1720
export 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
);

arduino-ide-extension/src/node/monitor-service.ts

-14
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ export class MonitorService extends CoreClientAware implements Disposable {
6060
protected readonly onDisposeEmitter = new Emitter<void>();
6161
readonly onDispose = this.onDisposeEmitter.event;
6262

63-
protected uploadInProgress = false;
6463
protected _initialized = new Deferred<void>();
6564
protected creating: Deferred<Status>;
6665

@@ -114,10 +113,6 @@ export class MonitorService extends CoreClientAware implements Disposable {
114113
return this._initialized.promise;
115114
}
116115

117-
setUploadInProgress(status: boolean): void {
118-
this.uploadInProgress = status;
119-
}
120-
121116
getWebsocketAddressPort(): number {
122117
return this.webSocketProvider.getAddress().port;
123118
}
@@ -161,15 +156,6 @@ export class MonitorService extends CoreClientAware implements Disposable {
161156
return this.creating.promise;
162157
}
163158

164-
if (this.uploadInProgress) {
165-
this.updateClientsSettings({
166-
monitorUISettings: { connected: false, serialPort: this.port.address },
167-
});
168-
169-
this.creating.resolve(Status.UPLOAD_IN_PROGRESS);
170-
return this.creating.promise;
171-
}
172-
173159
this.logger.info('starting monitor');
174160

175161
// get default monitor settings from the CLI

0 commit comments

Comments
 (0)