Skip to content

Commit bf958fd

Browse files
silvanocerzaAlberto Iannaccone
authored and
Alberto Iannaccone
committed
Proxied more monitor methods to frontend
1 parent ee265ae commit bf958fd

File tree

4 files changed

+155
-40
lines changed

4 files changed

+155
-40
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,103 @@
1-
import { Emitter } from "@theia/core";
2-
import { injectable } from "@theia/core/shared/inversify";
3-
import { MonitorManagerProxyClient } from "../common/protocol/monitor-service";
1+
import { Emitter, JsonRpcProxy, MessageService } from "@theia/core";
2+
import { inject, injectable } from "@theia/core/shared/inversify";
3+
import { Board, Port } from "../common/protocol";
4+
import { Monitor, MonitorManagerProxy, MonitorManagerProxyClient, MonitorSettings } from "../common/protocol/monitor-service";
45

56
@injectable()
67
export class MonitorManagerProxyClientImpl implements MonitorManagerProxyClient {
7-
protected readonly onWebSocketChangedEmitter = new Emitter<number>();
8-
readonly onWebSocketChanged = this.onWebSocketChangedEmitter.event;
8+
// When pluggable monitor messages are received from the backend
9+
// this event is triggered.
10+
// Ideally a frontend component is connected to this event
11+
// to update the UI.
12+
protected readonly onMessagesReceivedEmitter = new Emitter<{ messages: string[] }>();
13+
readonly onMessagesReceived = this.onMessagesReceivedEmitter.event;
914

10-
notifyWebSocketChanged(message: number): void {
11-
this.onWebSocketChangedEmitter.fire(message);
15+
// WebSocket used to handle pluggable monitor communication between
16+
// frontend and backend.
17+
private webSocket?: WebSocket;
18+
private wsPort?: number;
19+
20+
getWebSocketPort(): number | undefined {
21+
return this.wsPort;
22+
}
23+
24+
constructor(
25+
@inject(MessageService)
26+
protected messageService: MessageService,
27+
28+
// This is necessary to call the backend methods from the frontend
29+
@inject(MonitorManagerProxy)
30+
protected server: JsonRpcProxy<MonitorManagerProxy>
31+
) {
32+
33+
}
34+
35+
/**
36+
* Connects a localhost WebSocket using the specified port.
37+
* @param addressPort port of the WebSocket
38+
*/
39+
connect(addressPort: number): void {
40+
if (this.webSocket) {
41+
return;
42+
}
43+
try {
44+
this.webSocket = new WebSocket(`ws://localhost:${addressPort}`);
45+
} catch {
46+
this.messageService.error('Unable to connect to websocket');
47+
return;
48+
}
49+
50+
this.webSocket.onmessage = (res) => {
51+
const messages = JSON.parse(res.data);
52+
this.onMessagesReceivedEmitter.fire({ messages });
53+
}
54+
this.wsPort = addressPort;
55+
}
56+
57+
/**
58+
* Disconnects the WebSocket if connected.
59+
*/
60+
disconnect(): void {
61+
try {
62+
this.webSocket?.close();
63+
this.webSocket = undefined;
64+
} catch {
65+
this.messageService.error('Unable to close websocket');
66+
}
67+
}
68+
69+
async isWSConnected(): Promise<boolean> {
70+
return !!this.webSocket;
71+
}
72+
73+
async startMonitor(board: Board, port: Port, settings?: MonitorSettings): Promise<void> {
74+
return this.server.startMonitor(board, port, settings);
75+
}
76+
77+
getCurrentSettings(board: Board, port: Port): MonitorSettings {
78+
return this.server.getCurrentSettings(board, port);
79+
}
80+
81+
send(message: string): void {
82+
if (!this.webSocket) {
83+
return;
84+
}
85+
86+
this.webSocket.send(JSON.stringify({
87+
command: Monitor.Command.SEND_MESSAGE,
88+
data: message,
89+
}));
90+
}
91+
92+
changeSettings(settings: MonitorSettings): void {
93+
if (!this.webSocket) {
94+
return;
95+
}
96+
97+
this.webSocket.send(JSON.stringify({
98+
command: Monitor.Command.CHANGE_SETTINGS,
99+
// TODO: This might be wrong, verify if it works
100+
data: settings,
101+
}));
12102
}
13103
}

arduino-ide-extension/src/common/protocol/monitor-service.ts

+42-4
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,20 @@ export interface MonitorManagerProxy extends JsonRpcServer<MonitorManagerProxyCl
77
startMonitor(board: Board, port: Port, settings?: MonitorSettings): Promise<void>;
88
changeMonitorSettings(board: Board, port: Port, settings: MonitorSettings): Promise<void>;
99
stopMonitor(board: Board, port: Port): Promise<void>;
10-
getSupportedSettings(protocol: string, fqbn: string): Promise<MonitorSettings>;
10+
getCurrentSettings(board: Board, port: Port): MonitorSettings;
1111
}
1212

1313
export const MonitorManagerProxyClient = Symbol('MonitorManagerProxyClient');
1414
export interface MonitorManagerProxyClient {
15-
onWebSocketChanged: Event<number>;
16-
notifyWebSocketChanged(message: number): void;
15+
onMessagesReceived: Event<{ messages: string[] }>;
16+
connect(addressPort: number): void;
17+
disconnect(): void;
18+
getWebSocketPort(): number | undefined;
19+
isWSConnected(): Promise<boolean>;
20+
startMonitor(board: Board, port: Port, settings?: MonitorSettings): Promise<void>;
21+
getCurrentSettings(board: Board, port: Port): MonitorSettings;
22+
send(message: string): void;
23+
changeSettings(settings: MonitorSettings): void
1724
}
1825

