5
5
6
6
import { GitpodClient , GitpodServer , GitpodServiceImpl } from '@gitpod/gitpod-protocol/lib/gitpod-service' ;
7
7
import { JsonRpcProxyFactory } from '@gitpod/gitpod-protocol/lib/messaging/proxy-factory' ;
8
- import { listen as doListen } from 'vscode-ws-jsonrpc' ;
8
+ import { listen as doListen , ResponseError } from 'vscode-ws-jsonrpc' ;
9
9
import WebSocket , { ErrorEvent } from 'ws' ;
10
10
import ReconnectingWebSocket from 'reconnecting-websocket' ;
11
11
import * as vscode from 'vscode' ;
12
12
import { ILogService } from './services/logService' ;
13
+ import { Code } from '@bufbuild/connect' ;
14
+ import { WrapError } from './common/utils' ;
13
15
14
16
type UsedGitpodFunction = [ 'getLoggedInUser' , 'getWorkspace' , 'getOwnerToken' , 'getSSHPublicKeys' , 'sendHeartBeat' ] ;
15
17
type Union < Tuple extends any [ ] , Union = never > = Tuple [ number ] | Union ;
@@ -58,6 +60,11 @@ class GitpodServerApi extends vscode.Disposable {
58
60
} ) ;
59
61
webSocket . onerror = ( e : ErrorEvent ) => {
60
62
if ( webSocket . retryCount >= maxRetries ) {
63
+ // https://github.com/gitpod-io/gitpod/blob/d41a38ba83939856e5292e30912f52e749787db1/components/server/src/server.ts#L193-L195
64
+ if ( e . error . message === 'Unexpected server response: 401' ) {
65
+ this . onErrorEmitter . fire ( new WrapError ( 'Failed to call server API' , e . error , 'ServerAPI:' + Code [ Code . Unauthenticated ] ) ) ;
66
+ return ;
67
+ }
61
68
this . onErrorEmitter . fire ( e . error ) ;
62
69
}
63
70
} ;
@@ -84,9 +91,46 @@ class GitpodServerApi extends vscode.Disposable {
84
91
export function withServerApi < T > ( accessToken : string , serviceUrl : string , cb : ( service : GitpodConnection ) => Promise < T > , logger : ILogService ) : Promise < T > {
85
92
const api = new GitpodServerApi ( accessToken , serviceUrl , logger ) ;
86
93
return Promise . race ( [
87
- cb ( api . service ) ,
94
+ new Promise < T > ( ( resolve , reject ) => cb ( api . service ) . then ( resolve ) . catch ( err => {
95
+ if ( err instanceof ResponseError ) {
96
+ const code = categorizeRPCError ( err ) ;
97
+ const codeStr = code ? Code [ code ] : 'Unknown' ;
98
+ reject ( new WrapError ( 'Failed to call server API' , err , 'ServerAPI:' + codeStr ) ) ;
99
+ return ;
100
+ }
101
+ reject ( err ) ;
102
+ } ) ) ,
88
103
new Promise < T > ( ( _ , reject ) => api . onError ( error => {
89
104
reject ( error ) ;
90
105
} ) )
91
106
] ) . finally ( ( ) => api . dispose ( ) ) ;
92
107
}
108
+
109
+ // Should align with https://github.com/gitpod-io/gitpod/blob/d41a38ba83939856e5292e30912f52e749787db1/components/public-api-server/pkg/proxy/errors.go#LL25C1-L26C1
110
+ function categorizeRPCError ( err ?: ResponseError < any > ) : Code | undefined {
111
+ if ( ! err ) {
112
+ return ;
113
+ }
114
+ switch ( err . code ) {
115
+ case 400 :
116
+ return Code . InvalidArgument ;
117
+ case 401 :
118
+ return Code . Unauthenticated ;
119
+ case 403 :
120
+ return Code . PermissionDenied ;
121
+ case 404 :
122
+ return Code . NotFound ;
123
+ case 409 :
124
+ return Code . AlreadyExists ;
125
+ case 429 :
126
+ return Code . ResourceExhausted ;
127
+ case 470 :
128
+ return Code . PermissionDenied ;
129
+ case - 32603 :
130
+ return Code . Internal ;
131
+ }
132
+ if ( err . code >= 400 && err . code < 500 ) {
133
+ return Code . InvalidArgument ;
134
+ }
135
+ return Code . Internal ;
136
+ }
0 commit comments