mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-17 16:26:32 +00:00
Reconnect on interrupted system call
.
However, we have to figure out why does it happen at all. Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
parent
9efcbcf2ae
commit
eb7b3ad683
@ -32,13 +32,14 @@ export class MonitorConnection {
|
|||||||
|
|
||||||
@postConstruct()
|
@postConstruct()
|
||||||
protected init(): void {
|
protected init(): void {
|
||||||
this.monitorServiceClient.onError(error => {
|
this.monitorServiceClient.onError(async error => {
|
||||||
|
let shouldReconnect = false;
|
||||||
if (this.state) {
|
if (this.state) {
|
||||||
const { code, connectionId, config } = error;
|
const { code, connectionId, config } = error;
|
||||||
if (this.state.connectionId === connectionId) {
|
if (this.state.connectionId === connectionId) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case MonitorError.ErrorCodes.CLIENT_CANCEL: {
|
case MonitorError.ErrorCodes.CLIENT_CANCEL: {
|
||||||
console.log(`Connection was canceled by client: ${MonitorConnection.State.toString(this.state)}.`);
|
console.debug(`Connection was canceled by client: ${MonitorConnection.State.toString(this.state)}.`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MonitorError.ErrorCodes.DEVICE_BUSY: {
|
case MonitorError.ErrorCodes.DEVICE_BUSY: {
|
||||||
@ -51,8 +52,17 @@ export class MonitorConnection {
|
|||||||
this.messageService.info(`Disconnected from ${Port.toString(port)}.`);
|
this.messageService.info(`Disconnected from ${Port.toString(port)}.`);
|
||||||
break;
|
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;
|
this.state = undefined;
|
||||||
|
if (shouldReconnect) {
|
||||||
|
await this.connect(oldState.config);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn(`Received an error from unexpected connection: ${MonitorConnection.State.toString({ connectionId, config })}.`);
|
console.warn(`Received an error from unexpected connection: ${MonitorConnection.State.toString({ connectionId, config })}.`);
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,6 @@
|
|||||||
import { JsonRpcServer } from '@theia/core/lib/common/messaging/proxy-factory';
|
import { JsonRpcServer } from '@theia/core/lib/common/messaging/proxy-factory';
|
||||||
import { Board, Port } from './boards-service';
|
import { Board, Port } from './boards-service';
|
||||||
|
|
||||||
export interface MonitorError {
|
|
||||||
readonly connectionId: string;
|
|
||||||
readonly message: string;
|
|
||||||
readonly code: number;
|
|
||||||
readonly config: MonitorConfig;
|
|
||||||
}
|
|
||||||
export namespace MonitorError {
|
|
||||||
export namespace ErrorCodes {
|
|
||||||
/**
|
|
||||||
* The frontend has refreshed the browser, for instance.
|
|
||||||
*/
|
|
||||||
export const CLIENT_CANCEL = 1;
|
|
||||||
/**
|
|
||||||
* When detaching a physical device when the duplex channel is still opened.
|
|
||||||
*/
|
|
||||||
export const DEVICE_NOT_CONFIGURED = 2;
|
|
||||||
/**
|
|
||||||
* Another serial monitor was opened on this port. For another electron-instance, Java IDE.
|
|
||||||
*/
|
|
||||||
export const DEVICE_BUSY = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MonitorReadEvent {
|
|
||||||
readonly connectionId: string;
|
|
||||||
readonly data: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const MonitorServiceClient = Symbol('MonitorServiceClient');
|
|
||||||
export interface MonitorServiceClient {
|
|
||||||
notifyRead(event: MonitorReadEvent): void;
|
|
||||||
notifyError(event: MonitorError): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const MonitorServicePath = '/services/serial-monitor';
|
export const MonitorServicePath = '/services/serial-monitor';
|
||||||
export const MonitorService = Symbol('MonitorService');
|
export const MonitorService = Symbol('MonitorService');
|
||||||
export interface MonitorService extends JsonRpcServer<MonitorServiceClient> {
|
export interface MonitorService extends JsonRpcServer<MonitorServiceClient> {
|
||||||
@ -69,3 +35,40 @@ export namespace MonitorConfig {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const MonitorServiceClient = Symbol('MonitorServiceClient');
|
||||||
|
export interface MonitorServiceClient {
|
||||||
|
notifyRead(event: MonitorReadEvent): void;
|
||||||
|
notifyError(event: MonitorError): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MonitorReadEvent {
|
||||||
|
readonly connectionId: string;
|
||||||
|
readonly data: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MonitorError {
|
||||||
|
readonly connectionId: string;
|
||||||
|
readonly message: string;
|
||||||
|
readonly code: number;
|
||||||
|
readonly config: MonitorConfig;
|
||||||
|
}
|
||||||
|
export namespace MonitorError {
|
||||||
|
export namespace ErrorCodes {
|
||||||
|
/**
|
||||||
|
* The frontend has refreshed the browser, for instance.
|
||||||
|
*/
|
||||||
|
export const CLIENT_CANCEL = 1;
|
||||||
|
/**
|
||||||
|
* When detaching a physical device when the duplex channel is still opened.
|
||||||
|
*/
|
||||||
|
export const DEVICE_NOT_CONFIGURED = 2;
|
||||||
|
/**
|
||||||
|
* Another serial monitor was opened on this port. For another electron-instance, Java IDE.
|
||||||
|
*/
|
||||||
|
export const DEVICE_BUSY = 3;
|
||||||
|
/**
|
||||||
|
* Another serial monitor was opened on this port. For another electron-instance, Java IDE.
|
||||||
|
*/
|
||||||
|
export const interrupted_system_call = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -109,13 +109,14 @@ export class BoardsServiceImpl implements BoardsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
this.logger.info('>>> Disposing boards service...')
|
this.logger.info('>>> Disposing boards service...');
|
||||||
this.queue.pause();
|
this.queue.pause();
|
||||||
this.queue.clear();
|
this.queue.clear();
|
||||||
if (this.discoveryTimer !== undefined) {
|
if (this.discoveryTimer !== undefined) {
|
||||||
clearInterval(this.discoveryTimer);
|
clearInterval(this.discoveryTimer);
|
||||||
}
|
}
|
||||||
this.logger.info('<<< Disposed boards service.')
|
this.logger.info('<<< Disposed boards service.');
|
||||||
|
this.client = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAttachedBoards(): Promise<{ boards: Board[] }> {
|
async getAttachedBoards(): Promise<{ boards: Board[] }> {
|
||||||
|
@ -30,7 +30,6 @@ namespace ErrorWithCode {
|
|||||||
return {
|
return {
|
||||||
connectionId,
|
connectionId,
|
||||||
message,
|
message,
|
||||||
// message: `Cancelled on client. ${Board.toString(board)} from port ${Port.toString(port)}.`,
|
|
||||||
code: MonitorError.ErrorCodes.CLIENT_CANCEL,
|
code: MonitorError.ErrorCodes.CLIENT_CANCEL,
|
||||||
config
|
config
|
||||||
};
|
};
|
||||||
@ -40,7 +39,6 @@ namespace ErrorWithCode {
|
|||||||
case 'device not configured': {
|
case 'device not configured': {
|
||||||
return {
|
return {
|
||||||
connectionId,
|
connectionId,
|
||||||
// message: ``,
|
|
||||||
message,
|
message,
|
||||||
code: MonitorError.ErrorCodes.DEVICE_NOT_CONFIGURED,
|
code: MonitorError.ErrorCodes.DEVICE_NOT_CONFIGURED,
|
||||||
config
|
config
|
||||||
@ -49,12 +47,19 @@ namespace ErrorWithCode {
|
|||||||
case 'error opening serial monitor: Serial port busy': {
|
case 'error opening serial monitor: Serial port busy': {
|
||||||
return {
|
return {
|
||||||
connectionId,
|
connectionId,
|
||||||
// message: `Connection failed. Serial port is busy: ${Port.toString(port)}.`,
|
|
||||||
message,
|
message,
|
||||||
code: MonitorError.ErrorCodes.DEVICE_BUSY,
|
code: MonitorError.ErrorCodes.DEVICE_BUSY,
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case 'interrupted system call': {
|
||||||
|
return {
|
||||||
|
connectionId,
|
||||||
|
message,
|
||||||
|
code: MonitorError.ErrorCodes.interrupted_system_call,
|
||||||
|
config
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.warn(`Unhandled error with code:`, error);
|
console.warn(`Unhandled error with code:`, error);
|
||||||
@ -81,9 +86,12 @@ export class MonitorServiceImpl implements MonitorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
|
this.logger.info('>>> Disposing monitor service...');
|
||||||
for (const [connectionId, duplex] of this.connections.entries()) {
|
for (const [connectionId, duplex] of this.connections.entries()) {
|
||||||
this.doDisconnect(connectionId, duplex);
|
this.doDisconnect(connectionId, duplex);
|
||||||
}
|
}
|
||||||
|
this.logger.info('<<< Disposing monitor service...');
|
||||||
|
this.client = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect(config: MonitorConfig): Promise<{ connectionId: string }> {
|
async connect(config: MonitorConfig): Promise<{ connectionId: string }> {
|
||||||
@ -96,12 +104,6 @@ export class MonitorServiceImpl implements MonitorService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
duplex.on('error', ((error: Error) => {
|
duplex.on('error', ((error: Error) => {
|
||||||
// Dispose the connection on error.
|
|
||||||
// If the client has disconnected, we call `disconnect` and hit this error
|
|
||||||
// no need to disconnect once more.
|
|
||||||
if (!toDispose.disposed) {
|
|
||||||
toDispose.dispose();
|
|
||||||
}
|
|
||||||
if (ErrorWithCode.is(error)) {
|
if (ErrorWithCode.is(error)) {
|
||||||
const monitorError = ErrorWithCode.toMonitorError(error, connectionId, config);
|
const monitorError = ErrorWithCode.toMonitorError(error, connectionId, config);
|
||||||
if (monitorError) {
|
if (monitorError) {
|
||||||
@ -109,9 +111,22 @@ export class MonitorServiceImpl implements MonitorService {
|
|||||||
this.client.notifyError(monitorError);
|
this.client.notifyError(monitorError);
|
||||||
}
|
}
|
||||||
// Do not log the error, it was expected. The client will take care of the rest.
|
// Do not log the error, it was expected. The client will take care of the rest.
|
||||||
|
if (monitorError.code === MonitorError.ErrorCodes.interrupted_system_call) {
|
||||||
|
console.log('jajjajaja');
|
||||||
|
if (!toDispose.disposed) {
|
||||||
|
toDispose.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (error.message === 'interrupted system call') {
|
||||||
|
this.logger.info('TODO: reduce to debug, INTERRUPTED SYSTEM CALL');
|
||||||
|
return; // Continue.
|
||||||
|
}
|
||||||
|
if (!toDispose.disposed) {
|
||||||
|
toDispose.dispose();
|
||||||
|
}
|
||||||
this.logger.error(`Error occurred for connection ${connectionId}.`, error);
|
this.logger.error(`Error occurred for connection ${connectionId}.`, error);
|
||||||
}).bind(this));
|
}).bind(this));
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user