diff --git a/arduino-ide-extension/src/browser/boards/boards-config.tsx b/arduino-ide-extension/src/browser/boards/boards-config.tsx index ce5d9eda1..e3d36fb68 100644 --- a/arduino-ide-extension/src/browser/boards/boards-config.tsx +++ b/arduino-ide-extension/src/browser/boards/boards-config.tsx @@ -354,7 +354,7 @@ export class BoardsConfig extends React.Component<
{ports.map((port) => ( - key={`${port.id}`} + key={`${Port.keyOf(port)}`} item={port} label={Port.toString(port)} selected={Port.sameAs(this.state.selectedPort, port)} diff --git a/arduino-ide-extension/src/browser/boards/boards-service-provider.ts b/arduino-ide-extension/src/browser/boards/boards-service-provider.ts index e84e91e56..872e7d44b 100644 --- a/arduino-ide-extension/src/browser/boards/boards-service-provider.ts +++ b/arduino-ide-extension/src/browser/boards/boards-service-provider.ts @@ -13,6 +13,7 @@ import { AttachedBoardsChangeEvent, BoardWithPackage, BoardUserField, + AvailablePorts, } from '../../common/protocol'; import { BoardsConfig } from './boards-config'; import { naturalCompare } from '../../common/utils'; @@ -21,6 +22,7 @@ import { StorageWrapper } from '../storage-wrapper'; import { nls } from '@theia/core/lib/common'; import { Deferred } from '@theia/core/lib/common/promise-util'; import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state'; +import { Unknown } from '../../common/nls'; @injectable() export class BoardsServiceProvider implements FrontendApplicationContribution { @@ -96,11 +98,12 @@ export class BoardsServiceProvider implements FrontendApplicationContribution { ); this.appStateService.reachedState('ready').then(async () => { - const [attachedBoards, availablePorts] = await Promise.all([ - this.boardsService.getAttachedBoards(), - this.boardsService.getAvailablePorts(), + const [state] = await Promise.all([ + this.boardsService.getState(), this.loadState(), ]); + const { boards: attachedBoards, ports: availablePorts } = + AvailablePorts.split(state); this._attachedBoards = attachedBoards; this._availablePorts = availablePorts; this.onAvailablePortsChangedEmitter.fire(this._availablePorts); @@ -459,6 +462,16 @@ export class BoardsServiceProvider implements FrontendApplicationContribution { return this._availableBoards; } + /** + * @deprecated Do not use this API, it will be removed. This is a hack to be able to set the missing port `properties` before an upload. + * + * See: https://github.com/arduino/arduino-ide/pull/1335#issuecomment-1224355236. + */ + // TODO: remove this API and fix the selected board config store/restore correctly. + get availablePorts(): Port[] { + return this._availablePorts.slice(); + } + async waitUntilAvailable( what: Board & { port: Port }, timeout?: number @@ -558,7 +571,7 @@ export class BoardsServiceProvider implements FrontendApplicationContribution { }; } else { availableBoard = { - name: nls.localize('arduino/common/unknown', 'Unknown'), + name: Unknown, port: boardPort, state: AvailableBoard.State.incomplete, }; diff --git a/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx b/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx index a1ddb7749..93a15a3c5 100644 --- a/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx +++ b/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx @@ -138,7 +138,7 @@ export class BoardsDropDown extends React.Component { {boardLabel}
- {port.address} + {port.addressLabel}
{selected ?
: ''} diff --git a/arduino-ide-extension/src/browser/contributions/board-selection.ts b/arduino-ide-extension/src/browser/contributions/board-selection.ts index 24527ca79..21acc221b 100644 --- a/arduino-ide-extension/src/browser/contributions/board-selection.ts +++ b/arduino-ide-extension/src/browser/contributions/board-selection.ts @@ -288,7 +288,7 @@ PID: ${PID}`; for (let i = 0; i < sortedIDs.length; i++) { const portID = sortedIDs[i]; const [port, boards] = ports[portID]; - let label = `${port.address}`; + let label = `${port.addressLabel}`; if (boards.length) { const boardsList = boards.map((board) => board.name).join(', '); label = `${label} (${boardsList})`; @@ -331,7 +331,7 @@ PID: ${PID}`; } }; - const grouped = AvailablePorts.byProtocol(availablePorts); + const grouped = AvailablePorts.groupByProtocol(availablePorts); let protocolOrder = 100; // We first show serial and network ports, then all the rest ['serial', 'network'].forEach((protocol) => { diff --git a/arduino-ide-extension/src/browser/contributions/upload-sketch.ts b/arduino-ide-extension/src/browser/contributions/upload-sketch.ts index d3278f0ec..606647219 100644 --- a/arduino-ide-extension/src/browser/contributions/upload-sketch.ts +++ b/arduino-ide-extension/src/browser/contributions/upload-sketch.ts @@ -1,6 +1,6 @@ import { inject, injectable } from '@theia/core/shared/inversify'; import { Emitter } from '@theia/core/lib/common/event'; -import { BoardUserField, CoreService } from '../../common/protocol'; +import { BoardUserField, CoreService, Port } from '../../common/protocol'; import { ArduinoMenus, PlaceholderMenuNode } from '../menu/arduino-menus'; import { ArduinoToolbar } from '../toolbar/arduino-toolbar'; import { @@ -12,7 +12,7 @@ import { CoreServiceContribution, } from './contribution'; import { UserFieldsDialog } from '../dialogs/user-fields/user-fields-dialog'; -import { DisposableCollection, nls } from '@theia/core/lib/common'; +import { deepClone, DisposableCollection, nls } from '@theia/core/lib/common'; import { CurrentSketch } from '../../common/protocol/sketches-service-client-impl'; import type { VerifySketchParams } from './verify-sketch'; @@ -266,7 +266,7 @@ export class UploadSketch extends CoreServiceContribution { this.preferences.get('arduino.upload.verify'), this.preferences.get('arduino.upload.verbose'), ]); - const port = boardsConfig.selectedPort; + const port = this.maybeUpdatePortProperties(boardsConfig.selectedPort); return { sketch, fqbn, @@ -278,7 +278,29 @@ export class UploadSketch extends CoreServiceContribution { }; } - private userFields() { + /** + * This is a hack to ensure that the port object has the `properties` when uploading.(https://github.com/arduino/arduino-ide/issues/740) + * This method works around a bug when restoring a `port` persisted by an older version of IDE2. See the bug [here](https://github.com/arduino/arduino-ide/pull/1335#issuecomment-1224355236). + * + * Before the upload, this method checks the available ports and makes sure that the `properties` of an available port, and the port selected by the user have the same `properties`. + * This method does not update any state (for example, the `BoardsConfig.Config`) but uses the correct `properties` for the `upload`. + */ + private maybeUpdatePortProperties(port: Port | undefined): Port | undefined { + if (port) { + const key = Port.keyOf(port); + for (const candidate of this.boardsServiceProvider.availablePorts) { + if (key === Port.keyOf(candidate) && candidate.properties) { + return { + ...port, + properties: deepClone(candidate.properties), + }; + } + } + } + return port; + } + + private userFields(): BoardUserField[] { return this.cachedUserFields.get(this.selectedFqbnAddress()) ?? []; } diff --git a/arduino-ide-extension/src/browser/monitor-manager-proxy-client-impl.ts b/arduino-ide-extension/src/browser/monitor-manager-proxy-client-impl.ts index 5519057aa..94ab4d0f5 100644 --- a/arduino-ide-extension/src/browser/monitor-manager-proxy-client-impl.ts +++ b/arduino-ide-extension/src/browser/monitor-manager-proxy-client-impl.ts @@ -145,7 +145,10 @@ export class MonitorManagerProxyClientImpl if ( selectedBoard?.fqbn !== this.lastConnectedBoard?.selectedBoard?.fqbn || - selectedPort?.id !== this.lastConnectedBoard?.selectedPort?.id + Port.keyOf(selectedPort) !== + (this.lastConnectedBoard.selectedPort + ? Port.keyOf(this.lastConnectedBoard.selectedPort) + : undefined) ) { this.onMonitorShouldResetEmitter.fire(null); this.lastConnectedBoard = { diff --git a/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-input.tsx b/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-input.tsx index 19f06eea1..180949726 100644 --- a/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-input.tsx +++ b/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-input.tsx @@ -5,6 +5,7 @@ import { isOSX } from '@theia/core/lib/common/os'; import { DisposableCollection, nls } from '@theia/core/lib/common'; import { BoardsServiceProvider } from '../../boards/boards-service-provider'; import { MonitorModel } from '../../monitor-model'; +import { Unknown } from '../../../common/nls'; export namespace SerialMonitorSendInput { export interface Props { @@ -86,8 +87,8 @@ export class SerialMonitorSendInput extends React.Component< ? Board.toString(board, { useFqbn: false, }) - : 'unknown', - port ? port.address : 'unknown' + : Unknown, + port ? port.address : Unknown ); } diff --git a/arduino-ide-extension/src/browser/widgets/component-list/list-item-renderer.tsx b/arduino-ide-extension/src/browser/widgets/component-list/list-item-renderer.tsx index b11ea2a8e..62e1f3e1c 100644 --- a/arduino-ide-extension/src/browser/widgets/component-list/list-item-renderer.tsx +++ b/arduino-ide-extension/src/browser/widgets/component-list/list-item-renderer.tsx @@ -5,6 +5,7 @@ import { Installable } from '../../../common/protocol/installable'; import { ArduinoComponent } from '../../../common/protocol/arduino-component'; import { ComponentListItem } from './component-list-item'; import { nls } from '@theia/core/lib/common'; +import { Unknown } from '../../../common/nls'; @injectable() export class ListItemRenderer { @@ -42,11 +43,7 @@ export class ListItemRenderer { } else if ((item as any).id) { nameAndAuthor = {(item as any).id}; } else { - nameAndAuthor = ( - - {nls.localize('arduino/common/unknown', 'Unknown')} - - ); + nameAndAuthor = {Unknown}; } const onClickUninstall = () => uninstall(item); const installedVersion = !!item.installedVersion && ( diff --git a/arduino-ide-extension/src/common/nls.ts b/arduino-ide-extension/src/common/nls.ts new file mode 100644 index 000000000..2435ff3b4 --- /dev/null +++ b/arduino-ide-extension/src/common/nls.ts @@ -0,0 +1,3 @@ +import { nls } from '@theia/core/lib/common/nls'; + +export const Unknown = nls.localize('arduino/common/unknown', 'Unknown'); diff --git a/arduino-ide-extension/src/common/protocol/boards-service.ts b/arduino-ide-extension/src/common/protocol/boards-service.ts index c21773cf2..6ff6e440f 100644 --- a/arduino-ide-extension/src/common/protocol/boards-service.ts +++ b/arduino-ide-extension/src/common/protocol/boards-service.ts @@ -5,7 +5,7 @@ import { ArduinoComponent } from './arduino-component'; export type AvailablePorts = Record]>; export namespace AvailablePorts { - export function byProtocol( + export function groupByProtocol( availablePorts: AvailablePorts ): Map { const grouped = new Map(); @@ -20,6 +20,21 @@ export namespace AvailablePorts { } return grouped; } + export function split( + state: AvailablePorts + ): Readonly<{ boards: Board[]; ports: Port[] }> { + const availablePorts: Port[] = []; + const attachedBoards: Board[] = []; + for (const key of Object.keys(state)) { + const [port, boards] = state[key]; + availablePorts.push(port); + attachedBoards.push(...boards); + } + return { + boards: attachedBoards, + ports: availablePorts, + }; + } } export interface AttachedBoardsChangeEvent { @@ -117,16 +132,6 @@ export const BoardsService = Symbol('BoardsService'); export interface BoardsService extends Installable, Searchable { - /** - * Deprecated. `getState` should be used to correctly map a board with a port. - * @deprecated - */ - getAttachedBoards(): Promise; - /** - * Deprecated. `getState` should be used to correctly map a board with a port. - * @deprecated - */ - getAvailablePorts(): Promise; getState(): Promise; getBoardDetails(options: { fqbn: string }): Promise; getBoardPackage(options: { id: string }): Promise; @@ -141,28 +146,55 @@ export interface BoardsService } export interface Port { - // id is the combination of address and protocol - // formatted like "
|" used - // to uniquely recognize a port - readonly id: string; readonly address: string; readonly addressLabel: string; readonly protocol: string; readonly protocolLabel: string; + readonly properties?: Record; } export namespace Port { - export function is(arg: any): arg is Port { - return ( - !!arg && - 'address' in arg && - typeof arg['address'] === 'string' && - 'protocol' in arg && - typeof arg['protocol'] === 'string' - ); + export type Properties = Record; + export namespace Properties { + export function create( + properties: [string, string][] | undefined + ): Properties { + if (!properties) { + return {}; + } + return properties.reduce((acc, curr) => { + const [key, value] = curr; + acc[key] = value; + return acc; + }, {} as Record); + } + } + export function is(arg: unknown): arg is Port { + if (typeof arg === 'object') { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const object = arg as any; + return ( + 'address' in object && + typeof object['address'] === 'string' && + 'addressLabel' in object && + typeof object['addressLabel'] === 'string' && + 'protocol' in object && + typeof object['protocol'] === 'string' && + 'protocolLabel' in object && + typeof object['protocolLabel'] === 'string' + ); + } + return false; + } + + /** + * Key is the combination of address and protocol formatted like `'${address}|${protocol}'` used to uniquely identify a port. + */ + export function keyOf({ address, protocol }: Port): string { + return `${address}|${protocol}`; } - export function toString(port: Port): string { - return `${port.addressLabel} ${port.protocolLabel}`; + export function toString({ addressLabel, protocolLabel }: Port): string { + return `${addressLabel} ${protocolLabel}`; } export function compare(left: Port, right: Port): number { diff --git a/arduino-ide-extension/src/node/auth/utils.ts b/arduino-ide-extension/src/node/auth/utils.ts index a7bc36110..f04e938b3 100644 --- a/arduino-ide-extension/src/node/auth/utils.ts +++ b/arduino-ide-extension/src/node/auth/utils.ts @@ -3,6 +3,7 @@ import { sha256 } from 'hash.js'; import { randomBytes } from 'crypto'; import btoa = require('btoa'); // TODO: check why we cannot import { AuthenticationSession } from './types'; +import { Unknown } from '../../common/nls'; export interface IToken { accessToken: string; // When unable to refresh due to network problems, the access token becomes undefined @@ -62,10 +63,10 @@ export function token2IToken(token: Token): IToken { sessionId: parsedIdToken.sub, scope: token.scope, account: { - id: parsedIdToken.sub || 'unknown', - email: parsedIdToken.email || 'unknown', - nickname: parsedIdToken.nickname || 'unknown', - picture: parsedIdToken.picture || 'unknown', + id: parsedIdToken.sub || Unknown, + email: parsedIdToken.email || Unknown, + nickname: parsedIdToken.nickname || Unknown, + picture: parsedIdToken.picture || Unknown, }, }; } diff --git a/arduino-ide-extension/src/node/board-discovery.ts b/arduino-ide-extension/src/node/board-discovery.ts index 65663ced2..4f4bf40ee 100644 --- a/arduino-ide-extension/src/node/board-discovery.ts +++ b/arduino-ide-extension/src/node/board-discovery.ts @@ -1,27 +1,30 @@ -import { injectable, inject, named } from '@theia/core/shared/inversify'; import { ClientDuplexStream } from '@grpc/grpc-js'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +import { Emitter, Event } from '@theia/core/lib/common/event'; import { ILogger } from '@theia/core/lib/common/logger'; import { deepClone } from '@theia/core/lib/common/objects'; -import { CoreClientAware } from './core-client-provider'; -import { - BoardListWatchRequest, - BoardListWatchResponse, -} from './cli-protocol/cc/arduino/cli/commands/v1/board_pb'; +import { Deferred } from '@theia/core/lib/common/promise-util'; +import { BackendApplicationContribution } from '@theia/core/lib/node'; +import { inject, injectable, named } from '@theia/core/shared/inversify'; +import { Disposable } from '@theia/core/shared/vscode-languageserver-protocol'; +import { v4 } from 'uuid'; +import { Unknown } from '../common/nls'; import { + AttachedBoardsChangeEvent, + AvailablePorts, Board, - Port, NotificationServiceServer, - AvailablePorts, - AttachedBoardsChangeEvent, + Port, } from '../common/protocol'; -import { Emitter, Event } from '@theia/core/lib/common/event'; -import { DisposableCollection } from '@theia/core/lib/common/disposable'; -import { Disposable } from '@theia/core/shared/vscode-languageserver-protocol'; +import { + BoardListWatchRequest, + BoardListWatchResponse, + DetectedPort as RpcDetectedPort, +} from './cli-protocol/cc/arduino/cli/commands/v1/board_pb'; import { ArduinoCoreServiceClient } from './cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb'; -import { v4 } from 'uuid'; +import { Port as RpcPort } from './cli-protocol/cc/arduino/cli/commands/v1/port_pb'; +import { CoreClientAware } from './core-client-provider'; import { ServiceError } from './service-error'; -import { BackendApplicationContribution } from '@theia/core/lib/node'; -import { Deferred } from '@theia/core/lib/common/promise-util'; type Duplex = ClientDuplexStream; interface StreamWrapper extends Disposable { @@ -125,8 +128,8 @@ export class BoardDiscovery }); } - setUploadInProgress(uploadAttemptInProgress: boolean): void { - this.uploadInProgress = uploadAttemptInProgress; + setUploadInProgress(uploadInProgress: boolean): void { + this.uploadInProgress = uploadInProgress; } private createTimeout( @@ -216,7 +219,7 @@ export class BoardDiscovery } else { throw new Error(`Unhandled object type: ${arg}`); } - return JSON.stringify(object); + return JSON.stringify(object, null, 2); // TODO: remove `space`? } async start(): Promise { @@ -234,103 +237,7 @@ export class BoardDiscovery this.logger.info('start new deferred'); const { client, instance } = await this.coreClient; const wrapper = await this.createWrapper(client); - wrapper.stream.on('data', async (resp: BoardListWatchResponse) => { - this.logger.info('onData', this.toJson(resp)); - if (resp.getEventType() === 'quit') { - this.logger.info('quit received'); - this.stop(); - return; - } - - const detectedPort = resp.getPort(); - if (detectedPort) { - let eventType: 'add' | 'remove' | 'unknown' = 'unknown'; - if (resp.getEventType() === 'add') { - eventType = 'add'; - } else if (resp.getEventType() === 'remove') { - eventType = 'remove'; - } else { - eventType = 'unknown'; - } - - if (eventType === 'unknown') { - throw new Error(`Unexpected event type: '${resp.getEventType()}'`); - } - - const oldState = deepClone(this._availablePorts); - const newState = deepClone(this._availablePorts); - - const address = (detectedPort as any).getPort().getAddress(); - const protocol = (detectedPort as any).getPort().getProtocol(); - // Different discoveries can detect the same port with different - // protocols, so we consider the combination of address and protocol - // to be the id of a certain port to distinguish it from others. - // If we'd use only the address of a port to store it in a map - // we can have conflicts the same port is found with multiple - // protocols. - const portID = `${address}|${protocol}`; - const label = (detectedPort as any).getPort().getLabel(); - const protocolLabel = (detectedPort as any) - .getPort() - .getProtocolLabel(); - const port = { - id: portID, - address, - addressLabel: label, - protocol, - protocolLabel, - }; - const boards: Board[] = []; - for (const item of detectedPort.getMatchingBoardsList()) { - boards.push({ - fqbn: item.getFqbn(), - name: item.getName() || 'unknown', - port, - }); - } - - if (eventType === 'add') { - if (newState[portID]) { - const [, knownBoards] = newState[portID]; - this.logger.warn( - `Port '${Port.toString( - port - )}' was already available. Known boards before override: ${JSON.stringify( - knownBoards - )}` - ); - } - newState[portID] = [port, boards]; - } else if (eventType === 'remove') { - if (!newState[portID]) { - this.logger.warn( - `Port '${Port.toString(port)}' was not available. Skipping` - ); - return; - } - delete newState[portID]; - } - - const oldAvailablePorts = this.getAvailablePorts(oldState); - const oldAttachedBoards = this.getAttachedBoards(oldState); - const newAvailablePorts = this.getAvailablePorts(newState); - const newAttachedBoards = this.getAttachedBoards(newState); - const event: AttachedBoardsChangeEvent = { - oldState: { - ports: oldAvailablePorts, - boards: oldAttachedBoards, - }, - newState: { - ports: newAvailablePorts, - boards: newAttachedBoards, - }, - uploadInProgress: this.uploadInProgress, - }; - - this._availablePorts = newState; - this.notificationService.notifyAttachedBoardsDidChange(event); - } - }); + wrapper.stream.on('data', (resp) => this.onBoardListWatchResponse(resp)); this.logger.info('start request start watch'); await this.requestStartWatch( new BoardListWatchRequest().setInstance(instance), @@ -341,21 +248,124 @@ export class BoardDiscovery this.logger.info('start resolved watching'); } - getAttachedBoards(state: AvailablePorts = this.availablePorts): Board[] { - const attachedBoards: Board[] = []; - for (const portID of Object.keys(state)) { - const [, boards] = state[portID]; - attachedBoards.push(...boards); + // XXX: make this `protected` and override for tests if IDE2 wants to mock events from the CLI. + private onBoardListWatchResponse(resp: BoardListWatchResponse): void { + this.logger.info(this.toJson(resp)); + const eventType = EventType.parse(resp.getEventType()); + + if (eventType === EventType.Quit) { + this.logger.info('quit received'); + this.stop(); + return; } - return attachedBoards; + + const detectedPort = resp.getPort(); + if (detectedPort) { + const { port, boards } = this.fromRpc(detectedPort); + if (!port) { + if (!!boards.length) { + console.warn( + `Could not detect the port, but unexpectedly received discovered boards. This is most likely a bug! Response was: ${this.toJson( + resp + )}` + ); + } + return; + } + const oldState = deepClone(this._availablePorts); + const newState = deepClone(this._availablePorts); + const key = Port.keyOf(port); + + if (eventType === EventType.Add) { + if (newState[key]) { + const [, knownBoards] = newState[key]; + this.logger.warn( + `Port '${Port.toString( + port + )}' was already available. Known boards before override: ${JSON.stringify( + knownBoards + )}` + ); + } + newState[key] = [port, boards]; + } else if (eventType === EventType.Remove) { + if (!newState[key]) { + this.logger.warn( + `Port '${Port.toString(port)}' was not available. Skipping` + ); + return; + } + delete newState[key]; + } + + const event: AttachedBoardsChangeEvent = { + oldState: { + ...AvailablePorts.split(oldState), + }, + newState: { + ...AvailablePorts.split(newState), + }, + uploadInProgress: this.uploadInProgress, + }; + + this._availablePorts = newState; + this.notificationService.notifyAttachedBoardsDidChange(event); + } + } + + private fromRpc(detectedPort: RpcDetectedPort): DetectedPort { + const rpcPort = detectedPort.getPort(); + const port = rpcPort && this.fromRpcPort(rpcPort); + const boards = detectedPort.getMatchingBoardsList().map( + (board) => + ({ + fqbn: board.getFqbn(), + name: board.getName() || Unknown, + port, + } as Board) + ); + return { + boards, + port, + }; } - getAvailablePorts(state: AvailablePorts = this.availablePorts): Port[] { - const availablePorts: Port[] = []; - for (const portID of Object.keys(state)) { - const [port] = state[portID]; - availablePorts.push(port); + private fromRpcPort(rpcPort: RpcPort): Port { + const port = { + address: rpcPort.getAddress(), + addressLabel: rpcPort.getLabel(), + protocol: rpcPort.getProtocol(), + protocolLabel: rpcPort.getProtocolLabel(), + properties: Port.Properties.create(rpcPort.getPropertiesMap().toObject()), + }; + return port; + } +} + +enum EventType { + Add, + Remove, + Quit, +} +namespace EventType { + export function parse(type: string): EventType { + const normalizedType = type.toLowerCase(); + switch (normalizedType) { + case 'add': + return EventType.Add; + case 'remove': + return EventType.Remove; + case 'quit': + return EventType.Quit; + default: + throw new Error( + `Unexpected 'BoardListWatchResponse' event type: '${type}.'` + ); } - return availablePorts; } } + +interface DetectedPort { + port: Port | undefined; + boards: Board[]; +} diff --git a/arduino-ide-extension/src/node/boards-service-impl.ts b/arduino-ide-extension/src/node/boards-service-impl.ts index ccad3147d..927a10e46 100644 --- a/arduino-ide-extension/src/node/boards-service-impl.ts +++ b/arduino-ide-extension/src/node/boards-service-impl.ts @@ -6,7 +6,6 @@ import { Installable, BoardsPackage, Board, - Port, BoardDetails, Tool, ConfigOption, @@ -65,14 +64,6 @@ export class BoardsServiceImpl return this.boardDiscovery.availablePorts; } - async getAttachedBoards(): Promise { - return this.boardDiscovery.getAttachedBoards(); - } - - async getAvailablePorts(): Promise { - return this.boardDiscovery.getAvailablePorts(); - } - async getBoardDetails(options: { fqbn: string; }): Promise { diff --git a/arduino-ide-extension/src/node/core-service-impl.ts b/arduino-ide-extension/src/node/core-service-impl.ts index c9997cea9..f438ca2e6 100644 --- a/arduino-ide-extension/src/node/core-service-impl.ts +++ b/arduino-ide-extension/src/node/core-service-impl.ts @@ -25,7 +25,7 @@ import { import { ResponseService } from '../common/protocol/response-service'; import { OutputMessage, Port, Status } from '../common/protocol'; import { ArduinoCoreServiceClient } from './cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb'; -import { Port as GrpcPort } from './cli-protocol/cc/arduino/cli/commands/v1/port_pb'; +import { Port as RpcPort } from './cli-protocol/cc/arduino/cli/commands/v1/port_pb'; import { ApplicationError, CommandService, Disposable, nls } from '@theia/core'; import { MonitorManager } from './monitor-manager'; import { AutoFlushingBuffer } from './utils/buffers'; @@ -411,15 +411,20 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService { } } - private createPort(port: Port | undefined): GrpcPort { - const grpcPort = new GrpcPort(); + private createPort(port: Port | undefined): RpcPort { + const rpcPort = new RpcPort(); if (port) { - grpcPort.setAddress(port.address); - grpcPort.setLabel(port.addressLabel); - grpcPort.setProtocol(port.protocol); - grpcPort.setProtocolLabel(port.protocolLabel); + rpcPort.setAddress(port.address); + rpcPort.setLabel(port.addressLabel); + rpcPort.setProtocol(port.protocol); + rpcPort.setProtocolLabel(port.protocolLabel); + if (port.properties) { + for (const [key, value] of Object.entries(port.properties)) { + rpcPort.getPropertiesMap().set(key, value); + } + } } - return grpcPort; + return rpcPort; } } type StreamingResponse = diff --git a/arduino-ide-extension/src/node/monitor-service.ts b/arduino-ide-extension/src/node/monitor-service.ts index b9d844225..62d126f7f 100644 --- a/arduino-ide-extension/src/node/monitor-service.ts +++ b/arduino-ide-extension/src/node/monitor-service.ts @@ -12,7 +12,7 @@ import { } from './cli-protocol/cc/arduino/cli/commands/v1/monitor_pb'; import { CoreClientAware } from './core-client-provider'; import { WebSocketProvider } from './web-socket/web-socket-provider'; -import { Port as gRPCPort } from 'arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/port_pb'; +import { Port as RpcPort } from 'arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/port_pb'; import { MonitorSettings, PluggableMonitorSettings, @@ -193,10 +193,10 @@ export class MonitorService extends CoreClientAware implements Disposable { monitorRequest.setFqbn(this.board.fqbn); } if (this.port?.address && this.port?.protocol) { - const port = new gRPCPort(); - port.setAddress(this.port.address); - port.setProtocol(this.port.protocol); - monitorRequest.setPort(port); + const rpcPort = new RpcPort(); + rpcPort.setAddress(this.port.address); + rpcPort.setProtocol(this.port.protocol); + monitorRequest.setPort(rpcPort); } const config = new MonitorPortConfiguration(); for (const id in this.settings.pluggableMonitorSettings) { diff --git a/arduino-ide-extension/src/test/browser/fixtures/boards.ts b/arduino-ide-extension/src/test/browser/fixtures/boards.ts index c00ded48a..d7ddc3126 100644 --- a/arduino-ide-extension/src/test/browser/fixtures/boards.ts +++ b/arduino-ide-extension/src/test/browser/fixtures/boards.ts @@ -5,7 +5,6 @@ export const aBoard: Board = { fqbn: 'some:board:fqbn', name: 'Some Arduino Board', port: { - id: '/lol/port1234|serial', address: '/lol/port1234', addressLabel: '/lol/port1234', protocol: 'serial', @@ -13,7 +12,6 @@ export const aBoard: Board = { }, }; export const aPort: Port = { - id: aBoard.port!.id, address: aBoard.port!.address, addressLabel: aBoard.port!.addressLabel, protocol: aBoard.port!.protocol, @@ -27,7 +25,6 @@ export const anotherBoard: Board = { fqbn: 'another:board:fqbn', name: 'Another Arduino Board', port: { - id: '/kek/port5678|serial', address: '/kek/port5678', addressLabel: '/kek/port5678', protocol: 'serial', @@ -35,7 +32,6 @@ export const anotherBoard: Board = { }, }; export const anotherPort: Port = { - id: anotherBoard.port!.id, address: anotherBoard.port!.address, addressLabel: anotherBoard.port!.addressLabel, protocol: anotherBoard.port!.protocol,