1926
export interface MonitorSetting {
@@ -29,4 +36,35 @@ export interface MonitorSetting {
2936
selectedValue: string;
3037
}
3138

32-
export type MonitorSettings = Record<string, MonitorSetting>;
39+
export type MonitorSettings = Record<string, MonitorSetting>;
40+
41+
export namespace Monitor {
42+
export enum Command {
43+
SEND_MESSAGE = 'MONITOR_SEND_MESSAGE',
44+
CHANGE_SETTINGS = 'MONITOR_CHANGE_SETTINGS',
45+
}
46+
47+
export type Message = {
48+
command: Monitor.Command,
49+
data: string;
50+
}
51+
}
52+
53+
export interface Status { }
54+
export type OK = Status;
55+
export interface ErrorStatus extends Status {
56+
readonly message: string;
57+
}
58+
export namespace Status {
59+
export function isOK(status: Status & { message?: string }): status is OK {
60+
return !!status && typeof status.message !== 'string';
61+
}
62+
export const OK: OK = {};
63+
export const NOT_CONNECTED: ErrorStatus = { message: 'Not connected.' };
64+
export const ALREADY_CONNECTED: ErrorStatus = {
65+
message: 'Already connected.',
66+
};
67+
export const CONFIG_MISSING: ErrorStatus = {
68+
message: 'Serial Config missing.',
69+
};
70+
}

arduino-ide-extension/src/node/monitor-manager-proxy-impl.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export class MonitorManagerProxyImpl implements MonitorManagerProxy {
1919
}
2020

2121
dispose(): void {
22-
// NOOP
22+
this.client?.disconnect();
2323
}
2424

2525
/**
@@ -36,7 +36,8 @@ export class MonitorManagerProxyImpl implements MonitorManagerProxy {
3636
}
3737
const status = await this.manager.startMonitor(board, port);
3838
if (status === Status.ALREADY_CONNECTED || status === Status.OK) {
39-
this.client.notifyWebSocketChanged(this.manager.getWebsocketAddressPort(board, port));
39+
// Monitor started correctly, connect it with the frontend
40+
this.client.connect(this.manager.getWebsocketAddressPort(board, port));
4041
}
4142
}
4243

@@ -65,15 +66,14 @@ export class MonitorManagerProxyImpl implements MonitorManagerProxy {
6566
}
6667

6768
/**
68-
* Returns the settings supported by the pluggable monitor for the specified
69-
* protocol, the fqbn is necessary since it's used to tell different monitors
70-
* using the same protocol.
71-
* @param protocol protocol of a pluggable monitor
72-
* @param fqbn unique ID of a board
69+
* Returns the current settings by the pluggable monitor connected to specified
70+
* by board/port combination.
71+
* @param board board connected to port
72+
* @param port port monitored
7373
* @returns a map of MonitorSetting
7474
*/
75-
async getSupportedSettings(protocol: string, fqbn: string): Promise<MonitorSettings> {
76-
return this.manager.portMonitorSettings(protocol, fqbn);
75+
getCurrentSettings(board: Board, port: Port): MonitorSettings {
76+
return this.manager.currentMonitorSettings(board, port);
7777
}
7878

7979
setClient(client: MonitorManagerProxyClient | undefined): void {

arduino-ide-extension/src/node/monitor-service.ts

+7-20
Original file line numberDiff line numberDiff line change
@@ -321,29 +321,16 @@ export class MonitorService extends CoreClientAware implements Disposable {
321321
if (!this.onMessageReceived) {
322322
this.onMessageReceived = this.webSocketProvider.onMessageReceived(
323323
(msg: string) => {
324-
const message: SerialPlotter.Protocol.Message = JSON.parse(msg);
324+
const message: Monitor.Message = JSON.parse(msg);
325325

326326
switch (message.command) {
327-
case SerialPlotter.Protocol.Command.PLOTTER_SEND_MESSAGE:
327+
case Monitor.Command.SEND_MESSAGE:
328328
this.send(message.data);
329-
break;
330-
331-
case SerialPlotter.Protocol.Command.PLOTTER_SET_BAUDRATE:
332-
this.theiaFEClient?.notifyBaudRateChanged(
333-
parseInt(message.data, 10) as SerialConfig.BaudRate
334-
);
335-
break;
336-
337-
case SerialPlotter.Protocol.Command.PLOTTER_SET_LINE_ENDING:
338-
this.theiaFEClient?.notifyLineEndingChanged(message.data);
339-
break;
340-
341-
case SerialPlotter.Protocol.Command.PLOTTER_SET_INTERPOLATE:
342-
this.theiaFEClient?.notifyInterpolateChanged(message.data);
343-
break;
344-
345-
default:
346-
break;
329+
break
330+
case Monitor.Command.CHANGE_SETTINGS:
331+
const settings: MonitorSettings = JSON.parse(message.data);
332+
this.changeSettings(settings);
333+
break
347334
}
348335
}
349336
)

0 commit comments

Comments
 (0)