-
-
Notifications
You must be signed in to change notification settings - Fork 437
/
Copy pathmonitor-connection.ts
124 lines (106 loc) · 5.18 KB
/
monitor-connection.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { injectable, inject, postConstruct } from 'inversify';
import { Emitter, Event } from '@theia/core/lib/common/event';
// import { ConnectionStatusService } from '@theia/core/lib/browser/connection-status-service';
import { MessageService } from '@theia/core/lib/common/message-service';
import { MonitorService, MonitorConfig, MonitorError } from '../../common/protocol/monitor-service';
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
import { Port, Board } from '../../common/protocol/boards-service';
import { MonitorServiceClientImpl } from './monitor-service-client-impl';
@injectable()
export class MonitorConnection {
@inject(MonitorService)
protected readonly monitorService: MonitorService;
@inject(MonitorServiceClientImpl)
protected readonly monitorServiceClient: MonitorServiceClientImpl;
@inject(BoardsServiceClientImpl)
protected boardsServiceClient: BoardsServiceClientImpl;
@inject(MessageService)
protected messageService: MessageService;
// @inject(ConnectionStatusService)
// protected readonly connectionStatusService: ConnectionStatusService;
protected state: MonitorConnection.State | undefined;
protected readonly onConnectionChangedEmitter = new Emitter<string | undefined>();
readonly onConnectionChanged: Event<string | undefined> = this.onConnectionChangedEmitter.event;
@postConstruct()
protected init(): void {
this.monitorServiceClient.onError(async error => {
let shouldReconnect = false;
if (this.state) {
const { code, connectionId, config } = error;
if (this.state.connectionId === connectionId) {
switch (code) {
case MonitorError.ErrorCodes.CLIENT_CANCEL: {
console.debug(`Connection was canceled by client: ${MonitorConnection.State.toString(this.state)}.`);
break;
}
case MonitorError.ErrorCodes.DEVICE_BUSY: {
const { port } = config;
this.messageService.warn(`Connection failed. Serial port is busy: ${Port.toString(port)}.`);
break;
}
case MonitorError.ErrorCodes.DEVICE_NOT_CONFIGURED: {
const { port } = config;
this.messageService.info(`Disconnected from ${Port.toString(port)}.`);
break;
}
case MonitorError.ErrorCodes.interrupted_system_call: {
const { board, port } = config;
this.messageService.warn(`Unexpectedly interrupted by backend. Reconnecting ${Board.toString(board)} on port ${Port.toString(port)}.`);
shouldReconnect = true;
}
}
const oldState = this.state;
this.state = undefined;
if (shouldReconnect) {
await this.connect(oldState.config);
}
} else {
console.warn(`Received an error from unexpected connection: ${MonitorConnection.State.toString({ connectionId, config })}.`);
}
}
});
}
get connectionId(): string | undefined {
return this.state ? this.state.connectionId : undefined;
}
get connectionConfig(): MonitorConfig | undefined {
return this.state ? this.state.config : undefined;
}
async connect(config: MonitorConfig): Promise<string | undefined> {
if (this.state) {
throw new Error(`Already connected to ${MonitorConnection.State.toString(this.state)}.`);
}
const { connectionId } = await this.monitorService.connect(config);
this.state = { connectionId, config };
this.onConnectionChangedEmitter.fire(connectionId);
return connectionId;
}
async disconnect(): Promise<boolean> {
if (!this.state) {
throw new Error('Not connected. Nothing to disconnect.');
}
console.log('>>> Disposing existing monitor connection before establishing a new one...');
const result = await this.monitorService.disconnect(this.state.connectionId);
if (result) {
console.log(`<<< Disposed connection. Was: ${MonitorConnection.State.toString(this.state)}`);
this.state = undefined;
this.onConnectionChangedEmitter.fire(undefined);
} else {
console.warn(`<<< Could not dispose connection. Activate connection: ${MonitorConnection.State.toString(this.state)}`);
}
return result;
}
}
export namespace MonitorConnection {
export interface State {
readonly connectionId: string;
readonly config: MonitorConfig;
}
export namespace State {
export function toString(state: State): string {
const { connectionId, config } = state;
const { board, port } = config;
return `${Board.toString(board)} ${Port.toString(port)} [ID: ${connectionId}]`;
}
}
}