Proxied more monitor methods to frontend

This commit is contained in:
Silvano Cerza 2022-03-10 16:13:50 +01:00 committed by Alberto Iannaccone
parent ee265aec90
commit bf958fd8cf
4 changed files with 155 additions and 40 deletions

View File

@ -1,13 +1,103 @@
import { Emitter } from "@theia/core"; import { Emitter, JsonRpcProxy, MessageService } from "@theia/core";
import { injectable } from "@theia/core/shared/inversify"; import { inject, injectable } from "@theia/core/shared/inversify";
import { MonitorManagerProxyClient } from "../common/protocol/monitor-service"; import { Board, Port } from "../common/protocol";
import { Monitor, MonitorManagerProxy, MonitorManagerProxyClient, MonitorSettings } from "../common/protocol/monitor-service";
@injectable() @injectable()
export class MonitorManagerProxyClientImpl implements MonitorManagerProxyClient { export class MonitorManagerProxyClientImpl implements MonitorManagerProxyClient {
protected readonly onWebSocketChangedEmitter = new Emitter<number>(); // When pluggable monitor messages are received from the backend
readonly onWebSocketChanged = this.onWebSocketChangedEmitter.event; // this event is triggered.
// Ideally a frontend component is connected to this event
// to update the UI.
protected readonly onMessagesReceivedEmitter = new Emitter<{ messages: string[] }>();
readonly onMessagesReceived = this.onMessagesReceivedEmitter.event;
notifyWebSocketChanged(message: number): void { // WebSocket used to handle pluggable monitor communication between
this.onWebSocketChangedEmitter.fire(message); // frontend and backend.
private webSocket?: WebSocket;
private wsPort?: number;
getWebSocketPort(): number | undefined {
return this.wsPort;
}
constructor(
@inject(MessageService)
protected messageService: MessageService,
// This is necessary to call the backend methods from the frontend
@inject(MonitorManagerProxy)
protected server: JsonRpcProxy<MonitorManagerProxy>
) {
}
/**
* Connects a localhost WebSocket using the specified port.
* @param addressPort port of the WebSocket
*/
connect(addressPort: number): void {
if (this.webSocket) {
return;
}
try {
this.webSocket = new WebSocket(`ws://localhost:${addressPort}`);
} catch {
this.messageService.error('Unable to connect to websocket');
return;
}
this.webSocket.onmessage = (res) => {
const messages = JSON.parse(res.data);
this.onMessagesReceivedEmitter.fire({ messages });
}
this.wsPort = addressPort;
}
/**
* Disconnects the WebSocket if connected.
*/
disconnect(): void {
try {
this.webSocket?.close();
this.webSocket = undefined;
} catch {
this.messageService.error('Unable to close websocket');
}
}
async isWSConnected(): Promise<boolean> {
return !!this.webSocket;
}
async startMonitor(board: Board, port: Port, settings?: MonitorSettings): Promise<void> {
return this.server.startMonitor(board, port, settings);
}
getCurrentSettings(board: Board, port: Port): MonitorSettings {
return this.server.getCurrentSettings(board, port);
}
send(message: string): void {
if (!this.webSocket) {
return;
}
this.webSocket.send(JSON.stringify({
command: Monitor.Command.SEND_MESSAGE,
data: message,
}));
}
changeSettings(settings: MonitorSettings): void {
if (!this.webSocket) {
return;
}
this.webSocket.send(JSON.stringify({
command: Monitor.Command.CHANGE_SETTINGS,
// TODO: This might be wrong, verify if it works
data: settings,
}));
} }
} }

View File

