fix monitor connection

This commit is contained in:
Alberto Iannaccone 2022-04-08 15:42:52 +02:00
parent fbe8fb421a
commit eff960bb7f
5 changed files with 737 additions and 643 deletions

View File

@ -1,17 +1,29 @@
import { Emitter, MessageService } from "@theia/core"; import { Emitter, MessageService } from '@theia/core';
import { inject, injectable } from "@theia/core/shared/inversify"; import { inject, injectable } from '@theia/core/shared/inversify';
import { Board, Port } from "../common/protocol"; import { Board, Port } from '../common/protocol';
import { Monitor, MonitorManagerProxyClient, MonitorManagerProxyFactory, MonitorSettings } from "../common/protocol/monitor-service"; import {
Monitor,
MonitorManagerProxyClient,
MonitorManagerProxyFactory,
MonitorSettings,
} from '../common/protocol/monitor-service';
@injectable() @injectable()
export class MonitorManagerProxyClientImpl implements MonitorManagerProxyClient { export class MonitorManagerProxyClientImpl
implements MonitorManagerProxyClient
{
// When pluggable monitor messages are received from the backend // When pluggable monitor messages are received from the backend
// this event is triggered. // this event is triggered.
// Ideally a frontend component is connected to this event // Ideally a frontend component is connected to this event
// to update the UI. // to update the UI.
protected readonly onMessagesReceivedEmitter = new Emitter<{ messages: string[] }>(); protected readonly onMessagesReceivedEmitter = new Emitter<{
messages: string[];
}>();
readonly onMessagesReceived = this.onMessagesReceivedEmitter.event; readonly onMessagesReceived = this.onMessagesReceivedEmitter.event;
protected readonly onWSConnectionChangedEmitter = new Emitter<boolean>();
readonly onWSConnectionChanged = this.onWSConnectionChangedEmitter.event;
// WebSocket used to handle pluggable monitor communication between // WebSocket used to handle pluggable monitor communication between
// frontend and backend. // frontend and backend.
private webSocket?: WebSocket; private webSocket?: WebSocket;
@ -28,9 +40,7 @@ export class MonitorManagerProxyClientImpl implements MonitorManagerProxyClient
// This is necessary to call the backend methods from the frontend // This is necessary to call the backend methods from the frontend
@inject(MonitorManagerProxyFactory) @inject(MonitorManagerProxyFactory)
protected server: MonitorManagerProxyFactory protected server: MonitorManagerProxyFactory
) { ) {}
}
/** /**
* Connects a localhost WebSocket using the specified port. * Connects a localhost WebSocket using the specified port.
@ -42,6 +52,7 @@ export class MonitorManagerProxyClientImpl implements MonitorManagerProxyClient
} }
try { try {
this.webSocket = new WebSocket(`ws://localhost:${addressPort}`); this.webSocket = new WebSocket(`ws://localhost:${addressPort}`);
this.onWSConnectionChangedEmitter.fire(true);
} catch { } catch {
this.messageService.error('Unable to connect to websocket'); this.messageService.error('Unable to connect to websocket');
return; return;
@ -50,7 +61,7 @@ export class MonitorManagerProxyClientImpl implements MonitorManagerProxyClient
this.webSocket.onmessage = (res) => { this.webSocket.onmessage = (res) => {
const messages = JSON.parse(res.data); const messages = JSON.parse(res.data);
this.onMessagesReceivedEmitter.fire({ messages }); this.onMessagesReceivedEmitter.fire({ messages });
} };
this.wsPort = addressPort; this.wsPort = addressPort;
} }
@ -61,6 +72,7 @@ export class MonitorManagerProxyClientImpl implements MonitorManagerProxyClient
try { try {
this.webSocket?.close(); this.webSocket?.close();
this.webSocket = undefined; this.webSocket = undefined;
this.onWSConnectionChangedEmitter.fire(false);
} catch { } catch {
this.messageService.error('Unable to close websocket'); this.messageService.error('Unable to close websocket');
} }
@ -70,7 +82,11 @@ export class MonitorManagerProxyClientImpl implements MonitorManagerProxyClient
return !!this.webSocket; return !!this.webSocket;
} }
async startMonitor(board: Board, port: Port, settings?: MonitorSettings): Promise<void> { async startMonitor(
board: Board,
port: Port,
settings?: MonitorSettings
): Promise<void> {
return this.server().startMonitor(board, port, settings); return this.server().startMonitor(board, port, settings);
} }
@ -83,10 +99,12 @@ export class MonitorManagerProxyClientImpl implements MonitorManagerProxyClient
return; return;
} }
this.webSocket.send(JSON.stringify({ this.webSocket.send(
JSON.stringify({
command: Monitor.Command.SEND_MESSAGE, command: Monitor.Command.SEND_MESSAGE,
data: message, data: message,
})); })
);
} }
changeSettings(settings: MonitorSettings): void { changeSettings(settings: MonitorSettings): void {
@ -94,10 +112,12 @@ export class MonitorManagerProxyClientImpl implements MonitorManagerProxyClient
return; return;
} }
this.webSocket.send(JSON.stringify({ this.webSocket.send(
JSON.stringify({
command: Monitor.Command.CHANGE_SETTINGS, command: Monitor.Command.CHANGE_SETTINGS,
// TODO: This might be wrong, verify if it works // TODO: This might be wrong, verify if it works
data: settings, data: settings,
})); })
);
} }
} }

View File

@ -5,6 +5,7 @@ import { isOSX } from '@theia/core/lib/common/os';
import { DisposableCollection, nls } from '@theia/core/lib/common'; import { DisposableCollection, nls } from '@theia/core/lib/common';
import { MonitorManagerProxyClient } from '../../../common/protocol'; import { MonitorManagerProxyClient } from '../../../common/protocol';
import { BoardsServiceProvider } from '../../boards/boards-service-provider'; import { BoardsServiceProvider } from '../../boards/boards-service-provider';
import { timeout } from '@theia/core/lib/common/promise-util';
export namespace SerialMonitorSendInput { export namespace SerialMonitorSendInput {
export interface Props { export interface Props {
@ -27,16 +28,33 @@ export class SerialMonitorSendInput extends React.Component<
constructor(props: Readonly<SerialMonitorSendInput.Props>) { constructor(props: Readonly<SerialMonitorSendInput.Props>) {
super(props); super(props);
this.state = { text: '', connected: false }; this.state = { text: '', connected: true };
this.onChange = this.onChange.bind(this); this.onChange = this.onChange.bind(this);
this.onSend = this.onSend.bind(this); this.onSend = this.onSend.bind(this);
this.onKeyDown = this.onKeyDown.bind(this); this.onKeyDown = this.onKeyDown.bind(this);
} }
componentDidMount(): void { componentDidMount(): void {
this.props.monitorManagerProxy.isWSConnected().then((connected) => { this.setState({ connected: true });
const checkWSConnection = new Promise<boolean>((resolve) => {
this.props.monitorManagerProxy.onWSConnectionChanged((connected) => {
this.setState({ connected }); this.setState({ connected });
resolve(true);
}); });
});
const checkWSTimeout = timeout(1000).then(() => false);
Promise.race<boolean>([checkWSConnection, checkWSTimeout]).then(
async (resolved) => {
if (!resolved) {
const connected =
await this.props.monitorManagerProxy.isWSConnected();
this.setState({ connected });
}
}
);
} }
componentWillUnmount(): void { componentWillUnmount(): void {
@ -49,7 +67,7 @@ export class SerialMonitorSendInput extends React.Component<
<input <input
ref={this.setRef} ref={this.setRef}
type="text" type="text"
className={`theia-input ${this.state.connected ? '' : 'warning'}`} className={`theia-input ${this.shouldShowWarning() ? 'warning' : ''}`}
placeholder={this.placeholder} placeholder={this.placeholder}
value={this.state.text} value={this.state.text}
onChange={this.onChange} onChange={this.onChange}
@ -58,16 +76,22 @@ export class SerialMonitorSendInput extends React.Component<
); );
} }
protected get placeholder(): string { protected shouldShowWarning(): boolean {
const board = this.props.boardsServiceProvider.boardsConfig.selectedBoard; const board = this.props.boardsServiceProvider.boardsConfig.selectedBoard;
const port = this.props.boardsServiceProvider.boardsConfig.selectedPort; const port = this.props.boardsServiceProvider.boardsConfig.selectedPort;
if (!this.state.connected || !board || !port) { return !this.state.connected || !board || !port;
}
protected get placeholder(): string {
if (this.shouldShowWarning()) {
return nls.localize( return nls.localize(
'arduino/serial/notConnected', 'arduino/serial/notConnected',
'Not connected. Select a board and a port to connect automatically.' 'Not connected. Select a board and a port to connect automatically.'
); );
} }
const board = this.props.boardsServiceProvider.boardsConfig.selectedBoard;
const port = this.props.boardsServiceProvider.boardsConfig.selectedPort;
return nls.localize( return nls.localize(
'arduino/serial/message', 'arduino/serial/message',
"Message ({0} + Enter to send message to '{1}' on '{2}')", "Message ({0} + Enter to send message to '{1}' on '{2}')",

View File

@ -1,4 +1,4 @@
import { Event, JsonRpcServer } from "@theia/core"; import { Event, JsonRpcServer } from '@theia/core';
import { Board, Port } from './boards-service'; import { Board, Port } from './boards-service';
export const MonitorManagerProxyFactory = Symbol('MonitorManagerProxyFactory'); export const MonitorManagerProxyFactory = Symbol('MonitorManagerProxyFactory');
@ -6,9 +6,18 @@ export type MonitorManagerProxyFactory = () => MonitorManagerProxy;
export const MonitorManagerProxyPath = '/services/monitor-manager-proxy'; export const MonitorManagerProxyPath = '/services/monitor-manager-proxy';
export const MonitorManagerProxy = Symbol('MonitorManagerProxy'); export const MonitorManagerProxy = Symbol('MonitorManagerProxy');
export interface MonitorManagerProxy extends JsonRpcServer<MonitorManagerProxyClient> { export interface MonitorManagerProxy
startMonitor(board: Board, port: Port, settings?: MonitorSettings): Promise<void>; extends JsonRpcServer<MonitorManagerProxyClient> {
changeMonitorSettings(board: Board, port: Port, settings: MonitorSettings): Promise<void>; startMonitor(
board: Board,
port: Port,
settings?: MonitorSettings
): Promise<void>;
changeMonitorSettings(
board: Board,
port: Port,
settings: MonitorSettings
): Promise<void>;
stopMonitor(board: Board, port: Port): Promise<void>; stopMonitor(board: Board, port: Port): Promise<void>;
getCurrentSettings(board: Board, port: Port): MonitorSettings; getCurrentSettings(board: Board, port: Port): MonitorSettings;
} }
@ -16,14 +25,19 @@ export interface MonitorManagerProxy extends JsonRpcServer<MonitorManagerProxyCl
export const MonitorManagerProxyClient = Symbol('MonitorManagerProxyClient'); export const MonitorManagerProxyClient = Symbol('MonitorManagerProxyClient');
export interface MonitorManagerProxyClient { export interface MonitorManagerProxyClient {
onMessagesReceived: Event<{ messages: string[] }>; onMessagesReceived: Event<{ messages: string[] }>;
onWSConnectionChanged: Event<boolean>;
connect(addressPort: number): void; connect(addressPort: number): void;
disconnect(): void; disconnect(): void;
getWebSocketPort(): number | undefined; getWebSocketPort(): number | undefined;
isWSConnected(): Promise<boolean>; isWSConnected(): Promise<boolean>;
startMonitor(board: Board, port: Port, settings?: MonitorSettings): Promise<void>; startMonitor(
board: Board,
port: Port,
settings?: MonitorSettings
): Promise<void>;
getCurrentSettings(board: Board, port: Port): MonitorSettings; getCurrentSettings(board: Board, port: Port): MonitorSettings;
send(message: string): void; send(message: string): void;
changeSettings(settings: MonitorSettings): void changeSettings(settings: MonitorSettings): void;
} }
export interface MonitorSetting { export interface MonitorSetting {
@ -48,9 +62,9 @@ export namespace Monitor {
} }
export type Message = { export type Message = {
command: Monitor.Command, command: Monitor.Command;
data: string; data: string;
} };
} }
export interface Status {} export interface Status {}

View File

@ -1,8 +1,8 @@
import { ILogger } from "@theia/core"; import { ILogger } from '@theia/core';
import { inject, injectable, named } from "@theia/core/shared/inversify"; import { inject, injectable, named } from '@theia/core/shared/inversify';
import { Board, Port, Status, MonitorSettings } from "../common/protocol"; import { Board, Port, Status, MonitorSettings } from '../common/protocol';
import { CoreClientAware } from "./core-client-provider"; import { CoreClientAware } from './core-client-provider';
import { MonitorService } from "./monitor-service"; import { MonitorService } from './monitor-service';
type MonitorID = string; type MonitorID = string;
@ -19,7 +19,7 @@ export class MonitorManager extends CoreClientAware {
constructor( constructor(
@inject(ILogger) @inject(ILogger)
@named(MonitorManagerName) @named(MonitorManagerName)
protected readonly logger: ILogger, protected readonly logger: ILogger
) { ) {
super(); super();
} }
@ -52,7 +52,7 @@ export class MonitorManager extends CoreClientAware {
const monitorID = this.monitorID(board, port); const monitorID = this.monitorID(board, port);
let monitor = this.monitorServices.get(monitorID); let monitor = this.monitorServices.get(monitorID);
if (!monitor) { if (!monitor) {
monitor = this.createMonitor(board, port) monitor = this.createMonitor(board, port);
} }
return await monitor.start(); return await monitor.start();
} }
@ -146,7 +146,7 @@ export class MonitorManager extends CoreClientAware {
const monitorID = this.monitorID(board, port); const monitorID = this.monitorID(board, port);
let monitor = this.monitorServices.get(monitorID); let monitor = this.monitorServices.get(monitorID);
if (!monitor) { if (!monitor) {
monitor = this.createMonitor(board, port) monitor = this.createMonitor(board, port);
monitor.changeSettings(settings); monitor.changeSettings(settings);
} }
} }
@ -180,12 +180,15 @@ export class MonitorManager extends CoreClientAware {
this.logger, this.logger,
board, board,
port, port,
this.coreClientProvider, this.coreClientProvider
); );
monitor.onDispose((() => { this.monitorServices.set(monitorID, monitor);
monitor.onDispose(
(() => {
this.monitorServices.delete(monitorID); this.monitorServices.delete(monitorID);
}).bind(this)); }).bind(this)
return monitor );
return monitor;
} }
/** /**

View File

@ -1,12 +1,25 @@
import { ClientDuplexStream } from "@grpc/grpc-js"; import { ClientDuplexStream } from '@grpc/grpc-js';
import { Disposable, Emitter, ILogger } from "@theia/core"; import { Disposable, Emitter, ILogger } from '@theia/core';
import { inject, named } from "@theia/core/shared/inversify"; import { inject, named } from '@theia/core/shared/inversify';
import { Board, Port, Status, MonitorSettings, Monitor } from "../common/protocol"; import {
import { EnumerateMonitorPortSettingsRequest, EnumerateMonitorPortSettingsResponse, MonitorPortConfiguration, MonitorPortSetting, MonitorRequest, MonitorResponse } from "./cli-protocol/cc/arduino/cli/commands/v1/monitor_pb"; Board,
import { CoreClientAware, CoreClientProvider } from "./core-client-provider"; Port,
import { WebSocketProvider } from "./web-socket/web-socket-provider"; Status,
import { Port as gRPCPort } from 'arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/port_pb' MonitorSettings,
import WebSocketProviderImpl from "./web-socket/web-socket-provider-impl"; Monitor,
} from '../common/protocol';
import {
EnumerateMonitorPortSettingsRequest,
EnumerateMonitorPortSettingsResponse,
MonitorPortConfiguration,
MonitorPortSetting,
MonitorRequest,
MonitorResponse,
} from './cli-protocol/cc/arduino/cli/commands/v1/monitor_pb';
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';
export const MonitorServiceName = 'monitor-service'; export const MonitorServiceName = 'monitor-service';
@ -37,7 +50,8 @@ export class MonitorService extends CoreClientAware implements Disposable {
protected readonly onDisposeEmitter = new Emitter<void>(); protected readonly onDisposeEmitter = new Emitter<void>();
readonly onDispose = this.onDisposeEmitter.event; readonly onDispose = this.onDisposeEmitter.event;
protected readonly webSocketProvider: WebSocketProvider = new WebSocketProviderImpl(); protected readonly webSocketProvider: WebSocketProvider =
new WebSocketProviderImpl();
constructor( constructor(
@inject(ILogger) @inject(ILogger)
@ -46,11 +60,12 @@ export class MonitorService extends CoreClientAware implements Disposable {
private readonly board: Board, private readonly board: Board,
private readonly port: Port, private readonly port: Port,
protected readonly coreClientProvider: CoreClientProvider, protected readonly coreClientProvider: CoreClientProvider
) { ) {
super(); super();
this.onWSClientsNumberChanged = this.webSocketProvider.onClientsNumberChanged(async (clients: number) => { this.onWSClientsNumberChanged =
this.webSocketProvider.onClientsNumberChanged(async (clients: number) => {
if (clients === 0) { if (clients === 0) {
// There are no more clients that want to receive // There are no more clients that want to receive
// data from this monitor, we can freely close // data from this monitor, we can freely close
@ -61,7 +76,7 @@ export class MonitorService extends CoreClientAware implements Disposable {
// Sets default settings for this monitor // Sets default settings for this monitor
this.portMonitorSettings(port.protocol, board.fqbn!).then( this.portMonitorSettings(port.protocol, board.fqbn!).then(
settings => this.settings = settings (settings) => (this.settings = settings)
); );
} }
@ -95,46 +110,55 @@ export class MonitorService extends CoreClientAware implements Disposable {
} }
if (!this.board?.fqbn || !this.port?.address || !this.port?.protocol) { if (!this.board?.fqbn || !this.port?.address || !this.port?.protocol) {
return Status.CONFIG_MISSING return Status.CONFIG_MISSING;
} }
this.logger.info("starting monitor"); this.logger.info('starting monitor');
await this.coreClientProvider.initialized; await this.coreClientProvider.initialized;
const coreClient = await this.coreClient(); const coreClient = await this.coreClient();
const { client, instance } = coreClient; const { client, instance } = coreClient;
this.duplex = client.monitor() this.duplex = client.monitor();
this.duplex this.duplex
.on('close', () => { .on('close', () => {
this.logger.info(`monitor to ${this.port?.address} using ${this.port?.protocol} closed by client`) this.logger.info(
`monitor to ${this.port?.address} using ${this.port?.protocol} closed by client`
);
}) })
.on('end', () => { .on('end', () => {
this.logger.info(`monitor to ${this.port?.address} using ${this.port?.protocol} closed by server`) this.logger.info(
`monitor to ${this.port?.address} using ${this.port?.protocol} closed by server`
);
}) })
.on('error', (err: Error) => { .on('error', (err: Error) => {
this.logger.error(err); this.logger.error(err);
// TODO // TODO
// this.theiaFEClient?.notifyError() // this.theiaFEClient?.notifyError()
}) })
.on('data', ((res: MonitorResponse) => { .on(
'data',
((res: MonitorResponse) => {
if (res.getError()) { if (res.getError()) {
// TODO: Maybe disconnect // TODO: Maybe disconnect
this.logger.error(res.getError()); this.logger.error(res.getError());
return; return;
} }
const data = res.getRxData() const data = res.getRxData();
const message = const message =
typeof data === 'string' ? data : new TextDecoder('utf8').decode(data); typeof data === 'string'
this.messages.push(...splitLines(message)) ? data
}).bind(this)); : new TextDecoder('utf8').decode(data);
this.messages.push(...splitLines(message));
}).bind(this)
);
const req = new MonitorRequest(); const req = new MonitorRequest();
req.setInstance(instance); req.setInstance(instance);
if (this.board?.fqbn) { if (this.board?.fqbn) {
req.setFqbn(this.board.fqbn) req.setFqbn(this.board.fqbn);
} }
if (this.port?.address && this.port?.protocol) { if (this.port?.address && this.port?.protocol) {
const port = new gRPCPort() const port = new gRPCPort();
port.setAddress(this.port.address); port.setAddress(this.port.address);
port.setProtocol(this.port.protocol); port.setProtocol(this.port.protocol);
req.setPort(port); req.setPort(port);
@ -146,30 +170,33 @@ export class MonitorService extends CoreClientAware implements Disposable {
s.setValue(this.settings[id].selectedValue); s.setValue(this.settings[id].selectedValue);
config.addSettings(s); config.addSettings(s);
} }
req.setPortConfiguration(config) req.setPortConfiguration(config);
const connect = new Promise<Status>(resolve => { const connect = new Promise<Status>((resolve) => {
if (this.duplex?.write(req)) { if (this.duplex?.write(req)) {
this.startMessagesHandlers(); this.startMessagesHandlers();
this.logger.info(`started monitor to ${this.port?.address} using ${this.port?.protocol}`) this.logger.info(
`started monitor to ${this.port?.address} using ${this.port?.protocol}`
);
resolve(Status.OK); resolve(Status.OK);
return; return;
} }
this.logger.warn(`failed starting monitor to ${this.port?.address} using ${this.port?.protocol}`) this.logger.warn(
`failed starting monitor to ${this.port?.address} using ${this.port?.protocol}`
);
resolve(Status.NOT_CONNECTED); resolve(Status.NOT_CONNECTED);
}); });
const connectTimeout = new Promise<Status>(resolve => { const connectTimeout = new Promise<Status>((resolve) => {
setTimeout(async () => { setTimeout(async () => {
this.logger.warn(`timeout starting monitor to ${this.port?.address} using ${this.port?.protocol}`) this.logger.warn(
`timeout starting monitor to ${this.port?.address} using ${this.port?.protocol}`
);
resolve(Status.NOT_CONNECTED); resolve(Status.NOT_CONNECTED);
}, 1000); }, 1000);
}); });
// Try opening a monitor connection with a timeout // Try opening a monitor connection with a timeout
return await Promise.race([ return await Promise.race([connect, connectTimeout]);
connect,
connectTimeout,
])
} }
/** /**
@ -181,27 +208,29 @@ export class MonitorService extends CoreClientAware implements Disposable {
* @returns * @returns
*/ */
async pause(): Promise<void> { async pause(): Promise<void> {
return new Promise(resolve => { return new Promise(async (resolve) => {
if (!this.duplex) { if (!this.duplex) {
this.logger.warn(`monitor to ${this.port?.address} using ${this.port?.protocol} already stopped`) this.logger.warn(
`monitor to ${this.port?.address} using ${this.port?.protocol} already stopped`
);
return resolve(); return resolve();
} }
// It's enough to close the connection with the client // It's enough to close the connection with the client
// to stop the monitor process // to stop the monitor process
this.duplex.cancel(); this.duplex.end();
this.duplex = null; this.duplex = null;
this.logger.info(`stopped monitor to ${this.port?.address} using ${this.port?.protocol}`) this.logger.info(
`stopped monitor to ${this.port?.address} using ${this.port?.protocol}`
);
resolve(); resolve();
}) });
} }
/** /**
* Stop the monitor currently running * Stop the monitor currently running
*/ */
async stop(): Promise<void> { async stop(): Promise<void> {
return this.pause().finally( return this.pause().finally(this.stopMessagesHandlers.bind(this));
this.stopMessagesHandlers
);
} }
/** /**
@ -222,7 +251,7 @@ export class MonitorService extends CoreClientAware implements Disposable {
const req = new MonitorRequest(); const req = new MonitorRequest();
req.setInstance(instance); req.setInstance(instance);
req.setTxData(new TextEncoder().encode(message)); req.setTxData(new TextEncoder().encode(message));
return new Promise<Status>(resolve => { return new Promise<Status>((resolve) => {
if (this.duplex) { if (this.duplex) {
this.duplex?.write(req, () => { this.duplex?.write(req, () => {
resolve(Status.OK); resolve(Status.OK);
@ -230,7 +259,7 @@ export class MonitorService extends CoreClientAware implements Disposable {
return; return;
} }
this.stop().then(() => resolve(Status.NOT_CONNECTED)); this.stop().then(() => resolve(Status.NOT_CONNECTED));
}) });
} }
/** /**
@ -248,7 +277,10 @@ export class MonitorService extends CoreClientAware implements Disposable {
* @param fqbn the fqbn of the board we want to monitor * @param fqbn the fqbn of the board we want to monitor
* @returns a map of all the settings supported by the monitor * @returns a map of all the settings supported by the monitor
*/ */
private async portMonitorSettings(protocol: string, fqbn: string): Promise<MonitorSettings> { private async portMonitorSettings(
protocol: string,
fqbn: string
): Promise<MonitorSettings> {
await this.coreClientProvider.initialized; await this.coreClientProvider.initialized;
const coreClient = await this.coreClient(); const coreClient = await this.coreClient();
const { client, instance } = coreClient; const { client, instance } = coreClient;
@ -257,24 +289,26 @@ export class MonitorService extends CoreClientAware implements Disposable {
req.setPortProtocol(protocol); req.setPortProtocol(protocol);
req.setFqbn(fqbn); req.setFqbn(fqbn);
const res = await new Promise<EnumerateMonitorPortSettingsResponse>((resolve, reject) => { const res = await new Promise<EnumerateMonitorPortSettingsResponse>(
(resolve, reject) => {
client.enumerateMonitorPortSettings(req, (err, resp) => { client.enumerateMonitorPortSettings(req, (err, resp) => {
if (!!err) { if (!!err) {
reject(err) reject(err);
} }
resolve(resp) resolve(resp);
})
}); });
}
);
let settings: MonitorSettings = {}; const settings: MonitorSettings = {};
for (const iterator of res.getSettingsList()) { for (const iterator of res.getSettingsList()) {
settings[iterator.getSettingId()] = { settings[iterator.getSettingId()] = {
'id': iterator.getSettingId(), id: iterator.getSettingId(),
'label': iterator.getLabel(), label: iterator.getLabel(),
'type': iterator.getType(), type: iterator.getType(),
'values': iterator.getEnumValuesList(), values: iterator.getEnumValuesList(),
'selectedValue': iterator.getValue(), selectedValue: iterator.getValue(),
} };
} }
return settings; return settings;
} }
@ -306,9 +340,9 @@ export class MonitorService extends CoreClientAware implements Disposable {
const req = new MonitorRequest(); const req = new MonitorRequest();
req.setInstance(instance); req.setInstance(instance);
req.setPortConfiguration(config) req.setPortConfiguration(config);
this.duplex.write(req); this.duplex.write(req);
return Status.OK return Status.OK;
} }
/** /**
@ -334,14 +368,14 @@ export class MonitorService extends CoreClientAware implements Disposable {
switch (message.command) { switch (message.command) {
case Monitor.Command.SEND_MESSAGE: case Monitor.Command.SEND_MESSAGE:
this.send(message.data); this.send(message.data);
break break;
case Monitor.Command.CHANGE_SETTINGS: case Monitor.Command.CHANGE_SETTINGS:
const settings: MonitorSettings = JSON.parse(message.data); const settings: MonitorSettings = JSON.parse(message.data);
this.changeSettings(settings); this.changeSettings(settings);
break break;
} }
} }
) );
} }
} }
@ -359,7 +393,6 @@ export class MonitorService extends CoreClientAware implements Disposable {
this.onMessageReceived = undefined; this.onMessageReceived = undefined;
} }
} }
} }
/** /**