@@ -35,79 +35,40 @@ import {
35
35
} from '@firebase/util' ;
36
36
37
37
import { Token } from '../../api/credentials' ;
38
- import { DatabaseId , DatabaseInfo } from '../../core/database_info' ;
39
- import { SDK_VERSION } from '../../core/version' ;
40
- import { Connection , Stream } from '../../remote/connection' ;
38
+ import { DatabaseInfo } from '../../core/database_info' ;
39
+ import { Stream } from '../../remote/connection' ;
41
40
import {
42
41
mapCodeFromRpcStatus ,
43
42
mapCodeFromHttpResponseErrorStatus
44
43
} from '../../remote/rpc_error' ;
45
44
import { StreamBridge } from '../../remote/stream_bridge' ;
46
- import { debugAssert , fail , hardAssert } from '../../util/assert' ;
45
+ import { fail , hardAssert } from '../../util/assert' ;
47
46
import { Code , FirestoreError } from '../../util/error' ;
48
47
import { logDebug , logWarn } from '../../util/log' ;
49
- import { Indexable } from '../../util/misc' ;
50
48
import { Rejecter , Resolver } from '../../util/promise' ;
51
49
import { StringMap } from '../../util/types' ;
50
+ import { RestConnection } from '../../remote/rest_connection' ;
52
51
53
52
const LOG_TAG = 'Connection' ;
54
53
55
54
const RPC_STREAM_SERVICE = 'google.firestore.v1.Firestore' ;
56
- const RPC_URL_VERSION = 'v1' ;
57
-
58
- /**
59
- * Maps RPC names to the corresponding REST endpoint name.
60
- * Uses Object Literal notation to avoid renaming.
61
- */
62
- const RPC_NAME_REST_MAPPING : { [ key : string ] : string } = { } ;
63
- RPC_NAME_REST_MAPPING [ 'BatchGetDocuments' ] = 'batchGet' ;
64
- RPC_NAME_REST_MAPPING [ 'Commit' ] = 'commit' ;
65
- RPC_NAME_REST_MAPPING [ 'RunQuery' ] = 'runQuery' ;
66
-
67
- // TODO(b/38203344): The SDK_VERSION is set independently from Firebase because
68
- // we are doing out-of-band releases. Once we release as part of Firebase, we
69
- // should use the Firebase version instead.
70
- const X_GOOG_API_CLIENT_VALUE = 'gl-js/ fire/' + SDK_VERSION ;
71
55
72
56
const XHR_TIMEOUT_SECS = 15 ;
73
57
74
- export class WebChannelConnection implements Connection {
75
- private readonly databaseId : DatabaseId ;
76
- private readonly baseUrl : string ;
58
+ export class WebChannelConnection extends RestConnection {
77
59
private readonly forceLongPolling : boolean ;
78
60
79
61
constructor ( info : DatabaseInfo ) {
80
- this . databaseId = info . databaseId ;
81
- const proto = info . ssl ? 'https' : 'http' ;
82
- this . baseUrl = proto + '://' + info . host ;
62
+ super ( info ) ;
83
63
this . forceLongPolling = info . forceLongPolling ;
84
64
}
85
65
86
- /**
87
- * Modifies the headers for a request, adding any authorization token if
88
- * present and any additional headers for the request.
89
- */
90
- private modifyHeadersForRequest (
91
- headers : StringMap ,
92
- token : Token | null
93
- ) : void {
94
- if ( token ) {
95
- for ( const header in token . authHeaders ) {
96
- if ( token . authHeaders . hasOwnProperty ( header ) ) {
97
- headers [ header ] = token . authHeaders [ header ] ;
98
- }
99
- }
100
- }
101
- headers [ 'X-Goog-Api-Client' ] = X_GOOG_API_CLIENT_VALUE ;
102
- }
103
-
104
- invokeRPC < Req , Resp > (
66
+ protected performRPCRequest < Req , Resp > (
105
67
rpcName : string ,
106
- request : Req ,
107
- token : Token | null
68
+ url : string ,
69
+ headers : StringMap ,
70
+ body : Req
108
71
) : Promise < Resp > {
109
- const url = this . makeUrl ( rpcName ) ;
110
-
111
72
return new Promise ( ( resolve : Resolver < Resp > , reject : Rejecter ) => {
112
73
const xhr = new XhrIo ( ) ;
113
74
xhr . listenOnce ( EventType . COMPLETE , ( ) => {
@@ -161,7 +122,6 @@ export class WebChannelConnection implements Connection {
161
122
} else {
162
123
// If we received an HTTP_ERROR but there's no status code,
163
124
// it's most probably a connection issue
164
- logDebug ( LOG_TAG , 'RPC "' + rpcName + '" failed' ) ;
165
125
reject (
166
126
new FirestoreError ( Code . UNAVAILABLE , 'Connection failed.' )
167
127
) ;
@@ -184,37 +144,11 @@ export class WebChannelConnection implements Connection {
184
144
}
185
145
} ) ;
186
146
187
- // The database field is already encoded in URL. Specifying it again in
188
- // the body is not necessary in production, and will cause duplicate field
189
- // errors in the Firestore Emulator. Let's remove it.
190
- const jsonObj = ( { ...request } as unknown ) as Indexable ;
191
- delete jsonObj . database ;
192
-
193
- const requestString = JSON . stringify ( jsonObj ) ;
194
- logDebug ( LOG_TAG , 'XHR sending: ' , url + ' ' + requestString ) ;
195
- // Content-Type: text/plain will avoid preflight requests which might
196
- // mess with CORS and redirects by proxies. If we add custom headers
197
- // we will need to change this code to potentially use the
198
- // $httpOverwrite parameter supported by ESF to avoid
199
- // triggering preflight requests.
200
- const headers : StringMap = { 'Content-Type' : 'text/plain' } ;
201
-
202
- this . modifyHeadersForRequest ( headers , token ) ;
203
-
147
+ const requestString = JSON . stringify ( body ) ;
204
148
xhr . send ( url , 'POST' , requestString , headers , XHR_TIMEOUT_SECS ) ;
205
149
} ) ;
206
150
}
207
151
208
- invokeStreamingRPC < Req , Resp > (
209
- rpcName : string ,
210
- request : Req ,
211
- token : Token | null
212
- ) : Promise < Resp [ ] > {
213
- // The REST API automatically aggregates all of the streamed results, so we
214
- // can just use the normal invoke() method.
215
- return this . invokeRPC < Req , Resp [ ] > ( rpcName , request , token ) ;
216
- }
217
-
218
152
openStream < Req , Resp > (
219
153
rpcName : string ,
220
154
token : Token | null
@@ -283,7 +217,7 @@ export class WebChannelConnection implements Connection {
283
217
}
284
218
285
219
const url = urlParts . join ( '' ) ;
286
- logDebug ( LOG_TAG , 'Creating WebChannel: ' + url + ' ' + request ) ;
220
+ logDebug ( LOG_TAG , 'Creating WebChannel: ' + url , request ) ;
287
221
const channel = webchannelTransport . createWebChannel ( url , request ) ;
288
222
289
223
// WebChannel supports sending the first message with the handshake - saving
@@ -420,24 +354,4 @@ export class WebChannelConnection implements Connection {
420
354
} , 0 ) ;
421
355
return streamBridge ;
422
356
}
423
-
424
- // visible for testing
425
- makeUrl ( rpcName : string ) : string {
426
- const urlRpcName = RPC_NAME_REST_MAPPING [ rpcName ] ;
427
- debugAssert (
428
- urlRpcName !== undefined ,
429
- 'Unknown REST mapping for: ' + rpcName
430
- ) ;
431
- return (
432
- this . baseUrl +
433
- '/' +
434
- RPC_URL_VERSION +
435
- '/projects/' +
436
- this . databaseId . projectId +
437
- '/databases/' +
438
- this . databaseId . database +
439
- '/documents:' +
440
- urlRpcName
441
- ) ;
442
- }
443
357
}
0 commit comments