Skip to content

Commit 77307ac

Browse files
author
Akos Kitta
committed
changed how to init cli config service.
on daemon start, the port is broadcasted from BE. Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
1 parent 7fd35a2 commit 77307ac

13 files changed

+153
-196
lines changed

arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
ExecutableService,
88
Sketch,
99
LibraryService,
10+
ArduinoDaemon,
1011
} from '../common/protocol';
1112
import { Mutex } from 'async-mutex';
1213
import {
@@ -172,6 +173,9 @@ export class ArduinoFrontendContribution
172173
@inject(IDEUpdaterDialog)
173174
protected readonly updaterDialog: IDEUpdaterDialog;
174175

176+
@inject(ArduinoDaemon)
177+
protected readonly daemon: ArduinoDaemon;
178+
175179
protected invalidConfigPopup:
176180
| Promise<void | 'No' | 'Yes' | undefined>
177181
| undefined;
@@ -369,6 +373,10 @@ export class ArduinoFrontendContribution
369373
): Promise<void> {
370374
const release = await this.languageServerStartMutex.acquire();
371375
try {
376+
const port = this.daemon.tryGetPort();
377+
if (!port) {
378+
return;
379+
}
372380
await this.hostedPluginSupport.didStart;
373381
const details = await this.boardsService.getBoardDetails({ fqbn });
374382
if (!details) {
@@ -416,8 +424,6 @@ export class ArduinoFrontendContribution
416424
this.fileService.fsPath(new URI(lsUri)),
417425
]);
418426

419-
const config = await this.configService.getConfiguration();
420-
421427
this.languageServerFqbn = await Promise.race([
422428
new Promise<undefined>((_, reject) =>
423429
setTimeout(
@@ -429,7 +435,7 @@ export class ArduinoFrontendContribution
429435
'arduino.languageserver.start',
430436
{
431437
lsPath,
432-
cliDaemonAddr: `localhost:${config.daemon.port}`, // TODO: verify if this port is coming from the BE
438+
cliDaemonAddr: `localhost:${port}`,
433439
clangdPath,
434440
log: currentSketchPath ? currentSketchPath : log,
435441
cliDaemonInstance: '1',

arduino-ide-extension/src/browser/notification-center.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
1+
import {
2+
inject,
3+
injectable,
4+
postConstruct,
5+
} from '@theia/core/shared/inversify';
26
import { Emitter } from '@theia/core/lib/common/event';
37
import { JsonRpcProxy } from '@theia/core/lib/common/messaging/proxy-factory';
48
import { DisposableCollection } from '@theia/core/lib/common/disposable';
@@ -23,7 +27,7 @@ export class NotificationCenter
2327
protected readonly server: JsonRpcProxy<NotificationServiceServer>;
2428

2529
protected readonly indexUpdatedEmitter = new Emitter<void>();
26-
protected readonly daemonStartedEmitter = new Emitter<void>();
30+
protected readonly daemonStartedEmitter = new Emitter<string>();
2731
protected readonly daemonStoppedEmitter = new Emitter<void>();
2832
protected readonly configChangedEmitter = new Emitter<{
2933
config: Config | undefined;
@@ -82,8 +86,8 @@ export class NotificationCenter
8286
this.indexUpdatedEmitter.fire();
8387
}
8488

85-
notifyDaemonStarted(): void {
86-
this.daemonStartedEmitter.fire();
89+
notifyDaemonStarted(port: string): void {
90+
this.daemonStartedEmitter.fire(port);
8791
}
8892

8993
notifyDaemonStopped(): void {

arduino-ide-extension/src/browser/theia/core/connection-status-service.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
1+
import {
2+
inject,
3+
injectable,
4+
postConstruct,
5+
} from '@theia/core/shared/inversify';
26
import { Disposable } from '@theia/core/lib/common/disposable';
37
import { StatusBarAlignment } from '@theia/core/lib/browser/status-bar/status-bar';
48
import {
@@ -18,18 +22,22 @@ export class FrontendConnectionStatusService extends TheiaFrontendConnectionStat
1822
@inject(NotificationCenter)
1923
protected readonly notificationCenter: NotificationCenter;
2024

21-
protected isRunning = false;
25+
protected connectedPort: string | undefined;
2226

2327
@postConstruct()
2428
protected override async init(): Promise<void> {
2529
this.schedulePing();
2630
try {
27-
this.isRunning = await this.daemon.isRunning();
31+
this.connectedPort = await this.daemon.tryGetPort();
2832
} catch {}
29-
this.notificationCenter.onDaemonStarted(() => (this.isRunning = true));
30-
this.notificationCenter.onDaemonStopped(() => (this.isRunning = false));
33+
this.notificationCenter.onDaemonStarted(
34+
(port) => (this.connectedPort = port)
35+
);
36+
this.notificationCenter.onDaemonStopped(
37+
() => (this.connectedPort = undefined)
38+
);
3139
this.wsConnectionProvider.onIncomingMessageActivity(() => {
32-
this.updateStatus(this.isRunning);
40+
this.updateStatus(!!this.connectedPort);
3341
this.schedulePing();
3442
});
3543
}
@@ -43,19 +51,23 @@ export class ApplicationConnectionStatusContribution extends TheiaApplicationCon
4351
@inject(NotificationCenter)
4452
protected readonly notificationCenter: NotificationCenter;
4553

46-
protected isRunning = false;
54+
protected connectedPort: string | undefined;
4755

4856
@postConstruct()
4957
protected async init(): Promise<void> {
5058
try {
51-
this.isRunning = await this.daemon.isRunning();
59+
this.connectedPort = await this.daemon.tryGetPort();
5260
} catch {}
53-
this.notificationCenter.onDaemonStarted(() => (this.isRunning = true));
54-
this.notificationCenter.onDaemonStopped(() => (this.isRunning = false));
61+
this.notificationCenter.onDaemonStarted(
62+
(port) => (this.connectedPort = port)
63+
);
64+
this.notificationCenter.onDaemonStopped(
65+
() => (this.connectedPort = undefined)
66+
);
5567
}
5668

5769
protected override onStateChange(state: ConnectionStatus): void {
58-
if (!this.isRunning && state === ConnectionStatus.ONLINE) {
70+
if (!this.connectedPort && state === ConnectionStatus.ONLINE) {
5971
return;
6072
}
6173
super.onStateChange(state);
@@ -64,11 +76,11 @@ export class ApplicationConnectionStatusContribution extends TheiaApplicationCon
6476
protected override handleOffline(): void {
6577
this.statusBar.setElement('connection-status', {
6678
alignment: StatusBarAlignment.LEFT,
67-
text: this.isRunning
79+
text: this.connectedPort
6880
? nls.localize('theia/core/offline', 'Offline')
6981
: '$(bolt) ' +
7082
nls.localize('theia/core/daemonOffline', 'CLI Daemon Offline'),
71-
tooltip: this.isRunning
83+
tooltip: this.connectedPort
7284
? nls.localize(
7385
'theia/core/cannotConnectBackend',
7486
'Cannot connect to the backend.'
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
export const ArduinoDaemonPath = '/services/arduino-daemon';
22
export const ArduinoDaemon = Symbol('ArduinoDaemon');
33
export interface ArduinoDaemon {
4-
isRunning(): Promise<boolean>;
4+
/**
5+
* Returns with a promise that resolves with the port
6+
* of the CLI daemon when it's up and running.
7+
*/
58
getPort(): Promise<string>;
9+
/**
10+
* Unlike `getPort` this method returns with a promise
11+
* that resolves to `undefined` when the daemon is not running.
12+
* Otherwise resolves to the CLI daemon port.
13+
*/
14+
tryGetPort(): Promise<string | undefined>;
615
}

arduino-ide-extension/src/common/protocol/config-service.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ export interface ConfigService {
99
getCliConfigFileUri(): Promise<string>;
1010
getConfiguration(): Promise<Config>;
1111
setConfiguration(config: Config): Promise<void>;
12-
isInDataDir(uri: string): Promise<boolean>;
13-
isInSketchDir(uri: string): Promise<boolean>;
1412
}
1513

1614
export interface Daemon {
@@ -115,10 +113,8 @@ export interface Config {
115113
readonly locale: string;
116114
readonly sketchDirUri: string;
117115
readonly dataDirUri: string;
118-
readonly downloadsDirUri: string;
119116
readonly additionalUrls: AdditionalUrls;
120117
readonly network: Network;
121-
readonly daemon: Daemon;
122118
}
123119
export namespace Config {
124120
export function sameAs(left: Config, right: Config): boolean {
@@ -135,7 +131,6 @@ export namespace Config {
135131
return (
136132
left.locale === right.locale &&
137133
left.dataDirUri === right.dataDirUri &&
138-
left.downloadsDirUri === right.downloadsDirUri &&
139134
left.sketchDirUri === right.sketchDirUri &&
140135
Network.sameAs(left.network, right.network)
141136
);

arduino-ide-extension/src/common/protocol/notification-service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99

1010
export interface NotificationServiceClient {
1111
notifyIndexUpdated(): void;
12-
notifyDaemonStarted(): void;
12+
notifyDaemonStarted(port: string): void;
1313
notifyDaemonStopped(): void;
1414
notifyConfigChanged(event: { config: Config | undefined }): void;
1515
notifyPlatformInstalled(event: { item: BoardsPackage }): void;

arduino-ide-extension/src/node/arduino-daemon-impl.ts

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,12 @@ export class ArduinoDaemonImpl
3232
protected readonly notificationService: NotificationServiceServer;
3333

3434
protected readonly toDispose = new DisposableCollection();
35-
protected readonly onDaemonStartedEmitter = new Emitter<void>();
35+
protected readonly onDaemonStartedEmitter = new Emitter<string>();
3636
protected readonly onDaemonStoppedEmitter = new Emitter<void>();
3737

3838
protected _running = false;
39-
protected _ready = new Deferred<void>();
39+
protected _port = new Deferred<string>();
4040
protected _execPath: string | undefined;
41-
protected _port: string;
4241

4342
// Backend application lifecycle.
4443

@@ -48,12 +47,15 @@ export class ArduinoDaemonImpl
4847

4948
// Daemon API
5049

51-
async isRunning(): Promise<boolean> {
52-
return Promise.resolve(this._running);
50+
async getPort(): Promise<string> {
51+
return this._port.promise;
5352
}
5453

55-
async getPort(): Promise<string> {
56-
return Promise.resolve(this._port);
54+
async tryGetPort(): Promise<string | undefined> {
55+
if (this._running) {
56+
return this._port.promise;
57+
}
58+
return undefined;
5759
}
5860

5961
async startDaemon(): Promise<void> {
@@ -62,7 +64,6 @@ export class ArduinoDaemonImpl
6264
const cliPath = await this.getExecPath();
6365
this.onData(`Starting daemon from ${cliPath}...`);
6466
const { daemon, port } = await this.spawnDaemonProcess();
65-
this._port = port;
6667
// Watchdog process for terminating the daemon process when the backend app terminates.
6768
spawn(
6869
process.execPath,
@@ -83,7 +84,7 @@ export class ArduinoDaemonImpl
8384
Disposable.create(() => daemon.kill()),
8485
Disposable.create(() => this.fireDaemonStopped()),
8586
]);
86-
this.fireDaemonStarted();
87+
this.fireDaemonStarted(port);
8788
this.onData('Daemon is running.');
8889
} catch (err) {
8990
this.onData('Failed to start the daemon.');
@@ -103,18 +104,14 @@ export class ArduinoDaemonImpl
103104
this.toDispose.dispose();
104105
}
105106

106-
get onDaemonStarted(): Event<void> {
107+
get onDaemonStarted(): Event<string> {
107108
return this.onDaemonStartedEmitter.event;
108109
}
109110

110111
get onDaemonStopped(): Event<void> {
111112
return this.onDaemonStoppedEmitter.event;
112113
}
113114

114-
get ready(): Promise<void> {
115-
return this._ready.promise;
116-
}
117-
118115
async getExecPath(): Promise<string> {
119116
if (this._execPath) {
120117
return this._execPath;
@@ -240,20 +237,20 @@ export class ArduinoDaemonImpl
240237
return ready.promise;
241238
}
242239

243-
protected fireDaemonStarted(): void {
240+
protected fireDaemonStarted(port: string): void {
244241
this._running = true;
245-
this._ready.resolve();
246-
this.onDaemonStartedEmitter.fire();
247-
this.notificationService.notifyDaemonStarted();
242+
this._port.resolve(port);
243+
this.onDaemonStartedEmitter.fire(port);
244+
this.notificationService.notifyDaemonStarted(port);
248245
}
249246

250247
protected fireDaemonStopped(): void {
251248
if (!this._running) {
252249
return;
253250
}
254251
this._running = false;
255-
this._ready.reject(); // Reject all pending.
256-
this._ready = new Deferred<void>();
252+
this._port.reject(); // Reject all pending.
253+
this._port = new Deferred<string>();
257254
this.onDaemonStoppedEmitter.fire();
258255
this.notificationService.notifyDaemonStopped();
259256
}

arduino-ide-extension/src/node/cli-config.ts

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,31 @@
11
import { RecursivePartial } from '@theia/core/lib/common/types';
2-
import { Daemon } from '../common/protocol/config-service';
2+
import { AdditionalUrls } from '../common/protocol';
33

44
export const CLI_CONFIG = 'arduino-cli.yaml';
55

66
export interface BoardManager {
7-
readonly additional_urls: Array<string>;
7+
readonly additional_urls: AdditionalUrls;
88
}
99
export namespace BoardManager {
1010
export function sameAs(
1111
left: RecursivePartial<BoardManager> | undefined,
1212
right: RecursivePartial<BoardManager> | undefined
1313
): boolean {
14-
const leftOrDefault = left || {};
15-
const rightOrDefault = right || {};
16-
const leftUrls = Array.from(new Set(leftOrDefault.additional_urls || []));
17-
const rightUrls = Array.from(new Set(rightOrDefault.additional_urls || []));
18-
if (leftUrls.length !== rightUrls.length) {
19-
return false;
20-
}
21-
return leftUrls.every((url) => rightUrls.indexOf(url) !== -1);
14+
const leftUrls = left?.additional_urls ?? [];
15+
const rightUrls = right?.additional_urls ?? [];
16+
return AdditionalUrls.sameAs(leftUrls, rightUrls);
2217
}
2318
}
2419

2520
export interface Directories {
2621
readonly data: string;
27-
readonly downloads: string;
2822
readonly user: string;
2923
}
3024
export namespace Directories {
3125
export function is(
3226
directories: RecursivePartial<Directories> | undefined
3327
): directories is Directories {
34-
return (
35-
!!directories &&
36-
!!directories.data &&
37-
!!directories.downloads &&
38-
!!directories.user
39-
);
28+
return !!directories && !!directories.data && !!directories.user;
4029
}
4130
export function sameAs(
4231
left: RecursivePartial<Directories> | undefined,
@@ -48,11 +37,7 @@ export namespace Directories {
4837
if (right === undefined) {
4938
return left === undefined;
5039
}
51-
return (
52-
left.data === right.data &&
53-
left.downloads === right.downloads &&
54-
left.user === right.user
55-
);
40+
return left.data === right.data && left.user === right.user;
5641
}
5742
}
5843

@@ -111,23 +96,19 @@ export interface CliConfig {
11196
// Bare minimum required CLI config.
11297
export interface DefaultCliConfig extends CliConfig {
11398
directories: Directories;
114-
daemon: Daemon;
11599
}
116100
export namespace DefaultCliConfig {
117101
export function is(
118102
config: RecursivePartial<DefaultCliConfig> | undefined
119103
): config is DefaultCliConfig {
120-
return (
121-
!!config && Directories.is(config.directories) && Daemon.is(config.daemon)
122-
);
104+
return !!config && Directories.is(config.directories);
123105
}
124106
export function sameAs(
125107
left: DefaultCliConfig,
126108
right: DefaultCliConfig
127109
): boolean {
128110
return (
129111
Directories.sameAs(left.directories, right.directories) &&
130-
Daemon.sameAs(left.daemon, right.daemon) &&
131112
BoardManager.sameAs(left.board_manager, right.board_manager) &&
132113
Logging.sameAs(left.logging, right.logging)
133114
);

0 commit comments

Comments
 (0)