Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7c2843f

Browse files
Akos Kittakittaakos
Akos Kitta
authored andcommitted
Relaxed the error handling of the core client init
For example, `malformed custom board options` was incorrectly detected as loading JSON index file error. Closes #1036 Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
1 parent fd5154a commit 7c2843f

File tree

1 file changed

+83
-57
lines changed

1 file changed

+83
-57
lines changed

‎arduino-ide-extension/src/node/core-client-provider.ts‎

Lines changed: 83 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ import {
2121
import * as commandsGrpcPb from './cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb';
2222
import { NotificationServiceServer } from '../common/protocol';
2323
import { Deferred, retry } from '@theia/core/lib/common/promise-util';
24-
import { Status as RpcStatus } from './cli-protocol/google/rpc/status_pb';
24+
import {
25+
Status as RpcStatus,
26+
Status,
27+
} from './cli-protocol/google/rpc/status_pb';
2528

2629
@injectable()
2730
export class CoreClientProvider extends GrpcClientProvider<CoreClientProvider.Client> {
@@ -90,10 +93,11 @@ export class CoreClientProvider extends GrpcClientProvider<CoreClientProvider.Cl
9093
this._initialized.resolve();
9194
this.updateIndex(this._client); // Update the indexes asynchronously
9295
} catch (error: unknown) {
93-
if (
94-
this.isPackageIndexMissingError(error) ||
95-
this.isDiscoveryNotFoundError(error)
96-
) {
96+
console.error(
97+
'Error occurred while initializing the core gRPC client provider',
98+
error
99+
);
100+
if (error instanceof IndexUpdateRequiredBeforeInitError) {
97101
// If it's a first start, IDE2 must run index update before the init request.
98102
await this.updateIndexes(this._client);
99103
await this.initInstance(this._client);
@@ -114,41 +118,6 @@ export class CoreClientProvider extends GrpcClientProvider<CoreClientProvider.Cl
114118
});
115119
}
116120

117-
private isPackageIndexMissingError(error: unknown): boolean {
118-
const assert = (message: string) =>
119-
message.includes('loading json index file');
120-
// https://github.com/arduino/arduino-cli/blob/f0245bc2da6a56fccea7b2c9ea09e85fdcc52cb8/arduino/cores/packagemanager/package_manager.go#L247
121-
return this.isRpcStatusError(error, assert);
122-
}
123-
124-
private isDiscoveryNotFoundError(error: unknown): boolean {
125-
const assert = (message: string) =>
126-
message.includes('discovery') &&
127-
(message.includes('not found') || message.includes('not installed'));
128-
// https://github.com/arduino/arduino-cli/blob/f0245bc2da6a56fccea7b2c9ea09e85fdcc52cb8/arduino/cores/packagemanager/loader.go#L740
129-
// https://github.com/arduino/arduino-cli/blob/f0245bc2da6a56fccea7b2c9ea09e85fdcc52cb8/arduino/cores/packagemanager/loader.go#L744
130-
return this.isRpcStatusError(error, assert);
131-
}
132-
133-
private isCancelError(error: unknown): boolean {
134-
return (
135-
error instanceof Error &&
136-
error.message.toLocaleLowerCase().includes('cancelled on client')
137-
);
138-
}
139-
140-
// Final error codes are not yet defined by the CLI. Hence, we do string matching in the message RPC status.
141-
private isRpcStatusError(
142-
error: unknown,
143-
assert: (message: string) => boolean
144-
) {
145-
if (error instanceof RpcStatus) {
146-
const { message } = RpcStatus.toObject(false, error);
147-
return assert(message.toLocaleLowerCase());
148-
}
149-
return false;
150-
}
151-
152121
protected async createClient(
153122
port: string | number
154123
): Promise<CoreClientProvider.Client> {
@@ -192,7 +161,7 @@ export class CoreClientProvider extends GrpcClientProvider<CoreClientProvider.Cl
192161
initReq.setInstance(instance);
193162
return new Promise<void>((resolve, reject) => {
194163
const stream = client.init(initReq);
195-
const errorStatus: RpcStatus[] = [];
164+
const errors: RpcStatus[] = [];
196165
stream.on('data', (res: InitResponse) => {
197166
const progress = res.getInitProgress();
198167
if (progress) {
@@ -210,28 +179,30 @@ export class CoreClientProvider extends GrpcClientProvider<CoreClientProvider.Cl
210179

211180
const error = res.getError();
212181
if (error) {
213-
console.error(error.getMessage());
214-
errorStatus.push(error);
215-
// Cancel the init request. No need to wait until the end of the event. The init has already failed.
216-
// Canceling the request will result in a cancel error, but we need to reject with the original error later.
217-
stream.cancel();
182+
const{ code, message }=Status.toObject(false,error);
183+
console.error(
184+
`Detected an error response during the gRPC core client initialization: code: ${code}, message: ${message}`
185+
);
186+
errors.push(error);
218187
}
219188
});
220-
stream.on('error', (error)=>{
221-
// On any error during the init request, the request is canceled.
222-
// On cancel, the IDE2 ignores the cancel error and rejects with the original one.
223-
reject(
224-
this.isCancelError(error)&&errorStatus.length
225-
? errorStatus[0]
226-
: error
227-
);
189+
stream.on('error', reject);
190+
stream.on('end',()=>{
191+
consterror =this.evaluateErrorStatus(errors);
192+
if(error){
193+
reject(error);
194+
return;
195+
}
196+
resolve();
228197
});
229-
stream.on('end', () =>
230-
errorStatus.length ? reject(errorStatus) : resolve()
231-
);
232198
});
233199
}
234200

201+
private evaluateErrorStatus(status: RpcStatus[]): Error | undefined {
202+
const error = isIndexUpdateRequiredBeforeInit(status); // put future error matching here
203+
return error;
204+
}
205+
235206
protected async updateIndexes(
236207
client: CoreClientProvider.Client
237208
): Promise<CoreClientProvider.Client> {
@@ -338,3 +309,58 @@ export abstract class CoreClientAware {
338309
);
339310
}
340311
}
312+
313+
class IndexUpdateRequiredBeforeInitError extends Error {
314+
constructor(causes: RpcStatus.AsObject[]) {
315+
super(`The index of the cores and libraries must be updated before initializing the core gRPC client.
316+
The following problems were detected during the gRPC client initialization:
317+
${causes
318+
.map(({ code, message }) => ` - code: ${code}, message: ${message}`)
319+
.join('\n')}
320+
`);
321+
Object.setPrototypeOf(this, IndexUpdateRequiredBeforeInitError.prototype);
322+
if (!causes.length) {
323+
throw new Error(`expected non-empty 'causes'`);
324+
}
325+
}
326+
}
327+
328+
function isIndexUpdateRequiredBeforeInit(
329+
status: RpcStatus[]
330+
): IndexUpdateRequiredBeforeInitError | undefined {
331+
const causes = status
332+
.filter((s) =>
333+
IndexUpdateRequiredBeforeInit.map((predicate) => predicate(s)).some(
334+
Boolean
335+
)
336+
)
337+
.map((s) => RpcStatus.toObject(false, s));
338+
return causes.length
339+
? new IndexUpdateRequiredBeforeInitError(causes)
340+
: undefined;
341+
}
342+
const IndexUpdateRequiredBeforeInit = [
343+
isPackageIndexMissingStatus,
344+
isDiscoveryNotFoundStatus,
345+
];
346+
function isPackageIndexMissingStatus(status: RpcStatus): boolean {
347+
const predicate = ({ message }: RpcStatus.AsObject) =>
348+
message.includes('loading json index file');
349+
// https://github.com/arduino/arduino-cli/blob/f0245bc2da6a56fccea7b2c9ea09e85fdcc52cb8/arduino/cores/packagemanager/package_manager.go#L247
350+
return evaluate(status, predicate);
351+
}
352+
function isDiscoveryNotFoundStatus(status: RpcStatus): boolean {
353+
const predicate = ({ message }: RpcStatus.AsObject) =>
354+
message.includes('discovery') &&
355+
(message.includes('not found') || message.includes('not installed'));
356+
// https://github.com/arduino/arduino-cli/blob/f0245bc2da6a56fccea7b2c9ea09e85fdcc52cb8/arduino/cores/packagemanager/loader.go#L740
357+
// https://github.com/arduino/arduino-cli/blob/f0245bc2da6a56fccea7b2c9ea09e85fdcc52cb8/arduino/cores/packagemanager/loader.go#L744
358+
return evaluate(status, predicate);
359+
}
360+
function evaluate(
361+
subject: RpcStatus,
362+
predicate: (error: RpcStatus.AsObject) => boolean
363+
): boolean {
364+
const status = RpcStatus.toObject(false, subject);
365+
return predicate(status);
366+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /