mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-10 04:46:33 +00:00
fix: retry compilation if grpc client needs to be reinitialized (#2548)
* fix: use `Status` enum for status code in `ServiceError` type guards This change resolves the issue where the intersection of `ServiceError` error codes of type `number` resulted in the `never` type due to conflict between number and `State` enum if `StatusObject` * feat: add `isInvalidArgument` type guard to `ServiceError` * fix: retry compilation if grpc client needs to be reinitialized See https://github.com/arduino/arduino-ide/issues/2547
This commit is contained in:
parent
41844c9470
commit
4cf9909a07
@ -36,6 +36,7 @@ import { Instance } from './cli-protocol/cc/arduino/cli/commands/v1/common_pb';
|
|||||||
import {
|
import {
|
||||||
CompileRequest,
|
CompileRequest,
|
||||||
CompileResponse,
|
CompileResponse,
|
||||||
|
InstanceNeedsReinitializationError,
|
||||||
} from './cli-protocol/cc/arduino/cli/commands/v1/compile_pb';
|
} from './cli-protocol/cc/arduino/cli/commands/v1/compile_pb';
|
||||||
import { Port as RpcPort } from './cli-protocol/cc/arduino/cli/commands/v1/port_pb';
|
import { Port as RpcPort } from './cli-protocol/cc/arduino/cli/commands/v1/port_pb';
|
||||||
import {
|
import {
|
||||||
@ -89,48 +90,84 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
|||||||
compileSummaryHandler
|
compileSummaryHandler
|
||||||
);
|
);
|
||||||
const toDisposeOnFinally = new DisposableCollection(handler);
|
const toDisposeOnFinally = new DisposableCollection(handler);
|
||||||
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
const call = client.compile(request);
|
let hasRetried = false;
|
||||||
if (cancellationToken) {
|
|
||||||
toDisposeOnFinally.push(
|
const handleUnexpectedError = (error: Error) => {
|
||||||
cancellationToken.onCancellationRequested(() => call.cancel())
|
console.error(
|
||||||
|
'Unexpected error occurred while compiling the sketch.',
|
||||||
|
error
|
||||||
);
|
);
|
||||||
}
|
reject(error);
|
||||||
call
|
};
|
||||||
.on('data', handler.onData)
|
|
||||||
.on('error', (error) => {
|
const handleCancellationError = () => {
|
||||||
if (!ServiceError.is(error)) {
|
console.log(userAbort);
|
||||||
console.error(
|
reject(UserAbortApplicationError());
|
||||||
'Unexpected error occurred while compiling the sketch.',
|
};
|
||||||
error
|
|
||||||
);
|
const handleInstanceNeedsReinitializationError = async (
|
||||||
reject(error);
|
error: ServiceError & InstanceNeedsReinitializationError
|
||||||
return;
|
) => {
|
||||||
}
|
if (hasRetried) {
|
||||||
if (ServiceError.isCancel(error)) {
|
// If error persists, send the error message to the output
|
||||||
console.log(userAbort);
|
return parseAndSendErrorResponse(error);
|
||||||
reject(UserAbortApplicationError());
|
}
|
||||||
return;
|
|
||||||
}
|
hasRetried = true;
|
||||||
const compilerErrors = tryParseError({
|
await this.refresh();
|
||||||
content: handler.content,
|
return startCompileStream();
|
||||||
sketch: options.sketch,
|
};
|
||||||
});
|
|
||||||
const message = nls.localize(
|
const parseAndSendErrorResponse = (error: ServiceError) => {
|
||||||
'arduino/compile/error',
|
const compilerErrors = tryParseError({
|
||||||
'Compilation error: {0}',
|
content: handler.content,
|
||||||
compilerErrors
|
sketch: options.sketch,
|
||||||
.map(({ message }) => message)
|
});
|
||||||
.filter(notEmpty)
|
const message = nls.localize(
|
||||||
.shift() ?? error.details
|
'arduino/compile/error',
|
||||||
|
'Compilation error: {0}',
|
||||||
|
compilerErrors
|
||||||
|
.map(({ message }) => message)
|
||||||
|
.filter(notEmpty)
|
||||||
|
.shift() ?? error.details
|
||||||
|
);
|
||||||
|
this.sendResponse(
|
||||||
|
error.details + '\n\n' + message,
|
||||||
|
OutputMessage.Severity.Error
|
||||||
|
);
|
||||||
|
reject(CoreError.VerifyFailed(message, compilerErrors));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleError = async (error: Error) => {
|
||||||
|
if (!ServiceError.is(error)) return handleUnexpectedError(error);
|
||||||
|
if (ServiceError.isCancel(error)) return handleCancellationError();
|
||||||
|
|
||||||
|
if (
|
||||||
|
ServiceError.isInstanceOf(error, InstanceNeedsReinitializationError)
|
||||||
|
) {
|
||||||
|
return await handleInstanceNeedsReinitializationError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
parseAndSendErrorResponse(error);
|
||||||
|
};
|
||||||
|
|
||||||
|
const startCompileStream = () => {
|
||||||
|
const call = client.compile(request);
|
||||||
|
if (cancellationToken) {
|
||||||
|
toDisposeOnFinally.push(
|
||||||
|
cancellationToken.onCancellationRequested(() => call.cancel())
|
||||||
);
|
);
|
||||||
this.sendResponse(
|
}
|
||||||
error.details + '\n\n' + message,
|
|
||||||
OutputMessage.Severity.Error
|
call
|
||||||
);
|
.on('data', handler.onData)
|
||||||
reject(CoreError.VerifyFailed(message, compilerErrors));
|
.on('error', handleError)
|
||||||
})
|
.on('end', resolve);
|
||||||
.on('end', resolve);
|
};
|
||||||
|
|
||||||
|
startCompileStream();
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
toDisposeOnFinally.dispose();
|
toDisposeOnFinally.dispose();
|
||||||
if (!isCompileSummary(compileSummary)) {
|
if (!isCompileSummary(compileSummary)) {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { Metadata, StatusObject } from '@grpc/grpc-js';
|
import { Metadata, StatusObject } from '@grpc/grpc-js';
|
||||||
import { Status } from './cli-protocol/google/rpc/status_pb';
|
import { Status } from './cli-protocol/google/rpc/status_pb';
|
||||||
import { stringToUint8Array } from '../common/utils';
|
import { stringToUint8Array } from '../common/utils';
|
||||||
|
import { Status as StatusCode } from '@grpc/grpc-js/build/src/constants';
|
||||||
import { ProgrammerIsRequiredForUploadError } from './cli-protocol/cc/arduino/cli/commands/v1/upload_pb';
|
import { ProgrammerIsRequiredForUploadError } from './cli-protocol/cc/arduino/cli/commands/v1/upload_pb';
|
||||||
|
import { InstanceNeedsReinitializationError } from './cli-protocol/cc/arduino/cli/commands/v1/compile_pb';
|
||||||
|
|
||||||
type ProtoError = typeof ProgrammerIsRequiredForUploadError;
|
type ProtoError = typeof ProgrammerIsRequiredForUploadError;
|
||||||
const protoErrorsMap = new Map<string, ProtoError>([
|
const protoErrorsMap = new Map<string, ProtoError>([
|
||||||
@ -9,15 +11,27 @@ const protoErrorsMap = new Map<string, ProtoError>([
|
|||||||
'cc.arduino.cli.commands.v1.ProgrammerIsRequiredForUploadError',
|
'cc.arduino.cli.commands.v1.ProgrammerIsRequiredForUploadError',
|
||||||
ProgrammerIsRequiredForUploadError,
|
ProgrammerIsRequiredForUploadError,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'cc.arduino.cli.commands.v1.InstanceNeedsReinitializationError',
|
||||||
|
InstanceNeedsReinitializationError,
|
||||||
|
],
|
||||||
// handle other cli defined errors here
|
// handle other cli defined errors here
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export type ServiceError = StatusObject & Error;
|
export type ServiceError = StatusObject & Error;
|
||||||
export namespace ServiceError {
|
export namespace ServiceError {
|
||||||
export function isCancel(arg: unknown): arg is ServiceError & { code: 1 } {
|
export function isCancel(
|
||||||
|
arg: unknown
|
||||||
|
): arg is ServiceError & { code: StatusCode.CANCELLED } {
|
||||||
return is(arg) && arg.code === 1; // https://grpc.github.io/grpc/core/md_doc_statuscodes.html
|
return is(arg) && arg.code === 1; // https://grpc.github.io/grpc/core/md_doc_statuscodes.html
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isInvalidArgument(
|
||||||
|
arg: unknown
|
||||||
|
): arg is ServiceError & { code: StatusCode.INVALID_ARGUMENT } {
|
||||||
|
return is(arg) && arg.code === 3; // https://grpc.github.io/grpc/core/md_doc_statuscodes.html
|
||||||
|
}
|
||||||
|
|
||||||
export function is(arg: unknown): arg is ServiceError {
|
export function is(arg: unknown): arg is ServiceError {
|
||||||
return arg instanceof Error && isStatusObject(arg);
|
return arg instanceof Error && isStatusObject(arg);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user