Skip to content

Commit c2f15e2

Browse files
author
Akos Kitta
committed
fix: handle missing platform on monitor start
Ref: #1974 Signed-off-by: Akos Kitta <[email protected]>
1 parent f61c8b5 commit c2f15e2

File tree

2 files changed

+90
-61
lines changed

2 files changed

+90
-61
lines changed

Diff for: arduino-ide-extension/src/browser/monitor-manager-proxy-client-impl.ts

+14-6
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,11 @@ export class MonitorManagerProxyClientImpl
7373
* @param addressPort port of the WebSocket
7474
*/
7575
async connect(addressPort: number): Promise<void> {
76-
if (!!this.webSocket) {
77-
if (this.wsPort === addressPort) return;
78-
else this.disconnect();
76+
if (this.webSocket) {
77+
if (this.wsPort === addressPort) {
78+
return;
79+
}
80+
this.disconnect();
7981
}
8082
try {
8183
this.webSocket = new WebSocket(`ws://localhost:${addressPort}`);
@@ -111,13 +113,19 @@ export class MonitorManagerProxyClientImpl
111113
* Disconnects the WebSocket if connected.
112114
*/
113115
disconnect(): void {
114-
if (!this.webSocket) return;
116+
if (!this.webSocket) {
117+
return;
118+
}
115119
this.onBoardsConfigChanged?.dispose();
116120
this.onBoardsConfigChanged = undefined;
117121
try {
118-
this.webSocket?.close();
122+
this.webSocket.close();
119123
this.webSocket = undefined;
120-
} catch {
124+
} catch (err) {
125+
console.error(
126+
'Could not close the websocket connection for the monitor.',
127+
err
128+
);
121129
this.messageService.error(
122130
nls.localize(
123131
'arduino/monitor/unableToCloseWebSocket',

Diff for: arduino-ide-extension/src/node/monitor-service.ts

+76-55
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ClientDuplexStream } from '@grpc/grpc-js';
1+
import { ClientDuplexStream, status } from '@grpc/grpc-js';
22
import {
33
ApplicationError,
44
Disposable,
@@ -134,7 +134,7 @@ export class MonitorService extends CoreClientAware implements Disposable {
134134
this.updateClientsSettings(this.settings);
135135
});
136136

137-
this.portMonitorSettings(this.port.protocol, this.board.fqbn!).then(
137+
this.portMonitorSettings(this.port.protocol, this.board.fqbn!, true).then(
138138
async (settings) => {
139139
this.settings = {
140140
...this.settings,
@@ -205,51 +205,53 @@ export class MonitorService extends CoreClientAware implements Disposable {
205205
}
206206

207207
this.logger.info('starting monitor');
208-
this.updateClientsSettings({
209-
monitorUISettings: { connectionStatus: 'connecting' },
210-
});
211208

212-
// get default monitor settings from the CLI
213-
const defaultSettings = await this.portMonitorSettings(
214-
this.port.protocol,
215-
this.board.fqbn
216-
);
217-
// get actual settings from the settings provider
218-
this.settings = {
219-
...this.settings,
220-
pluggableMonitorSettings: {
221-
...this.settings.pluggableMonitorSettings,
222-
...(await this.monitorSettingsProvider.getSettings(
223-
this.monitorID,
224-
defaultSettings
225-
)),
226-
},
227-
};
209+
try {
210+
// get default monitor settings from the CLI
211+
const defaultSettings = await this.portMonitorSettings(
212+
this.port.protocol,
213+
this.board.fqbn
214+
);
228215

229-
const coreClient = await this.coreClient;
216+
this.updateClientsSettings({
217+
monitorUISettings: { connectionStatus: 'connecting' },
218+
});
230219

231-
const { instance } = coreClient;
232-
const monitorRequest = new MonitorRequest();
233-
monitorRequest.setInstance(instance);
234-
if (this.board?.fqbn) {
235-
monitorRequest.setFqbn(this.board.fqbn);
236-
}
237-
if (this.port?.address && this.port?.protocol) {
238-
const rpcPort = new RpcPort();
239-
rpcPort.setAddress(this.port.address);
240-
rpcPort.setProtocol(this.port.protocol);
241-
monitorRequest.setPort(rpcPort);
242-
}
243-
const config = new MonitorPortConfiguration();
244-
for (const id in this.settings.pluggableMonitorSettings) {
245-
const s = new MonitorPortSetting();
246-
s.setSettingId(id);
247-
s.setValue(this.settings.pluggableMonitorSettings[id].selectedValue);
248-
config.addSettings(s);
249-
}
250-
monitorRequest.setPortConfiguration(config);
220+
// get actual settings from the settings provider
221+
this.settings = {
222+
...this.settings,
223+
pluggableMonitorSettings: {
224+
...this.settings.pluggableMonitorSettings,
225+
...(await this.monitorSettingsProvider.getSettings(
226+
this.monitorID,
227+
defaultSettings
228+
)),
229+
},
230+
};
231+
232+
const coreClient = await this.coreClient;
233+
234+
const { instance } = coreClient;
235+
const monitorRequest = new MonitorRequest();
236+
monitorRequest.setInstance(instance);
237+
if (this.board?.fqbn) {
238+
monitorRequest.setFqbn(this.board.fqbn);
239+
}
240+
if (this.port?.address && this.port?.protocol) {
241+
const rpcPort = new RpcPort();
242+
rpcPort.setAddress(this.port.address);
243+
rpcPort.setProtocol(this.port.protocol);
244+
monitorRequest.setPort(rpcPort);
245+
}
246+
const config = new MonitorPortConfiguration();
247+
for (const id in this.settings.pluggableMonitorSettings) {
248+
const s = new MonitorPortSetting();
249+
s.setSettingId(id);
250+
s.setValue(this.settings.pluggableMonitorSettings[id].selectedValue);
251+
config.addSettings(s);
252+
}
253+
monitorRequest.setPortConfiguration(config);
251254

252-
try {
253255
await this.pollWriteToStream(monitorRequest);
254256
// Only store the config, if the monitor has successfully started.
255257
this.currentPortConfigSnapshot = MonitorPortConfiguration.toObject(
@@ -282,7 +284,11 @@ export class MonitorService extends CoreClientAware implements Disposable {
282284
? err
283285
: createConnectionFailedError(
284286
this.port,
285-
err instanceof Error ? err.message : String(err)
287+
ServiceError.is(err)
288+
? err.details
289+
: err instanceof Error
290+
? err.message
291+
: String(err)
286292
);
287293
this.creating.reject(appError);
288294
this.updateClientsSettings({
@@ -485,7 +491,8 @@ export class MonitorService extends CoreClientAware implements Disposable {
485491
*/
486492
private async portMonitorSettings(
487493
protocol: string,
488-
fqbn: string
494+
fqbn: string,
495+
swallowsPlatformNotFoundError = false
489496
): Promise<PluggableMonitorSettings> {
490497
const coreClient = await this.coreClient;
491498
const { client, instance } = coreClient;
@@ -494,19 +501,33 @@ export class MonitorService extends CoreClientAware implements Disposable {
494501
req.setPortProtocol(protocol);
495502
req.setFqbn(fqbn);
496503

497-
const res = await new Promise<EnumerateMonitorPortSettingsResponse>(
498-
(resolve, reject) => {
499-
client.enumerateMonitorPortSettings(req, (err, resp) => {
500-
if (!!err) {
501-
reject(err);
504+
const resp = await new Promise<
505+
EnumerateMonitorPortSettingsResponse | undefined
506+
>((resolve, reject) => {
507+
client.enumerateMonitorPortSettings(req, async (err, resp) => {
508+
if (err) {
509+
// Check whether the platform is installed: https://github.com/arduino/arduino-ide/issues/1974.
510+
// No error codes. Look for `Unknown FQBN: platform arduino:mbed_nano is not installed` message similarities: https://github.com/arduino/arduino-cli/issues/1762.
511+
if (
512+
swallowsPlatformNotFoundError &&
513+
ServiceError.is(err) &&
514+
err.code === status.NOT_FOUND &&
515+
err.details.includes('FQBN') &&
516+
err.details.includes(fqbn.split(':', 2).join(':')) // create a platform ID from the FQBN
517+
) {
518+
resolve(undefined);
502519
}
503-
resolve(resp);
504-
});
505-
}
506-
);
520+
reject(err);
521+
}
522+
resolve(resp);
523+
});
524+
});
507525

508526
const settings: PluggableMonitorSettings = {};
509-
for (const iterator of res.getSettingsList()) {
527+
if (!resp) {
528+
return settings;
529+
}
530+
for (const iterator of resp.getSettingsList()) {
510531
settings[iterator.getSettingId()] = {
511532
id: iterator.getSettingId(),
512533
label: iterator.getLabel(),

0 commit comments

Comments
 (0)