Skip to content

Commit

Permalink
feat: use Arduino CLI 0.36.0-rc.1 APIs
Browse files Browse the repository at this point in the history
Signed-off-by: Akos Kitta <[email protected]>
  • Loading branch information
Akos Kitta authored and kittaakos committed Feb 20, 2024
1 parent 48e7bf6 commit 8e09971
Show file tree
Hide file tree
Showing 43 changed files with 5,530 additions and 3,268 deletions.
8 changes: 6 additions & 2 deletions arduino-ide-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,17 @@
],
"arduino": {
"arduino-cli": {
"version": "0.35.3"
"version": "0.36.0-rc.1"
},
"arduino-fwuploader": {
"version": "2.4.1"
},
"arduino-language-server": {
"version": "0.7.6"
"version": {
"owner": "arduino",
"repo": "arduino-language-server",
"commitish": "91c2ba8"
}
},
"clangd": {
"version": "14.0.0"
Expand Down
6 changes: 5 additions & 1 deletion arduino-ide-extension/scripts/generate-protocol.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
(async () => {
const os = require('node:os');
const path = require('node:path');
const { mkdirSync, promises: fs } = require('node:fs');
const { mkdirSync, promises: fs, rmSync } = require('node:fs');
const { exec } = require('./utils');
const glob = require('glob');
const { SemVer, gte, valid: validSemVer } = require('semver');
Expand Down Expand Up @@ -140,6 +140,10 @@

const rpc = path.join(repository, 'rpc');
const out = path.join(__dirname, '..', 'src', 'node', 'cli-protocol');
// Must wipe the gen output folder. Otherwise, dangling service implementation remain in IDE2 code,
// although it has been removed from the proto file.
// For example, https://github.com/arduino/arduino-cli/commit/50a8bf5c3e61d5b661ccfcd6a055e82eeb510859.
rmSync(out, { recursive: true, maxRetries: 5, force: true });
mkdirSync(out, { recursive: true });

const protos = await new Promise((resolve) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,7 @@ export class InoLanguage extends SketchContribution {
forceStart = false
): Promise<void> {
const port = await this.daemon.tryGetPort();
if (!port) {
return;
}
const portNumber = Number.parseInt(port, 10); // TODO: IDE2 APIs should provide a number and not string
if (Number.isNaN(portNumber)) {
if (typeof port !== 'number') {
return;
}
const release = await this.languageServerStartMutex.acquire();
Expand Down Expand Up @@ -280,7 +276,7 @@ export class InoLanguage extends SketchContribution {
lsPath,
daemonAddress: {
hostname: 'localhost',
port: portNumber,
port,
instance: 1, // TODO: get it from the backend
},
clangdPath,
Expand Down
4 changes: 2 additions & 2 deletions arduino-ide-extension/src/browser/notification-center.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class NotificationCenter
new Emitter<ProgressMessage>();
private readonly indexUpdateDidFailEmitter =
new Emitter<IndexUpdateDidFailParams>();
private readonly daemonDidStartEmitter = new Emitter<string>();
private readonly daemonDidStartEmitter = new Emitter<number>();
private readonly daemonDidStopEmitter = new Emitter<void>();
private readonly configDidChangeEmitter = new Emitter<ConfigState>();
private readonly platformDidInstallEmitter = new Emitter<{
Expand Down Expand Up @@ -136,7 +136,7 @@ export class NotificationCenter
this.indexUpdateDidFailEmitter.fire(params);
}

notifyDaemonDidStart(port: string): void {
notifyDaemonDidStart(port: number): void {
this.daemonDidStartEmitter.fire(port);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ export class DaemonPort implements FrontendApplicationContribution {
@inject(NotificationCenter)
private readonly notificationCenter: NotificationCenter;

private readonly onPortDidChangeEmitter = new Emitter<string | undefined>();
private _port: string | undefined;
private readonly onPortDidChangeEmitter = new Emitter<number | undefined>();
private _port: number | undefined;

onStart(): void {
this.daemon.tryGetPort().then(
Expand All @@ -91,15 +91,15 @@ export class DaemonPort implements FrontendApplicationContribution {
this.onPortDidChangeEmitter.dispose();
}

get port(): string | undefined {
get port(): number | undefined {
return this._port;
}

get onDidChangePort(): Event<string | undefined> {
get onDidChangePort(): Event<number | undefined> {
return this.onPortDidChangeEmitter.event;
}

private setPort(port: string | undefined): void {
private setPort(port: number | undefined): void {
const oldPort = this._port;
this._port = port;
if (this._port !== oldPort) {
Expand Down
8 changes: 4 additions & 4 deletions arduino-ide-extension/src/common/protocol/arduino-daemon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ export interface ArduinoDaemon {
* Returns with a promise that resolves with the port
* of the CLI daemon when it's up and running.
*/
getPort(): Promise<string>;
getPort(): Promise<number>;
/**
* Unlike `getPort` this method returns with a promise
* that resolves to `undefined` when the daemon is not running.
* Otherwise resolves to the CLI daemon port.
*/
tryGetPort(): Promise<string | undefined>;
start(): Promise<string>;
tryGetPort(): Promise<number | undefined>;
start(): Promise<number>;
stop(): Promise<void>;
restart(): Promise<string>;
restart(): Promise<number>;
}
3 changes: 3 additions & 0 deletions arduino-ide-extension/src/common/protocol/boards-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ export interface BoardsService
}): Promise<BoardsPackage | undefined>;
searchBoards({ query }: { query?: string }): Promise<BoardWithPackage[]>;
getInstalledBoards(): Promise<BoardWithPackage[]>;
/**
* Returns with all installed platforms including the manually installed ones.
*/
getInstalledPlatforms(): Promise<BoardsPackage[]>;
getBoardUserFields(options: {
fqbn: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export interface NotificationServiceClient {
notifyIndexUpdateDidFail(params: IndexUpdateDidFailParams): void;

// Daemon
notifyDaemonDidStart(port: string): void;
notifyDaemonDidStart(port: number): void;
notifyDaemonDidStop(): void;

// CLI config
Expand Down
53 changes: 53 additions & 0 deletions arduino-ide-extension/src/node/arduino-core-service-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { credentials, makeClientConstructor } from '@grpc/grpc-js';
import * as commandsGrpcPb from './cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb';
import { ArduinoCoreServiceClient } from './cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb';

export interface CreateClientOptions {
/**
* The port to the Arduino CLI daemon.
*/
readonly port: number;
/**
* Defaults to `'localhost'`.
*/
readonly host?: string;

/**
* gRCP channel options. Defaults to `createDefaultChannelOptions` with `'0.0.0'` `appVersion`
*/
readonly channelOptions?: Record<string, unknown>;
}

export function createDefaultChannelOptions(
appVersion = '0.0.0'
): Record<string, unknown> {
return {
'grpc.max_send_message_length': 512 * 1024 * 1024,
'grpc.max_receive_message_length': 512 * 1024 * 1024,
'grpc.primary_user_agent': `arduino-ide/${appVersion}`,
};
}

export function createArduinoCoreServiceClient(
options: CreateClientOptions
): ArduinoCoreServiceClient {
const {
port,
host = 'localhost',
channelOptions = createDefaultChannelOptions(),
} = options;
const address = `${host}:${port}`;
// https://github.com/agreatfool/grpc_tools_node_protoc_ts/blob/master/doc/grpcjs_support.md#usage
const ArduinoCoreServiceClient = makeClientConstructor(
// @ts-expect-error: ignore
commandsGrpcPb['cc.arduino.cli.commands.v1.ArduinoCoreService'],
'ArduinoCoreServiceService'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) as any;
const client = new ArduinoCoreServiceClient(
address,
credentials.createInsecure(),
channelOptions
) as ArduinoCoreServiceClient;
return client;
}
30 changes: 18 additions & 12 deletions arduino-ide-extension/src/node/arduino-daemon-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ export class ArduinoDaemonImpl
private readonly processUtils: ProcessUtils;

private readonly toDispose = new DisposableCollection();
private readonly onDaemonStartedEmitter = new Emitter<string>();
private readonly onDaemonStartedEmitter = new Emitter<number>();
private readonly onDaemonStoppedEmitter = new Emitter<void>();

private _running = false;
private _port = new Deferred<string>();
private _port = new Deferred<number>();

// Backend application lifecycle.

Expand All @@ -53,18 +53,18 @@ export class ArduinoDaemonImpl

// Daemon API

async getPort(): Promise<string> {
async getPort(): Promise<number> {
return this._port.promise;
}

async tryGetPort(): Promise<string | undefined> {
async tryGetPort(): Promise<number | undefined> {
if (this._running) {
return this._port.promise;
}
return undefined;
}

async start(): Promise<string> {
async start(): Promise<number> {
try {
this.toDispose.dispose(); // This will `kill` the previously started daemon process, if any.
const cliPath = this.getExecPath();
Expand Down Expand Up @@ -101,13 +101,13 @@ export class ArduinoDaemonImpl
this.toDispose.dispose();
}

async restart(): Promise<string> {
async restart(): Promise<number> {
return this.start();
}

// Backend only daemon API

get onDaemonStarted(): Event<string> {
get onDaemonStarted(): Event<number> {
return this.onDaemonStartedEmitter.event;
}

Expand Down Expand Up @@ -150,11 +150,11 @@ export class ArduinoDaemonImpl

protected async spawnDaemonProcess(): Promise<{
daemon: ChildProcess;
port: string;
port: number;
}> {
const args = await this.getSpawnArgs();
const cliPath = this.getExecPath();
const ready = new Deferred<{ daemon: ChildProcess; port: string }>();
const ready = new Deferred<{ daemon: ChildProcess; port: number }>();
const options = {
env: { ...deepClone(process.env), NO_COLOR: String(true) },
};
Expand Down Expand Up @@ -195,7 +195,13 @@ export class ArduinoDaemonImpl

if (port.length && address.length) {
grpcServerIsReady = true;
ready.resolve({ daemon, port });
const portNumber = Number.parseInt(port, 10);
if (Number.isNaN(portNumber)) {
ready.reject(
new Error(`Received a NaN port from the CLI: ${port}`)
);
}
ready.resolve({ daemon, port: portNumber });
}
}
});
Expand Down Expand Up @@ -225,7 +231,7 @@ export class ArduinoDaemonImpl
return ready.promise;
}

private fireDaemonStarted(port: string): void {
private fireDaemonStarted(port: number): void {
this._running = true;
this._port.resolve(port);
this.onDaemonStartedEmitter.fire(port);
Expand All @@ -238,7 +244,7 @@ export class ArduinoDaemonImpl
}
this._running = false;
this._port.reject(); // Reject all pending.
this._port = new Deferred<string>();
this._port = new Deferred<number>();
this.onDaemonStoppedEmitter.fire();
this.notificationService.notifyDaemonDidStop();
}
Expand Down
Loading

0 comments on commit 8e09971

Please sign in to comment.