From 7bf4ea06375e1bb6d6974c52df84890d21a61128 Mon Sep 17 00:00:00 2001 From: Alberto Iannaccone Date: Tue, 17 May 2022 17:45:47 +0200 Subject: [PATCH] add MonitorSettingsProvider interface --- .../monitor-manager-proxy-client-impl.ts | 2 +- .../src/browser/monitor-model.ts | 225 +++++++++--------- .../browser/serial/monitor/monitor-widget.tsx | 6 +- .../plotter/plotter-frontend-contribution.ts | 2 +- .../src/common/protocol/monitor-service.ts | 3 +- .../src/node/monitor-manager-proxy-impl.ts | 146 ++++++------ .../src/node/monitor-manager.ts | 7 +- .../src/node/monitor-service.ts | 29 ++- .../monitor-settings-provider.ts | 14 ++ 9 files changed, 233 insertions(+), 201 deletions(-) create mode 100644 arduino-ide-extension/src/node/monitor-settings/monitor-settings-provider.ts 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 2a7b7cc9..acde1998 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 @@ -5,8 +5,8 @@ import { Monitor, MonitorManagerProxyClient, MonitorManagerProxyFactory, - MonitorSettings, } from '../common/protocol/monitor-service'; +import { MonitorSettings } from '../node/monitor-settings/monitor-settings-provider'; @injectable() export class MonitorManagerProxyClientImpl diff --git a/arduino-ide-extension/src/browser/monitor-model.ts b/arduino-ide-extension/src/browser/monitor-model.ts index 5082e98a..ccbd073c 100644 --- a/arduino-ide-extension/src/browser/monitor-model.ts +++ b/arduino-ide-extension/src/browser/monitor-model.ts @@ -1,134 +1,139 @@ -import { Emitter, Event } from "@theia/core"; -import { FrontendApplicationContribution, LocalStorageService } from "@theia/core/lib/browser"; -import { inject, injectable } from "@theia/core/shared/inversify"; +import { Emitter, Event } from '@theia/core'; +import { + FrontendApplicationContribution, + LocalStorageService, +} from '@theia/core/lib/browser'; +import { inject, injectable } from '@theia/core/shared/inversify'; @injectable() export class MonitorModel implements FrontendApplicationContribution { - protected static STORAGE_ID = 'arduino-monitor-model'; + protected static STORAGE_ID = 'arduino-monitor-model'; - @inject(LocalStorageService) - protected readonly localStorageService: LocalStorageService; + @inject(LocalStorageService) + protected readonly localStorageService: LocalStorageService; - protected readonly onChangeEmitter: Emitter>; + protected readonly onChangeEmitter: Emitter< + MonitorModel.State.Change + >; - protected _autoscroll: boolean; - protected _timestamp: boolean; - protected _lineEnding: MonitorModel.EOL; - protected _interpolate: boolean; + protected _autoscroll: boolean; + protected _timestamp: boolean; + protected _lineEnding: MonitorModel.EOL; + protected _interpolate: boolean; - constructor() { - this._autoscroll = true; - this._timestamp = false; - this._interpolate = false; - this._lineEnding = MonitorModel.EOL.DEFAULT; + constructor() { + this._autoscroll = true; + this._timestamp = false; + this._interpolate = false; + this._lineEnding = MonitorModel.EOL.DEFAULT; - this.onChangeEmitter = new Emitter< - MonitorModel.State.Change - >(); + this.onChangeEmitter = new Emitter< + MonitorModel.State.Change + >(); + } + + onStart(): void { + this.localStorageService + .getData(MonitorModel.STORAGE_ID) + .then(this.restoreState); + } + + get onChange(): Event> { + return this.onChangeEmitter.event; + } + + protected restoreState(state: MonitorModel.State): void { + if (!state) { + return; } + this._autoscroll = state.autoscroll; + this._timestamp = state.timestamp; + this._lineEnding = state.lineEnding; + this._interpolate = state.interpolate; + } - onStart(): void { - this.localStorageService - .getData(MonitorModel.STORAGE_ID) - .then(this.restoreState); - } + protected async storeState(): Promise { + return this.localStorageService.setData(MonitorModel.STORAGE_ID, { + autoscroll: this._autoscroll, + timestamp: this._timestamp, + lineEnding: this._lineEnding, + interpolate: this._interpolate, + }); + } - get onChange(): Event> { - return this.onChangeEmitter.event; - } + get autoscroll(): boolean { + return this._autoscroll; + } - protected restoreState(state: MonitorModel.State): void { - if (!state) { - return; - } - this._autoscroll = state.autoscroll; - this._timestamp = state.timestamp; - this._lineEnding = state.lineEnding; - this._interpolate = state.interpolate; - } + toggleAutoscroll(): void { + this._autoscroll = !this._autoscroll; + this.storeState().then(() => { + this.onChangeEmitter.fire({ + property: 'autoscroll', + value: this._timestamp, + }); + }); + } - protected async storeState(): Promise { - return this.localStorageService.setData(MonitorModel.STORAGE_ID, { - autoscroll: this._autoscroll, - timestamp: this._timestamp, - lineEnding: this._lineEnding, - interpolate: this._interpolate, - }); - } + get timestamp(): boolean { + return this._timestamp; + } - get autoscroll(): boolean { - return this._autoscroll; - } + toggleTimestamp(): void { + this._timestamp = !this._timestamp; + this.storeState().then(() => + this.onChangeEmitter.fire({ + property: 'timestamp', + value: this._timestamp, + }) + ); + } - toggleAutoscroll(): void { - this._autoscroll = !this._autoscroll; - this.storeState().then(() => { - this.onChangeEmitter.fire({ - property: 'autoscroll', - value: this._timestamp - }); - }); - } + get lineEnding(): MonitorModel.EOL { + return this._lineEnding; + } - get timestamp(): boolean { - return this._timestamp; - } + set lineEnding(lineEnding: MonitorModel.EOL) { + this._lineEnding = lineEnding; + this.storeState().then(() => + this.onChangeEmitter.fire({ + property: 'lineEnding', + value: this._lineEnding, + }) + ); + } - toggleTimestamp(): void { - this._timestamp = !this._timestamp; - this.storeState().then(() => - this.onChangeEmitter.fire({ - property: 'timestamp', - value: this._timestamp, - }) - ); - } + get interpolate(): boolean { + return this._interpolate; + } - get lineEnding(): MonitorModel.EOL { - return this._lineEnding; - } - - set lineEnding(lineEnding: MonitorModel.EOL) { - this._lineEnding = lineEnding; - this.storeState().then(() => - this.onChangeEmitter.fire({ - property: 'lineEnding', - value: this._lineEnding, - }) - ); - } - - get interpolate(): boolean { - return this._interpolate; - } - - set interpolate(i: boolean) { - this._interpolate = i; - this.storeState().then(() => - this.onChangeEmitter.fire({ - property: 'interpolate', - value: this._interpolate, - }) - ); - } + set interpolate(i: boolean) { + this._interpolate = i; + this.storeState().then(() => + this.onChangeEmitter.fire({ + property: 'interpolate', + value: this._interpolate, + }) + ); + } } export namespace MonitorModel { - export interface State { - autoscroll: boolean; - timestamp: boolean; - lineEnding: EOL; - interpolate: boolean; - } - export namespace State { - export interface Change { - readonly property: K; - readonly value: State[K]; - } + export interface State { + autoscroll: boolean; + timestamp: boolean; + lineEnding: EOL; + interpolate: boolean; + } + export namespace State { + export interface Change { + readonly property: K; + readonly value: State[K]; } + } - export type EOL = '' | '\n' | '\r' | '\r\n'; - export namespace EOL { - export const DEFAULT: EOL = '\n'; - } + export type EOL = '' | '\n' | '\r' | '\r\n'; + export namespace EOL { + export const DEFAULT: EOL = '\n'; + } } diff --git a/arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx b/arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx index 43f3a3b2..9d9a0830 100644 --- a/arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx +++ b/arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx @@ -14,11 +14,9 @@ import { SerialMonitorSendInput } from './serial-monitor-send-input'; import { SerialMonitorOutput } from './serial-monitor-send-output'; import { BoardsServiceProvider } from '../../boards/boards-service-provider'; import { nls } from '@theia/core/lib/common'; -import { - MonitorManagerProxyClient, - MonitorSettings, -} from '../../../common/protocol'; +import { MonitorManagerProxyClient } from '../../../common/protocol'; import { MonitorModel } from '../../monitor-model'; +import { MonitorSettings } from '../../../node/monitor-settings/monitor-settings-provider'; @injectable() export class MonitorWidget extends ReactWidget { diff --git a/arduino-ide-extension/src/browser/serial/plotter/plotter-frontend-contribution.ts b/arduino-ide-extension/src/browser/serial/plotter/plotter-frontend-contribution.ts index 3f22f207..1cc5e0f6 100644 --- a/arduino-ide-extension/src/browser/serial/plotter/plotter-frontend-contribution.ts +++ b/arduino-ide-extension/src/browser/serial/plotter/plotter-frontend-contribution.ts @@ -91,7 +91,7 @@ export class PlotterFrontendContribution extends Contribution { const settings = this.monitorManagerProxy.getCurrentSettings(board, port); if ('baudrate' in settings) { // Convert from string to numbers - baudrates = settings['baudrate'].values.map(b => +b); + baudrates = settings['baudrate'].values.map((b) => +b); currentBaudrate = +settings['baudrate'].selectedValue; } } diff --git a/arduino-ide-extension/src/common/protocol/monitor-service.ts b/arduino-ide-extension/src/common/protocol/monitor-service.ts index 765b7dc2..4cfb76a3 100644 --- a/arduino-ide-extension/src/common/protocol/monitor-service.ts +++ b/arduino-ide-extension/src/common/protocol/monitor-service.ts @@ -1,4 +1,5 @@ import { Event, JsonRpcServer } from '@theia/core'; +import { MonitorSettings } from '../../node/monitor-settings/monitor-settings-provider'; import { Board, Port } from './boards-service'; export const MonitorManagerProxyFactory = Symbol('MonitorManagerProxyFactory'); @@ -53,8 +54,6 @@ export interface MonitorSetting { selectedValue: string; } -export type MonitorSettings = Record; - export namespace Monitor { export enum Command { SEND_MESSAGE = 'MONITOR_SEND_MESSAGE', diff --git a/arduino-ide-extension/src/node/monitor-manager-proxy-impl.ts b/arduino-ide-extension/src/node/monitor-manager-proxy-impl.ts index e1fa1eef..9e78274b 100644 --- a/arduino-ide-extension/src/node/monitor-manager-proxy-impl.ts +++ b/arduino-ide-extension/src/node/monitor-manager-proxy-impl.ts @@ -1,80 +1,92 @@ -import { inject, injectable } from "@theia/core/shared/inversify"; -import { MonitorManagerProxy, MonitorManagerProxyClient, MonitorSettings, Status } from "../common/protocol"; -import { Board, Port } from "../common/protocol"; -import { MonitorManager } from "./monitor-manager"; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { + MonitorManagerProxy, + MonitorManagerProxyClient, + Status, +} from '../common/protocol'; +import { Board, Port } from '../common/protocol'; +import { MonitorManager } from './monitor-manager'; +import { MonitorSettings } from './monitor-settings/monitor-settings-provider'; @injectable() export class MonitorManagerProxyImpl implements MonitorManagerProxy { - protected client: MonitorManagerProxyClient; + protected client: MonitorManagerProxyClient; - constructor( - @inject(MonitorManager) - protected readonly manager: MonitorManager, - ) { - } + constructor( + @inject(MonitorManager) + protected readonly manager: MonitorManager + ) {} - dispose(): void { - this.client?.disconnect(); - } + dispose(): void { + this.client?.disconnect(); + } - /** - * Start a pluggable monitor and/or change its settings. - * If settings are defined they'll be set before starting the monitor, - * otherwise default ones will be used by the monitor. - * @param board board connected to port - * @param port port to monitor - * @param settings map of supported configuration by the monitor - */ - async startMonitor(board: Board, port: Port, settings?: MonitorSettings): Promise { - if (settings) { - await this.changeMonitorSettings(board, port, settings); - } - const status = await this.manager.startMonitor(board, port); - if (status === Status.ALREADY_CONNECTED || status === Status.OK) { - // Monitor started correctly, connect it with the frontend - this.client.connect(this.manager.getWebsocketAddressPort(board, port)); - } + /** + * Start a pluggable monitor and/or change its settings. + * If settings are defined they'll be set before starting the monitor, + * otherwise default ones will be used by the monitor. + * @param board board connected to port + * @param port port to monitor + * @param settings map of supported configuration by the monitor + */ + async startMonitor( + board: Board, + port: Port, + settings?: MonitorSettings + ): Promise { + if (settings) { + await this.changeMonitorSettings(board, port, settings); } + const status = await this.manager.startMonitor(board, port); + if (status === Status.ALREADY_CONNECTED || status === Status.OK) { + // Monitor started correctly, connect it with the frontend + this.client.connect(this.manager.getWebsocketAddressPort(board, port)); + } + } - /** - * Changes the settings of a running pluggable monitor, if that monitor is not - * started this function is a noop. - * @param board board connected to port - * @param port port monitored - * @param settings map of supported configuration by the monitor - */ - async changeMonitorSettings(board: Board, port: Port, settings: MonitorSettings): Promise { - if (!this.manager.isStarted(board, port)) { - // Monitor is not running, no need to change settings - return; - } - return this.manager.changeMonitorSettings(board, port, settings); + /** + * Changes the settings of a running pluggable monitor, if that monitor is not + * started this function is a noop. + * @param board board connected to port + * @param port port monitored + * @param settings map of supported configuration by the monitor + */ + async changeMonitorSettings( + board: Board, + port: Port, + settings: MonitorSettings + ): Promise { + if (!this.manager.isStarted(board, port)) { + // Monitor is not running, no need to change settings + return; } + return this.manager.changeMonitorSettings(board, port, settings); + } - /** - * Stops a running pluggable monitor. - * @param board board connected to port - * @param port port monitored - */ - async stopMonitor(board: Board, port: Port): Promise { - return this.manager.stopMonitor(board, port); - } + /** + * Stops a running pluggable monitor. + * @param board board connected to port + * @param port port monitored + */ + async stopMonitor(board: Board, port: Port): Promise { + return this.manager.stopMonitor(board, port); + } - /** - * Returns the current settings by the pluggable monitor connected to specified - * by board/port combination. - * @param board board connected to port - * @param port port monitored - * @returns a map of MonitorSetting - */ - getCurrentSettings(board: Board, port: Port): MonitorSettings { - return this.manager.currentMonitorSettings(board, port); - } + /** + * Returns the current settings by the pluggable monitor connected to specified + * by board/port combination. + * @param board board connected to port + * @param port port monitored + * @returns a map of MonitorSetting + */ + getCurrentSettings(board: Board, port: Port): MonitorSettings { + return this.manager.currentMonitorSettings(board, port); + } - setClient(client: MonitorManagerProxyClient | undefined): void { - if (!client) { - return; - } - this.client = client; + setClient(client: MonitorManagerProxyClient | undefined): void { + if (!client) { + return; } -} \ No newline at end of file + this.client = client; + } +} diff --git a/arduino-ide-extension/src/node/monitor-manager.ts b/arduino-ide-extension/src/node/monitor-manager.ts index e1370818..d4a56557 100644 --- a/arduino-ide-extension/src/node/monitor-manager.ts +++ b/arduino-ide-extension/src/node/monitor-manager.ts @@ -1,8 +1,9 @@ import { ILogger } from '@theia/core'; import { inject, injectable, named } from '@theia/core/shared/inversify'; -import { Board, Port, Status, MonitorSettings } from '../common/protocol'; +import { Board, Port, Status } from '../common/protocol'; import { CoreClientAware } from './core-client-provider'; import { MonitorService } from './monitor-service'; +import { MonitorSettings } from './monitor-settings/monitor-settings-provider'; type MonitorID = string; @@ -54,7 +55,7 @@ export class MonitorManager extends CoreClientAware { if (!monitor) { monitor = this.createMonitor(board, port); } - return await monitor.start(); + return await monitor.start(monitorID); } /** @@ -134,7 +135,7 @@ export class MonitorManager extends CoreClientAware { return Status.NOT_CONNECTED; } monitor.setUploadInProgress(false); - return await monitor.start(); + return await monitor.start(monitorID); } /** diff --git a/arduino-ide-extension/src/node/monitor-service.ts b/arduino-ide-extension/src/node/monitor-service.ts index 94b980b4..405fceaa 100644 --- a/arduino-ide-extension/src/node/monitor-service.ts +++ b/arduino-ide-extension/src/node/monitor-service.ts @@ -1,13 +1,7 @@ import { ClientDuplexStream } from '@grpc/grpc-js'; import { Disposable, Emitter, ILogger } from '@theia/core'; import { inject, named } from '@theia/core/shared/inversify'; -import { - Board, - Port, - Status, - MonitorSettings, - Monitor, -} from '../common/protocol'; +import { Board, Port, Status, Monitor } from '../common/protocol'; import { EnumerateMonitorPortSettingsRequest, EnumerateMonitorPortSettingsResponse, @@ -20,6 +14,10 @@ import { CoreClientAware, CoreClientProvider } 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 WebSocketProviderImpl from './web-socket/web-socket-provider-impl'; +import { + MonitorSettings, + MonitorSettingsProvider, +} from './monitor-settings/monitor-settings-provider'; export const MonitorServiceName = 'monitor-service'; @@ -50,6 +48,10 @@ export class MonitorService extends CoreClientAware implements Disposable { protected readonly onDisposeEmitter = new Emitter(); readonly onDispose = this.onDisposeEmitter.event; + @inject(MonitorSettingsProvider) + protected readonly monitorSettingsProvider: MonitorSettingsProvider; + + // TODO: use dependency injection protected readonly webSocketProvider: WebSocketProvider = new WebSocketProviderImpl(); @@ -75,11 +77,6 @@ export class MonitorService extends CoreClientAware implements Disposable { this.dispose(); } }); - - // Sets default settings for this monitor - this.portMonitorSettings(port.protocol, board.fqbn!).then( - (settings) => (this.settings = settings) - ); } setUploadInProgress(status: boolean): void { @@ -108,9 +105,10 @@ export class MonitorService extends CoreClientAware implements Disposable { * Start and connects a monitor using currently set board and port. * If a monitor is already started or board fqbn, port address and/or protocol * are missing nothing happens. + * @param id * @returns a status to verify connection has been established. */ - async start(): Promise { + async start(monitorID: string): Promise { if (this.duplex) { return Status.ALREADY_CONNECTED; } @@ -124,6 +122,10 @@ export class MonitorService extends CoreClientAware implements Disposable { } this.logger.info('starting monitor'); + this.settings = await this.monitorSettingsProvider.init( + monitorID, + this.coreClientProvider + ); await this.coreClientProvider.initialized; const coreClient = await this.coreClient(); const { client, instance } = coreClient; @@ -281,6 +283,7 @@ export class MonitorService extends CoreClientAware implements Disposable { return this.settings; } + // TODO: move this into MonitoSettingsProvider /** * Returns the possible configurations used to connect a monitor * to the board specified by fqbn using the specified protocol diff --git a/arduino-ide-extension/src/node/monitor-settings/monitor-settings-provider.ts b/arduino-ide-extension/src/node/monitor-settings/monitor-settings-provider.ts new file mode 100644 index 00000000..959ff1ad --- /dev/null +++ b/arduino-ide-extension/src/node/monitor-settings/monitor-settings-provider.ts @@ -0,0 +1,14 @@ +import { MonitorSetting } from '../../common/protocol'; +import { CoreClientProvider } from '../core-client-provider'; + +export type MonitorSettings = Record; + +export const MonitorSettingsProvider = Symbol('MonitorSettingsProvider'); +export interface MonitorSettingsProvider { + init( + id: string, + coreClientProvider: CoreClientProvider + ): Promise; + get(): Promise; + set(settings: MonitorSettings): Promise; +}