17
17
18
18
import {
19
19
assert ,
20
- jsonEval ,
21
20
safeGet ,
22
- querystring ,
23
- Deferred
24
21
} from '@firebase/util' ;
25
22
26
23
import { AppCheckTokenProvider } from './AppCheckTokenProvider' ;
@@ -56,7 +53,7 @@ export class ReadonlyRestClient extends ServerActions {
56
53
} else {
57
54
assert (
58
55
query . _queryParams . isDefault ( ) ,
59
- " should have a tag if it's not a default query."
56
+ ' should have a tag if it\ 's not a default query.'
60
57
) ;
61
58
return query . _path . toString ( ) ;
62
59
}
@@ -81,7 +78,7 @@ export class ReadonlyRestClient extends ServerActions {
81
78
}
82
79
83
80
/** @inheritDoc */
84
- listen (
81
+ async listen (
85
82
query : QueryContext ,
86
83
currentHashFn : ( ) => string ,
87
84
tag : number | null ,
@@ -99,35 +96,34 @@ export class ReadonlyRestClient extends ServerActions {
99
96
query . _queryParams
100
97
) ;
101
98
102
- this . restRequest_ (
99
+ let [ response , data ] = await this . restRequest_ (
103
100
pathString + '.json' ,
104
101
queryStringParameters ,
105
- ( error , result ) => {
106
- let data = result ;
107
-
108
- if ( error === 404 ) {
109
- data = null ;
110
- error = null ;
111
- }
112
-
113
- if ( error === null ) {
114
- this . onDataUpdate_ ( pathString , data , /*isMerge=*/ false , tag ) ;
115
- }
116
-
117
- if ( safeGet ( this . listens_ , listenId ) === thisListen ) {
118
- let status ;
119
- if ( ! error ) {
120
- status = 'ok' ;
121
- } else if ( error === 401 ) {
122
- status = 'permission_denied' ;
123
- } else {
124
- status = 'rest_error:' + error ;
125
- }
126
-
127
- onComplete ( status , null ) ;
128
- }
129
- }
130
102
) ;
103
+
104
+ let error = response . status ;
105
+
106
+ if ( error === 404 ) {
107
+ data = null ;
108
+ error = null ;
109
+ }
110
+
111
+ if ( error === null ) {
112
+ this . onDataUpdate_ ( pathString , data , /*isMerge=*/ false , tag ) ;
113
+ }
114
+
115
+ if ( safeGet ( this . listens_ , listenId ) === thisListen ) {
116
+ let status ;
117
+ if ( ! error ) {
118
+ status = 'ok' ;
119
+ } else if ( error === 401 ) {
120
+ status = 'permission_denied' ;
121
+ } else {
122
+ status = 'rest_error:' + error ;
123
+ }
124
+
125
+ onComplete ( status , null ) ;
126
+ }
131
127
}
132
128
133
129
/** @inheritDoc */
@@ -136,40 +132,31 @@ export class ReadonlyRestClient extends ServerActions {
136
132
delete this . listens_ [ listenId ] ;
137
133
}
138
134
139
- get ( query : QueryContext ) : Promise < string > {
135
+ async get ( query : QueryContext ) : Promise < string > {
140
136
const queryStringParameters = queryParamsToRestQueryStringParameters (
141
137
query . _queryParams
142
138
) ;
143
139
144
140
const pathString = query . _path . toString ( ) ;
145
141
146
- const deferred = new Deferred < string > ( ) ;
147
-
148
- this . restRequest_ (
142
+ let [ response , data ] = await this . restRequest_ (
149
143
pathString + '.json' ,
150
- queryStringParameters ,
151
- ( error , result ) => {
152
- let data = result ;
153
-
154
- if ( error === 404 ) {
155
- data = null ;
156
- error = null ;
157
- }
158
-
159
- if ( error === null ) {
160
- this . onDataUpdate_ (
161
- pathString ,
162
- data ,
163
- /*isMerge=*/ false ,
164
- /*tag=*/ null
165
- ) ;
166
- deferred . resolve ( data as string ) ;
167
- } else {
168
- deferred . reject ( new Error ( data as string ) ) ;
169
- }
170
- }
144
+ queryStringParameters
171
145
) ;
172
- return deferred . promise ;
146
+
147
+ if ( response . status === 404 ) {
148
+ data = null ;
149
+ } else if ( ! response . ok ) {
150
+ throw new Error ( data as string ) ;
151
+ }
152
+
153
+ this . onDataUpdate_ (
154
+ pathString ,
155
+ data ,
156
+ /*isMerge=*/ false ,
157
+ /*tag=*/ null
158
+ ) ;
159
+ return data as string ;
173
160
}
174
161
175
162
/** @inheritDoc */
@@ -181,74 +168,57 @@ export class ReadonlyRestClient extends ServerActions {
181
168
* Performs a REST request to the given path, with the provided query string parameters,
182
169
* and any auth credentials we have.
183
170
*/
184
- private restRequest_ (
171
+ private async restRequest_ < T = unknown > (
185
172
pathString : string ,
186
- queryStringParameters : { [ k : string ] : string | number } = { } ,
187
- callback : ( ( a : number | null , b ?: unknown ) => void ) | null
188
- ) {
189
- queryStringParameters [ 'format' ] = 'export' ;
173
+ queryStringParameters : Record < string , string | number > = { } ,
174
+ ) : Promise < [ Response , T | null ] > {
190
175
191
- return Promise . all ( [
176
+ // Fetch tokens
177
+ const [ authToken , appCheckToken ] = await Promise . all ( [
192
178
this . authTokenProvider_ . getToken ( /*forceRefresh=*/ false ) ,
193
179
this . appCheckTokenProvider_ . getToken ( /*forceRefresh=*/ false )
194
- ] ) . then ( ( [ authToken , appCheckToken ] ) => {
195
- if ( authToken && authToken . accessToken ) {
196
- queryStringParameters [ 'auth' ] = authToken . accessToken ;
197
- }
198
- if ( appCheckToken && appCheckToken . token ) {
199
- queryStringParameters [ 'ac' ] = appCheckToken . token ;
200
- }
180
+ ] ) ;
181
+
182
+ // Configure URL parameters
183
+ const searchParams = new URLSearchParams ( queryStringParameters as Record < string , string > ) ;
184
+ if ( authToken && authToken . accessToken ) {
185
+ searchParams . set ( 'auth' , authToken . accessToken ) ;
186
+ }
187
+ if ( appCheckToken && appCheckToken . token ) {
188
+ searchParams . set ( "ac" , appCheckToken . token ) ;
189
+ }
190
+ searchParams . set ( 'format' , 'export' ) ;
191
+ searchParams . set ( 'ns' , this . repoInfo_ . namespace ) ;
192
+
193
+ // Build & send the request
194
+ const url =
195
+ ( this . repoInfo_ . secure ? 'https://' : 'http://' ) +
196
+ this . repoInfo_ . host +
197
+ pathString +
198
+ '?' +
199
+ searchParams . toString ( ) ;
200
+
201
+ this . log_ ( 'Sending REST request for ' + url ) ;
202
+ const response = await fetch ( url ) ;
203
+ if ( ! response . ok ) {
204
+ // Request was not successful, so throw an error
205
+ throw new Error ( `REST request at ${ url } returned error: ${ response . status } ` ) ;
206
+ }
207
+
208
+ this . log_ (
209
+ 'REST Response for ' + url + ' received. status:' ,
210
+ response . status ,
211
+ ) ;
212
+ let result : T | null = null ;
213
+ try {
214
+ result = await response . json ( ) ;
215
+ } catch ( e ) {
216
+ warn (
217
+ 'Failed to parse server response as json.' ,
218
+ e
219
+ ) ;
220
+ }
201
221
202
- const url =
203
- ( this . repoInfo_ . secure ? 'https://' : 'http://' ) +
204
- this . repoInfo_ . host +
205
- pathString +
206
- '?' +
207
- 'ns=' +
208
- this . repoInfo_ . namespace +
209
- querystring ( queryStringParameters ) ;
210
-
211
- this . log_ ( 'Sending REST request for ' + url ) ;
212
- const xhr = new XMLHttpRequest ( ) ;
213
- xhr . onreadystatechange = ( ) => {
214
- if ( callback && xhr . readyState === 4 ) {
215
- this . log_ (
216
- 'REST Response for ' + url + ' received. status:' ,
217
- xhr . status ,
218
- 'response:' ,
219
- xhr . responseText
220
- ) ;
221
- let res = null ;
222
- if ( xhr . status >= 200 && xhr . status < 300 ) {
223
- try {
224
- res = jsonEval ( xhr . responseText ) ;
225
- } catch ( e ) {
226
- warn (
227
- 'Failed to parse JSON response for ' +
228
- url +
229
- ': ' +
230
- xhr . responseText
231
- ) ;
232
- }
233
- callback ( null , res ) ;
234
- } else {
235
- // 401 and 404 are expected.
236
- if ( xhr . status !== 401 && xhr . status !== 404 ) {
237
- warn (
238
- 'Got unsuccessful REST response for ' +
239
- url +
240
- ' Status: ' +
241
- xhr . status
242
- ) ;
243
- }
244
- callback ( xhr . status ) ;
245
- }
246
- callback = null ;
247
- }
248
- } ;
249
-
250
- xhr . open ( 'GET' , url , /*asynchronous=*/ true ) ;
251
- xhr . send ( ) ;
252
- } ) ;
222
+ return [ response , result ] ;
253
223
}
254
224
}
0 commit comments