@ -7,13 +7,20 @@ export interface MonitorManagerProxy extends JsonRpcServer<MonitorManagerProxyCl
startMonitor(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>; changeMonitorSettings(board: Board, port: Port, settings: MonitorSettings): Promise<void>;
stopMonitor(board: Board, port: Port): Promise<void>; stopMonitor(board: Board, port: Port): Promise<void>;
getSupportedSettings(protocol: string, fqbn: string): Promise<MonitorSettings>; getCurrentSettings(board: Board, port: Port): MonitorSettings;
} }
export const MonitorManagerProxyClient = Symbol('MonitorManagerProxyClient'); export const MonitorManagerProxyClient = Symbol('MonitorManagerProxyClient');
export interface MonitorManagerProxyClient { export interface MonitorManagerProxyClient {
onWebSocketChanged: Event<number>; onMessagesReceived: Event<{ messages: string[] }>;
notifyWebSocketChanged(message: number): void; connect(addressPort: number): void;
disconnect(): void;
getWebSocketPort(): number | undefined;
isWSConnected(): Promise<boolean>;
startMonitor(board: Board, port: Port, settings?: MonitorSettings): Promise<void>;
getCurrentSettings(board: Board, port: Port): MonitorSettings;
send(message: string): void;
changeSettings(settings: MonitorSettings): void
} }
export interface MonitorSetting { export interface MonitorSetting {
@ -29,4 +36,35 @@ export interface MonitorSetting {
selectedValue: string; selectedValue: string;
} }
export type MonitorSettings = Record<string, MonitorSetting>; export type MonitorSettings = Record<string, MonitorSetting>;
export namespace Monitor {
export enum Command {
SEND_MESSAGE = 'MONITOR_SEND_MESSAGE',
CHANGE_SETTINGS = 'MONITOR_CHANGE_SETTINGS',
}
export type Message = {
command: Monitor.Command,
data: string;
}
}
export interface Status { }
export type OK = Status;
export interface ErrorStatus extends Status {
readonly message: string;
}
export namespace Status {
export function isOK(status: Status & { message?: string }): status is OK {
return !!status && typeof status.message !== 'string';
}
export const OK: OK = {};
export const NOT_CONNECTED: ErrorStatus = { message: 'Not connected.' };
export const ALREADY_CONNECTED: ErrorStatus = {
message: 'Already connected.',
};
export const CONFIG_MISSING: ErrorStatus = {
message: 'Serial Config missing.',
};
}

View File

@ -19,7 +19,7 @@ export class MonitorManagerProxyImpl implements MonitorManagerProxy {
} }
dispose(): void { dispose(): void {
// NOOP this.client?.disconnect();
} }
/** /**
@ -36,7 +36,8 @@ export class MonitorManagerProxyImpl implements MonitorManagerProxy {
} }
const status = await this.manager.startMonitor(board, port); const status = await this.manager.startMonitor(board, port);
if (status === Status.ALREADY_CONNECTED || status === Status.OK) { if (status === Status.ALREADY_CONNECTED || status === Status.OK) {
this.client.notifyWebSocketChanged(this.manager.getWebsocketAddressPort(board, port)); // Monitor started correctly, connect it with the frontend
this.client.connect(this.manager.getWebsocketAddressPort(board, port));
} }
} }
@ -65,15 +66,14 @@ export class MonitorManagerProxyImpl implements MonitorManagerProxy {
} }
/** /**
* Returns the settings supported by the pluggable monitor for the specified * Returns the current settings by the pluggable monitor connected to specified
* protocol, the fqbn is necessary since it's used to tell different monitors * by board/port combination.
* using the same protocol. * @param board board connected to port
* @param protocol protocol of a pluggable monitor * @param port port monitored
* @param fqbn unique ID of a board
* @returns a map of MonitorSetting * @returns a map of MonitorSetting
*/ */
async getSupportedSettings(protocol: string, fqbn: string): Promise<MonitorSettings> { getCurrentSettings(board: Board, port: Port): MonitorSettings {
return this.manager.portMonitorSettings(protocol, fqbn); return this.manager.currentMonitorSettings(board, port);
} }
setClient(client: MonitorManagerProxyClient | undefined): void { setClient(client: MonitorManagerProxyClient | undefined): void {

View File

@ -321,29 +321,16 @@ export class MonitorService extends CoreClientAware implements Disposable {
if (!this.onMessageReceived) { if (!this.onMessageReceived) {
this.onMessageReceived = this.webSocketProvider.onMessageReceived( this.onMessageReceived = this.webSocketProvider.onMessageReceived(
(msg: string) => { (msg: string) => {
const message: SerialPlotter.Protocol.Message = JSON.parse(msg); const message: Monitor.Message = JSON.parse(msg);
switch (message.command) { switch (message.command) {
case SerialPlotter.Protocol.Command.PLOTTER_SEND_MESSAGE: case Monitor.Command.SEND_MESSAGE:
this.send(message.data); this.send(message.data);
break; break
case Monitor.Command.CHANGE_SETTINGS:
case SerialPlotter.Protocol.Command.PLOTTER_SET_BAUDRATE: const settings: MonitorSettings = JSON.parse(message.data);
this.theiaFEClient?.notifyBaudRateChanged( this.changeSettings(settings);
parseInt(message.data, 10) as SerialConfig.BaudRate break
);
break;
case SerialPlotter.Protocol.Command.PLOTTER_SET_LINE_ENDING:
this.theiaFEClient?.notifyLineEndingChanged(message.data);
break;
case SerialPlotter.Protocol.Command.PLOTTER_SET_INTERPOLATE:
this.theiaFEClient?.notifyInterpolateChanged(message.data);
break;
default:
break;
} }
} }
) )