Skip to content

Commit e00f867

Browse files
author
Alberto Iannaccone
committed
fix clearConsole + refactor monitor connection
1 parent 1cac04d commit e00f867

File tree

7 files changed

+91
-79
lines changed

7 files changed

+91
-79
lines changed

Diff for: arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ import {
8181
} from '../common/protocol/config-service';
8282
import { MonitorWidget } from './monitor/monitor-widget';
8383
import { MonitorViewContribution } from './monitor/monitor-view-contribution';
84-
import { MonitorConnection } from './monitor/monitor-connection';
84+
import { SerialConnectionManager } from './monitor/monitor-connection';
8585
import { MonitorModel } from './monitor/monitor-model';
8686
import { TabBarDecoratorService as TheiaTabBarDecoratorService } from '@theia/core/lib/browser/shell/tab-bar-decorator';
8787
import { TabBarDecoratorService } from './theia/core/tab-bar-decorator';
@@ -409,7 +409,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
409409
return connection.createProxy(MonitorServicePath, client);
410410
})
411411
.inSingletonScope();
412-
bind(MonitorConnection).toSelf().inSingletonScope();
412+
bind(SerialConnectionManager).toSelf().inSingletonScope();
413413

414414
// Serial monitor service client to receive and delegate notifications from the backend.
415415
bind(MonitorServiceClient).to(MonitorServiceClientImpl).inSingletonScope();

