Clone the tshd gRPC client to allow inspecting errors#39229
Conversation
It's needed because now we also log a passwordless login stream call.
avatus
left a comment
There was a problem hiding this comment.
I need to dive in more but so far looks good
|
@ravicious helped me with creating a function to wrap the entire client, instead of each method manually. I updated both PRs. |
ravicious
left a comment
There was a problem hiding this comment.
Nice job, the code in this PR looks very good. I submitted a bunch of minor suggestions.
| * A unary RPC call. Can be passed over the context bridge. | ||
| * Errors are converted to `TshdRpcError` objects. | ||
| */ | ||
| export type CloneableUnaryCall<I extends object, O extends object> = Pick< |
There was a problem hiding this comment.
Do types for specific calls need to be exported?
There was a problem hiding this comment.
I wanted to say that I need a CloneableUnaryCall for types of reportEvent, but actually I don't.
I can do this:
reportUsageEvent: CloneableClient<ITerminalServiceClient>['reportUsageEvent'];instead of this:
reportUsageEvent: (
input: ReportUsageEventRequest,
options?: CloneableRpcOptions
) => CloneableUnaryCall<ReportUsageEventRequest, apiService.EmptyResponse>;There was a problem hiding this comment.
This should be fine for now until we replace createClient. In my opinion, when defining types it's better to avoid to referring to types of other "entities".
It's pretty much like Law of Demeter but for types. Such things are not even possible in languages designed with types in mind from the start. 😏
| if (error.name === 'RpcError') { | ||
| const e = error as RpcError; |
There was a problem hiding this comment.
if (error instanceof RpcError) should work here, shouldn't it? Since we're still on the preload side.
There was a problem hiding this comment.
I'm sure that I tried this, but it didn't want to work 🤔
But I was wrong, it works perfectly fine, I don't know, maybe I was checking it on the renderer side 🤷♂️
…e context bridge (#39230) * Regenerate protos with the `protobuf-ts` client * Enable `strictBindCallApply` so `.bind()` results have correct types (instead of `any`) This is needed for wrapping calls in `createClient`. * Use `protobuf-ts` client instead of `grpc-js` one * Convert `createClient` to use `protobuf-ts` response style, clone each call * Switch callsites to `cloneAbortSignal` * Replace `error.message` checks with a proper check on the error status code * Clone the entire client instead of each method separately * Correct the error `cause` in `ResourceSearchError` * Remove `params.sortBy` defaults, always set `startKey` to string * Use a simpler type for `reportUsageEvent`
# Conflicts: # web/packages/teleterm/src/services/tshd/createClient.ts
* Add functions to clone every gRPC method, so they can be passed over the context bridge * Replace `@grpc/grpc-js` interceptors with `@protobuf-ts/runtime-rpc` ones * Replace string check with check on metadata, add missing `AddMetadataToRetryableError` * Add `pin` to sensitive properties It's needed because now we also log a passwordless login stream call. * Add `cloneClient` method to clone the entire gRPC client * Switch tests to `TshdRetryableError` * Improve comments * Move `cloneClient` and `cloneAbortSignal` to the top of the file * Simplify condition * Lowercase logs * Check if the error is `RpcError` using `instanceof` * Log error object instead of `[object Object]` * Do not export call specific types * Wrap gRPC calls in `createClient` to allow passing the errors over the context bridge (#39230) * Regenerate protos with the `protobuf-ts` client * Enable `strictBindCallApply` so `.bind()` results have correct types (instead of `any`) This is needed for wrapping calls in `createClient`. * Use `protobuf-ts` client instead of `grpc-js` one * Convert `createClient` to use `protobuf-ts` response style, clone each call * Switch callsites to `cloneAbortSignal` * Replace `error.message` checks with a proper check on the error status code * Clone the entire client instead of each method separately * Correct the error `cause` in `ResourceSearchError` * Remove `params.sortBy` defaults, always set `startKey` to string * Use a simpler type for `reportUsageEvent` * Fix interceptor test * Ignore TS error in `highbar.ts` (cherry picked from commit 784d7ac)
…ss denied" (#39720) * Clone the tshd gRPC client to allow inspecting errors (#39229) * Add functions to clone every gRPC method, so they can be passed over the context bridge * Replace `@grpc/grpc-js` interceptors with `@protobuf-ts/runtime-rpc` ones * Replace string check with check on metadata, add missing `AddMetadataToRetryableError` * Add `pin` to sensitive properties It's needed because now we also log a passwordless login stream call. * Add `cloneClient` method to clone the entire gRPC client * Switch tests to `TshdRetryableError` * Improve comments * Move `cloneClient` and `cloneAbortSignal` to the top of the file * Simplify condition * Lowercase logs * Check if the error is `RpcError` using `instanceof` * Log error object instead of `[object Object]` * Do not export call specific types * Wrap gRPC calls in `createClient` to allow passing the errors over the context bridge (#39230) * Regenerate protos with the `protobuf-ts` client * Enable `strictBindCallApply` so `.bind()` results have correct types (instead of `any`) This is needed for wrapping calls in `createClient`. * Use `protobuf-ts` client instead of `grpc-js` one * Convert `createClient` to use `protobuf-ts` response style, clone each call * Switch callsites to `cloneAbortSignal` * Replace `error.message` checks with a proper check on the error status code * Clone the entire client instead of each method separately * Correct the error `cause` in `ResourceSearchError` * Remove `params.sortBy` defaults, always set `startKey` to string * Use a simpler type for `reportUsageEvent` * Fix interceptor test * Ignore TS error in `highbar.ts` (cherry picked from commit 784d7ac) * Do not replace `AccessDenied` error messages with generic "access denied" (#39558) * Do not replace `AccessDenied` error messages with generic "access denied" * Replace `error.code` checks with `isTshdRpcError(error, code)` * Add `ABORTED` and `UNAUTHENTICATED` codes * Improve `isTshdRpcError` documentation * Do not catch `retryWithRelogin` errors in `Setup.tsx` (cherry picked from commit 48c05b6)
Part 1/2 of https://github.com/gravitational/teleport.e/issues/853
The task of this PR is to provide utility functions for wrapping each gRPC call so we can inspect their errors on the renderer side.
Why do we need all these
clone*functions? Because when the error goes through the electron context bridge (is a bridge between preload and renderer) most of its properties is removed, so we can't inspect gRPCcodeormetadata.The solution for this is converting the error to an object before its crosses the bridge.
Additionally, I switched the client from
grpc-jstoprotobuf-ts. It has a more modern API that uses promises and abort signals. The conversion ofcreateClientis done in the second PR.Also, emitting our custom errors addresses #30753. The codes are no longer visible, but if we want to bring them back (in a nicer form) we can do it.
I wanted split the changes into something that is easier to review, this PR contains the essential parts: adds functions to convert the calls and abort signals, converts interceptors to the form required by
protobuf-ts, replaces the check inisRetryablewith the check on error metadata.Note: this PR doesn't pass TS check, it requires the second PR.