From 33dcb5ccc5caa350fb5f0f762225aa4d76a0ae1c Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Wed, 24 Mar 2021 16:03:21 +0100 Subject: [PATCH] ATL-1137: Show error when could not connect to CLI Signed-off-by: Akos Kitta --- .vscode/launch.json | 3 ++- .../theia/workspace/workspace-service.ts | 11 ++++++-- .../src/node/board-discovery.ts | 26 ++----------------- .../src/node/core-client-provider.ts | 26 ++++++++++++------- .../src/node/grpc-client-provider.ts | 11 ++++---- .../src/node/monitor/monitor-service-impl.ts | 3 +++ 6 files changed, 39 insertions(+), 41 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 3854ce418..7a8f58298 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -29,9 +29,10 @@ "NODE_PRESERVE_SYMLINKS": "1" } }, - "program": "${workspaceRoot}/electron-app/src-gen/frontend/electron-main.js", + "cwd": "${workspaceFolder}/electron-app", "protocol": "inspector", "args": [ + ".", "--log-level=debug", "--hostname=localhost", "--no-cluster", diff --git a/arduino-ide-extension/src/browser/theia/workspace/workspace-service.ts b/arduino-ide-extension/src/browser/theia/workspace/workspace-service.ts index 3db16c732..784f0a7fd 100644 --- a/arduino-ide-extension/src/browser/theia/workspace/workspace-service.ts +++ b/arduino-ide-extension/src/browser/theia/workspace/workspace-service.ts @@ -6,6 +6,7 @@ import { MessageService } from '@theia/core/lib/common/message-service'; import { ApplicationServer } from '@theia/core/lib/common/application-protocol'; import { FrontendApplication } from '@theia/core/lib/browser/frontend-application'; import { FocusTracker, Widget } from '@theia/core/lib/browser'; +import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state'; import { WorkspaceService as TheiaWorkspaceService } from '@theia/workspace/lib/browser/workspace-service'; import { ConfigService } from '../../../common/protocol/config-service'; import { SketchesService, Sketch, SketchContainer } from '../../../common/protocol/sketches-service'; @@ -29,10 +30,15 @@ export class WorkspaceService extends TheiaWorkspaceService { @inject(ApplicationServer) protected readonly applicationServer: ApplicationServer; + @inject(FrontendApplicationStateService) + protected readonly appStateService: FrontendApplicationStateService; + + private application: FrontendApplication; private workspaceUri?: Promise; - private version?: string + private version?: string; async onStart(application: FrontendApplication): Promise { + this.application = application; const info = await this.applicationServer.getApplicationInfo(); this.version = info?.version; application.shell.onDidChangeCurrentWidget(this.onCurrentWidgetChange.bind(this)); @@ -62,11 +68,12 @@ export class WorkspaceService extends TheiaWorkspaceService { } return (await this.sketchService.createNewSketch()).uri; } catch (err) { + this.appStateService.reachedState('ready').then(() => this.application.shell.update()); this.logger.fatal(`Failed to determine the sketch directory: ${err}`) this.messageService.error( 'There was an error creating the sketch directory. ' + 'See the log for more details. ' + - 'The application will probably not work as expected.') + 'The application will probably not work as expected.'); return super.getDefaultWorkspaceUri(); } })(); diff --git a/arduino-ide-extension/src/node/board-discovery.ts b/arduino-ide-extension/src/node/board-discovery.ts index d10de5e76..73f77ba4d 100644 --- a/arduino-ide-extension/src/node/board-discovery.ts +++ b/arduino-ide-extension/src/node/board-discovery.ts @@ -2,7 +2,7 @@ import { injectable, inject, postConstruct, named } from 'inversify'; import { ClientDuplexStream } from '@grpc/grpc-js'; import { ILogger } from '@theia/core/lib/common/logger'; import { deepClone } from '@theia/core/lib/common/objects'; -import { CoreClientProvider } from './core-client-provider'; +import { CoreClientAware } from './core-client-provider'; import { BoardListWatchReq, BoardListWatchResp } from './cli-protocol/commands/board_pb'; import { Board, Port, NotificationServiceServer, AvailablePorts, AttachedBoardsChangeEvent } from '../common/protocol'; @@ -12,15 +12,12 @@ import { Board, Port, NotificationServiceServer, AvailablePorts, AttachedBoardsC * Unlike other services, this is not connection scoped. */ @injectable() -export class BoardDiscovery { +export class BoardDiscovery extends CoreClientAware { @inject(ILogger) @named('discovery') protected discoveryLogger: ILogger; - @inject(CoreClientProvider) - protected readonly coreClientProvider: CoreClientProvider; - @inject(NotificationServiceServer) protected readonly notificationService: NotificationServiceServer; @@ -133,23 +130,4 @@ export class BoardDiscovery { return availablePorts; } - private async coreClient(): Promise { - const coreClient = await new Promise(async resolve => { - const client = await this.coreClientProvider.client(); - if (client) { - resolve(client); - return; - } - const toDispose = this.coreClientProvider.onClientReady(async () => { - const client = await this.coreClientProvider.client(); - if (client) { - toDispose.dispose(); - resolve(client); - return; - } - }); - }); - return coreClient; - } - } diff --git a/arduino-ide-extension/src/node/core-client-provider.ts b/arduino-ide-extension/src/node/core-client-provider.ts index 7919ea9bf..0cbf307c9 100644 --- a/arduino-ide-extension/src/node/core-client-provider.ts +++ b/arduino-ide-extension/src/node/core-client-provider.ts @@ -1,6 +1,7 @@ import * as grpc from '@grpc/grpc-js'; import { inject, injectable } from 'inversify'; import { Event, Emitter } from '@theia/core/lib/common/event'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; import { GrpcClientProvider } from './grpc-client-provider'; import { ArduinoCoreClient } from './cli-protocol/commands/commands_grpc_pb'; import * as commandsGrpcPb from './cli-protocol/commands/commands_grpc_pb'; @@ -27,7 +28,7 @@ export class CoreClientProvider extends GrpcClientProvider { if (port && port === this._port) { // No need to create a new gRPC client, but we have to update the indexes. - if (this._client) { + if (this._client && !(this._client instanceof Error)) { await this.updateIndexes(this._client); this.onClientReadyEmitter.fire(); } @@ -48,7 +49,7 @@ export class CoreClientProvider extends GrpcClientProvider resp = data); - stream.on('end', () => resolve(resp)); + stream.on('end', () => resolve(resp!)); stream.on('error', err => reject(err)); }); @@ -175,20 +176,27 @@ export abstract class CoreClientAware { protected readonly coreClientProvider: CoreClientProvider; protected async coreClient(): Promise { - const coreClient = await new Promise(async resolve => { + const coreClient = await new Promise(async (resolve, reject) => { + const handle = (c: CoreClientProvider.Client | Error) => { + if (c instanceof Error) { + reject(c); + } else { + resolve(c); + } + } const client = await this.coreClientProvider.client(); if (client) { - resolve(client); + handle(client); return; } - const toDispose = this.coreClientProvider.onClientReady(async () => { + const toDispose = new DisposableCollection(); + toDispose.push(this.coreClientProvider.onClientReady(async () => { const client = await this.coreClientProvider.client(); if (client) { - toDispose.dispose(); - resolve(client); - return; + handle(client); } - }); + toDispose.dispose(); + })); }); return coreClient; } diff --git a/arduino-ide-extension/src/node/grpc-client-provider.ts b/arduino-ide-extension/src/node/grpc-client-provider.ts index c87770090..49ba5a9de 100644 --- a/arduino-ide-extension/src/node/grpc-client-provider.ts +++ b/arduino-ide-extension/src/node/grpc-client-provider.ts @@ -17,7 +17,7 @@ export abstract class GrpcClientProvider { protected readonly configService: ConfigServiceImpl; protected _port: string | number | undefined; - protected _client: C | undefined; + protected _client: C | Error | undefined; @postConstruct() protected init(): void { @@ -28,7 +28,7 @@ export abstract class GrpcClientProvider { this.configService.onConfigChange(updateClient); this.daemon.ready.then(updateClient); this.daemon.onDaemonStopped(() => { - if (this._client) { + if (this._client && !(this._client instanceof Error)) { this.close(this._client); } this._client = undefined; @@ -36,12 +36,12 @@ export abstract class GrpcClientProvider { }) } - async client(): Promise { + async client(): Promise { try { await this.daemon.ready; return this._client; } catch (error) { - return undefined; + return error; } } @@ -50,7 +50,7 @@ export abstract class GrpcClientProvider { return; // Nothing to do. } this._port = port; - if (this._client) { + if (this._client && !(this._client instanceof Error)) { this.close(this._client); this._client = undefined; } @@ -60,6 +60,7 @@ export abstract class GrpcClientProvider { this._client = client; } catch (error) { this.logger.error('Could not create client for gRPC.', error) + this._client = error; } } } diff --git a/arduino-ide-extension/src/node/monitor/monitor-service-impl.ts b/arduino-ide-extension/src/node/monitor/monitor-service-impl.ts index 06e68cc0e..9005ace97 100644 --- a/arduino-ide-extension/src/node/monitor/monitor-service-impl.ts +++ b/arduino-ide-extension/src/node/monitor/monitor-service-impl.ts @@ -72,6 +72,9 @@ export class MonitorServiceImpl implements MonitorService { if (!client) { return Status.NOT_CONNECTED; } + if (client instanceof Error) { + return { message: client.message }; + } const duplex = client.streamingOpen(); this.connection = { duplex, config };