Diff for: arduino-ide-extension/src/browser/contributions/burn-bootloader.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { OutputChannelManager } from '@theia/output/lib/common/output-channel';
33
import { CoreService } from '../../common/protocol';
44
import { ArduinoMenus } from '../menu/arduino-menus';
55
import { BoardsDataStore } from '../boards/boards-data-store';
6-
import { MonitorConnection } from '../monitor/monitor-connection';
6+
import { SerialConnectionManager } from '../monitor/monitor-connection';
77
import { BoardsServiceProvider } from '../boards/boards-service-provider';
88
import {
99
SketchContribution,
@@ -18,8 +18,8 @@ export class BurnBootloader extends SketchContribution {
1818
@inject(CoreService)
1919
protected readonly coreService: CoreService;
2020

21-
@inject(MonitorConnection)
22-
protected readonly monitorConnection: MonitorConnection;
21+
@inject(SerialConnectionManager)
22+
protected readonly monitorConnection: SerialConnectionManager;
2323

2424
@inject(BoardsDataStore)
2525
protected readonly boardsDataStore: BoardsDataStore;

Diff for: arduino-ide-extension/src/browser/contributions/upload-sketch.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { CoreService } from '../../common/protocol';
44
import { ArduinoMenus } from '../menu/arduino-menus';
55
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
66
import { BoardsDataStore } from '../boards/boards-data-store';
7-
import { MonitorConnection } from '../monitor/monitor-connection';
7+
import { SerialConnectionManager } from '../monitor/monitor-connection';
88
import { BoardsServiceProvider } from '../boards/boards-service-provider';
99
import {
1010
SketchContribution,
@@ -21,8 +21,8 @@ export class UploadSketch extends SketchContribution {
2121
@inject(CoreService)
2222
protected readonly coreService: CoreService;
2323

24-
@inject(MonitorConnection)
25-
protected readonly monitorConnection: MonitorConnection;
24+
@inject(SerialConnectionManager)
25+
protected readonly monitorConnection: SerialConnectionManager;
2626

2727
@inject(BoardsDataStore)
2828
protected readonly boardsDataStore: BoardsDataStore;

Diff for: arduino-ide-extension/src/browser/monitor/monitor-connection.ts

+71-57
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { injectable, inject, postConstruct } from 'inversify';
22
import { deepClone } from '@theia/core/lib/common/objects';
33
import { Emitter, Event } from '@theia/core/lib/common/event';
44
import { MessageService } from '@theia/core/lib/common/message-service';
5-
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
65
import {
76
MonitorService,
87
MonitorConfig,
@@ -23,13 +22,8 @@ import { NotificationCenter } from '../notification-center';
2322
import { ThemeService } from '@theia/core/lib/browser/theming';
2423
import { nls } from '@theia/core/lib/browser/nls';
2524

26-
export enum SerialType {
27-
Monitor = 'Monitor',
28-
Plotter = 'Plotter',
29-
}
30-
3125
@injectable()
32-
export class MonitorConnection {
26+
export class SerialConnectionManager {
3327
@inject(MonitorModel)
3428
protected readonly monitorModel: MonitorModel;
3529

@@ -51,26 +45,19 @@ export class MonitorConnection {
5145
@inject(MessageService)
5246
protected messageService: MessageService;
5347

54-
@inject(FrontendApplicationStateService)
55-
protected readonly applicationState: FrontendApplicationStateService;
56-
57-
@inject(MonitorModel)
58-
protected readonly model: MonitorModel;
59-
6048
@inject(ThemeService)
6149
protected readonly themeService: ThemeService;
62-
63-
protected _state: MonitorConnection.State = [];
50+
protected _state: Serial.State = [];
6451
protected _connected: boolean;
6552

6653
/**
6754
* Note: The idea is to toggle this property from the UI (`Monitor` view)
6855
* and the boards config and the boards attachment/detachment logic can be at on place, here.
6956
*/
70-
protected readonly onConnectionChangedEmitter =
71-
new Emitter<MonitorConnection.State>();
57+
protected readonly onConnectionChangedEmitter = new Emitter<boolean>();
58+
7259
/**
73-
* This emitter forwards all read events **iff** the connection is established.
60+
* This emitter forwards all read events **if** the connection is established.
7461
*/
7562
protected readonly onReadEmitter = new Emitter<{ messages: string[] }>();
7663

@@ -82,8 +69,13 @@ export class MonitorConnection {
8269
protected monitorErrors: MonitorError[] = [];
8370
protected reconnectTimeout?: number;
8471

72+
/**
73+
* When the websocket server is up on the backend, we save the port here, so that the client knows how to connect to it
74+
* */
8575
protected wsPort?: number;
76+
8677
protected webSocket?: WebSocket;
78+
8779
protected config: Partial<MonitorConfig> = {
8880
board: undefined,
8981
port: undefined,
@@ -117,15 +109,21 @@ export class MonitorConnection {
117109
});
118110
}
119111

112+
/**
113+
* Set the config passing only the properties that has changed. If some has changed and the serial is open,
114+
* we try to reconnect
115+
*
116+
* @param newConfig the porperties of the config that has changed
117+
*/
120118
protected setConfig(newConfig: Partial<MonitorConfig>): void {
121-
let shouldReconnect = false;
119+
let configHasChanged = false;
122120
Object.keys(this.config).forEach((key: keyof MonitorConfig) => {
123121
if (newConfig[key] && newConfig[key] !== this.config[key]) {
124-
shouldReconnect = true;
122+
configHasChanged = true;
125123
this.config = { ...this.config, [key]: newConfig[key] };
126124
}
127125
});
128-
if (shouldReconnect && this.isSerialOpen()) {
126+
if (configHasChanged && this.isSerialOpen()) {
129127
this.disconnect().then(() => this.connect());
130128
}
131129
}
@@ -134,10 +132,13 @@ export class MonitorConnection {
134132
return this.wsPort;
135133
}
136134

137-
handleWebSocketChanged(wsPort: number): void {
135+
protected handleWebSocketChanged(wsPort: number): void {
138136
this.wsPort = wsPort;
139137
}
140138

139+
/**
140+
* When the serial monitor is open and the frontend is connected to the serial, we create the websocket here
141+
*/
141142
protected createWsConnection(): boolean {
142143
if (this.wsPort) {
143144
try {
@@ -154,10 +155,17 @@ export class MonitorConnection {
154155
return false;
155156
}
156157

157-
protected async setState(s: MonitorConnection.State): Promise<Status> {
158+
/**
159+
* Sets the types of connections needed by the client.
160+
*
161+
* @param s The new types of connections (can be 'Monitor', 'Plotter', none or both).
162+
* If the previuos state was empty and 's' is not, it tries to reconnect to the serial service
163+
* If the provios state was NOT empty and now it is, it disconnects to the serial service
164+
* @returns The status of the operation
165+
*/
166+
protected async setState(s: Serial.State): Promise<Status> {
158167
const oldState = deepClone(this._state);
159168
this._state = s;
160-
this.onConnectionChangedEmitter.fire(this._state);
161169
let status = Status.OK;
162170

163171
if (this.isSerialOpen(oldState) && !this.isSerialOpen()) {
@@ -166,34 +174,14 @@ export class MonitorConnection {
166174
status = await this.connect();
167175
}
168176

169-
// if (this.connected) {
170-
// switch (this.state.connected) {
171-
// case SerialType.All:
172-
// return Status.OK;
173-
// case SerialType.Plotter:
174-
// if (type === SerialType.Monitor) {
175-
// if (this.createWsConnection()) {
176-
// this.state = { ...this.state, connected: SerialType.All };
177-
// return Status.OK;
178-
// }
179-
// return Status.NOT_CONNECTED;
180-
// }
181-
// return Status.OK;
182-
// case SerialType.Monitor:
183-
// if (type === SerialType.Plotter)
184-
// this.state = { ...this.state, connected: SerialType.All };
185-
// return SerialType.All;
186-
// }
187-
// }
188-
189177
return status;
190178
}
191179

192-
protected get state(): MonitorConnection.State {
180+
protected get state(): Serial.State {
193181
return this._state;
194182
}
195183

196-
isSerialOpen(state?: MonitorConnection.State): boolean {
184+
isSerialOpen(state?: Serial.State): boolean {
197185
return (state ? state : this._state).length > 0;
198186
}
199187

@@ -209,19 +197,32 @@ export class MonitorConnection {
209197

210198
set connected(c: boolean) {
211199
this._connected = c;
200+
this.onConnectionChangedEmitter.fire(this._connected);
212201
}
213-
214-
async openSerial(type: SerialType): Promise<Status> {
202+
/**
203+
* Called when a client opens the serial from the GUI
204+
*
205+
* @param type could be either 'Monitor' or 'Plotter'. If it's 'Monitor' we also connect to the websocket and
206+
* listen to the message events
207+
* @returns the status of the operation
208+
*/
209+
async openSerial(type: Serial.Type): Promise<Status> {
215210
if (this.state.includes(type)) return Status.OK;
216211
const newState = deepClone(this.state);
217212
newState.push(type);
218213
const status = await this.setState(newState);
219-
if (Status.isOK(status) && type === SerialType.Monitor)
214+
if (Status.isOK(status) && type === Serial.Type.Monitor)
220215
this.createWsConnection();
221216
return status;
222217
}
223218

224-
async closeSerial(type: SerialType): Promise<Status> {
219+
/**
220+
* Called when a client closes the serial from the GUI
221+
*
222+
* @param type could be either 'Monitor' or 'Plotter'. If it's 'Monitor' we close the websocket connection
223+
* @returns the status of the operation
224+
*/
225+
async closeSerial(type: Serial.Type): Promise<Status> {
225226
const index = this.state.indexOf(type);
226227
let status = Status.OK;
227228
if (index >= 0) {
@@ -230,7 +231,7 @@ export class MonitorConnection {
230231
status = await this.setState(newState);
231232
if (
232233
Status.isOK(status) &&
233-
type === SerialType.Monitor &&
234+
type === Serial.Type.Monitor &&
234235
this.webSocket
235236
) {
236237
this.webSocket.close();
@@ -240,6 +241,9 @@ export class MonitorConnection {
240241
return status;
241242
}
242243

244+
/**
245+
* Handles error on the MonitorServiceClient and try to reconnect, eventually
246+
*/
243247
handleError(error: MonitorError): void {
244248
if (!this.connected) return;
245249
const { code, config } = error;
@@ -248,7 +252,7 @@ export class MonitorConnection {
248252
switch (code) {
249253
case MonitorError.ErrorCodes.CLIENT_CANCEL: {
250254
console.debug(
251-
`Serial connection was canceled by client: ${MonitorConnection.Config.toString(
255+
`Serial connection was canceled by client: ${Serial.Config.toString(
252256
this.config
253257
)}.`
254258
);
@@ -394,14 +398,14 @@ export class MonitorConnection {
394398
if (Status.isOK(status)) {
395399
this.connected = false;
396400
console.log(
397-
`<<< Disposed serial connection. Was: ${MonitorConnection.Config.toString(
401+
`<<< Disposed serial connection. Was: ${Serial.Config.toString(
398402
this.config
399403
)}`
400404
);
401405
this.wsPort = undefined;
402406
} else {
403407
console.warn(
404-
`<<< Could not dispose serial connection. Activate connection: ${MonitorConnection.Config.toString(
408+
`<<< Could not dispose serial connection. Activate connection: ${Serial.Config.toString(
405409
this.config
406410
)}`
407411
);
@@ -426,7 +430,7 @@ export class MonitorConnection {
426430
});
427431
}
428432

429-
get onConnectionChanged(): Event<MonitorConnection.State> {
433+
get onConnectionChanged(): Event<boolean> {
430434
return this.onConnectionChangedEmitter.event;
431435
}
432436

@@ -459,8 +463,18 @@ export class MonitorConnection {
459463
}
460464
}
461465

462-
export namespace MonitorConnection {
463-
export type State = SerialType[];
466+
export namespace Serial {
467+
export enum Type {
468+
Monitor = 'Monitor',
469+
Plotter = 'Plotter',
470+
}
471+
472+
/**
473+
* The state represents which types of connections are needed by the client, and it should match whether the Serial Monitor
474+
* or the Serial Plotter are open or not in the GUI. It's an array cause it's possible to have both, none or only one of
475+
* them open
476+
*/
477+
export type State = Serial.Type[];
464478

465479
export namespace Config {
466480
export function toString(config: Partial<MonitorConfig>): string {

Diff for: arduino-ide-extension/src/browser/monitor/monitor-widget.tsx

+5-7
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { MonitorConfig } from '../../common/protocol/monitor-service';
1313
import { ArduinoSelect } from '../widgets/arduino-select';
1414
import { MonitorModel } from './monitor-model';
15-
import { MonitorConnection, SerialType } from './monitor-connection';
15+
import { Serial, SerialConnectionManager } from './monitor-connection';
1616
import { SerialMonitorSendInput } from './serial-monitor-send-input';
1717
import { SerialMonitorOutput } from './serial-monitor-send-output';
1818
import { nls } from '@theia/core/lib/browser/nls';
@@ -29,8 +29,8 @@ export class MonitorWidget extends ReactWidget {
2929
@inject(MonitorModel)
3030
protected readonly monitorModel: MonitorModel;
3131

32-
@inject(MonitorConnection)
33-
protected readonly monitorConnection: MonitorConnection;
32+
@inject(SerialConnectionManager)
33+
protected readonly monitorConnection: SerialConnectionManager;
3434

3535
@inject(BoardsServiceProvider)
3636
protected readonly boardsServiceProvider: BoardsServiceProvider;
@@ -58,7 +58,7 @@ export class MonitorWidget extends ReactWidget {
5858
this.toDispose.push(this.clearOutputEmitter);
5959
this.toDispose.push(
6060
Disposable.create(() =>
61-
this.monitorConnection.closeSerial(SerialType.Monitor)
61+
this.monitorConnection.closeSerial(Serial.Type.Monitor)
6262
)
6363
);
6464
}
@@ -82,9 +82,7 @@ export class MonitorWidget extends ReactWidget {
8282

8383
protected onAfterAttach(msg: Message): void {
8484
super.onAfterAttach(msg);
85-
// const { boardsConfig } = this.boardsServiceProvider;
86-
87-
this.monitorConnection.openSerial(SerialType.Monitor);
85+
this.monitorConnection.openSerial(Serial.Type.Monitor);
8886
}
8987

9088
onCloseRequest(msg: Message): void {

Diff for: arduino-ide-extension/src/browser/monitor/serial-monitor-send-output.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Event } from '@theia/core/lib/common/event';
33
import { DisposableCollection } from '@theia/core/lib/common/disposable';
44
import { areEqual, FixedSizeList as List } from 'react-window';
55
import { MonitorModel } from './monitor-model';
6-
import { MonitorConnection } from './monitor-connection';
6+
import { SerialConnectionManager } from './monitor-connection';
77
import dateFormat = require('dateformat');
88
import { messagesToLines, truncateLines } from './monitor-utils';
99

@@ -126,7 +126,7 @@ const Row = React.memo(_Row, areEqual);
126126
export namespace SerialMonitorOutput {
127127
export interface Props {
128128
readonly monitorModel: MonitorModel;
129-
readonly monitorConnection: MonitorConnection;
129+
readonly monitorConnection: SerialConnectionManager;
130130
readonly clearConsoleEvent: Event<void>;
131131
readonly height: number;
132132
}

0 commit comments

Comments
 (0)