Skip to content

Commit 46c46df

Browse files
Remove WebChannelConnection from Lite SDK
1 parent 94986e6 commit 46c46df

23 files changed

+725
-138
lines changed

packages/firestore/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"@firebase/webchannel-wrapper": "0.2.41",
6464
"@grpc/grpc-js": "^1.0.0",
6565
"@grpc/proto-loader": "^0.5.0",
66+
"axios": "^0.19.2",
6667
"tslib": "^1.11.1"
6768
},
6869
"peerDependencies": {

packages/firestore/src/platform/browser/webchannel_connection.ts

Lines changed: 20 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -35,79 +35,40 @@ import {
3535
} from '@firebase/util';
3636

3737
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';
4140
import {
4241
mapCodeFromRpcStatus,
4342
mapCodeFromHttpResponseErrorStatus
4443
} from '../../remote/rpc_error';
4544
import { StreamBridge } from '../../remote/stream_bridge';
46-
import { debugAssert, fail, hardAssert } from '../../util/assert';
45+
import { fail, hardAssert } from '../../util/assert';
4746
import { Code, FirestoreError } from '../../util/error';
4847
import { logDebug, logWarn } from '../../util/log';
49-
import { Indexable } from '../../util/misc';
5048
import { Rejecter, Resolver } from '../../util/promise';
5149
import { StringMap } from '../../util/types';
50+
import { RestConnection } from '../../remote/rest_connection';
5251

5352
const LOG_TAG = 'Connection';
5453

5554
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;
7155

7256
const XHR_TIMEOUT_SECS = 15;
7357

74-
export class WebChannelConnection implements Connection {
75-
private readonly databaseId: DatabaseId;
76-
private readonly baseUrl: string;
58+
export class WebChannelConnection extends RestConnection {
7759
private readonly forceLongPolling: boolean;
7860

7961
constructor(info: DatabaseInfo) {
80-
this.databaseId = info.databaseId;
81-
const proto = info.ssl ? 'https' : 'http';
82-
this.baseUrl = proto + '://' + info.host;
62+
super(info);
8363
this.forceLongPolling = info.forceLongPolling;
8464
}
8565

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>(
10567
rpcName: string,
106-
request: Req,
107-
token: Token | null
68+
url: string,
69+
headers: StringMap,
70+
body: Req
10871
): Promise<Resp> {
109-
const url = this.makeUrl(rpcName);
110-
11172
return new Promise((resolve: Resolver<Resp>, reject: Rejecter) => {
11273
const xhr = new XhrIo();
11374
xhr.listenOnce(EventType.COMPLETE, () => {
@@ -161,7 +122,6 @@ export class WebChannelConnection implements Connection {
161122
} else {
162123
// If we received an HTTP_ERROR but there's no status code,
163124
// it's most probably a connection issue
164-
logDebug(LOG_TAG, 'RPC "' + rpcName + '" failed');
165125
reject(
166126
new FirestoreError(Code.UNAVAILABLE, 'Connection failed.')
167127
);
@@ -170,51 +130,25 @@ export class WebChannelConnection implements Connection {
170130
default:
171131
fail(
172132
'RPC "' +
173-
rpcName +
174-
'" failed with unanticipated ' +
175-
'webchannel error ' +
176-
xhr.getLastErrorCode() +
177-
': ' +
178-
xhr.getLastError() +
179-
', giving up.'
133+
rpcName +
134+
'" failed with unanticipated ' +
135+
'webchannel error ' +
136+
xhr.getLastErrorCode() +
137+
': ' +
138+
xhr.getLastError() +
139+
', giving up.'
180140
);
181141
}
182142
} finally {
183143
logDebug(LOG_TAG, 'RPC "' + rpcName + '" completed.');
184144
}
185145
});
186146

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);
204148
xhr.send(url, 'POST', requestString, headers, XHR_TIMEOUT_SECS);
205149
});
206150
}
207-
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-
151+
218152
openStream<Req, Resp>(
219153
rpcName: string,
220154
token: Token | null
@@ -283,7 +217,7 @@ export class WebChannelConnection implements Connection {
283217
}
284218

285219
const url = urlParts.join('');
286-
logDebug(LOG_TAG, 'Creating WebChannel: ' + url + ' ' + request);
220+
logDebug(LOG_TAG, 'Creating WebChannel: ' + url, request);
287221
const channel = webchannelTransport.createWebChannel(url, request);
288222

289223
// WebChannel supports sending the first message with the handshake - saving
@@ -420,24 +354,4 @@ export class WebChannelConnection implements Connection {
420354
}, 0);
421355
return streamBridge;
422356
}
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-
}
443357
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
export * from '../browser/base64';
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { DatabaseInfo } from '../../core/database_info';
19+
import { Connection } from '../../remote/connection';
20+
import { FetchConnection } from './fetch_connection';
21+
22+
export { newConnectivityMonitor } from '../browser/connection';
23+
24+
/** Initializes the HTTP connection for the REST API. */
25+
export function newConnection(databaseInfo: DatabaseInfo): Promise<Connection> {
26+
return Promise.resolve(new FetchConnection(databaseInfo));
27+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
export * from '../browser/dom';
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { Token } from '../../api/credentials';
19+
import { Stream } from '../../remote/connection';
20+
import { mapCodeFromHttpStatus } from '../../remote/rpc_error';
21+
import { FirestoreError } from '../../util/error';
22+
import { StringMap } from '../../util/types';
23+
import { RestConnection } from '../../remote/rest_connection';
24+
25+
export class FetchConnection extends RestConnection {
26+
openStream<Req, Resp>(
27+
rpcName: string,
28+
token: Token | null
29+
): Stream<Req, Resp> {
30+
throw new Error('Not supported by FetchConnection');
31+
}
32+
33+
protected async performRPCRequest<Req, Resp>(
34+
rpcName: string,
35+
url: string,
36+
headers: StringMap,
37+
body: Req
38+
): Promise<Resp> {
39+
const requestJson = JSON.stringify(body);
40+
let response: Response;
41+
42+
try {
43+
response = await fetch(url, {
44+
method: 'POST',
45+
headers,
46+
body: requestJson
47+
});
48+
} catch (err) {
49+
throw new FirestoreError(
50+
mapCodeFromHttpStatus(err.status),
51+
'Request failed with error: ' + err.statusText
52+
);
53+
}
54+
55+
return JSON.parse(await response.text());
56+
}
57+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
export * from '../browser/format_json';
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
export * from '../browser/random_bytes';
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
/** Return the Platform-specific serializer monitor. */
19+
import { JsonProtoSerializer } from '../../remote/serializer';
20+
import { DatabaseId } from '../../core/database_info';
21+
22+
export function newSerializer(databaseId: DatabaseId): JsonProtoSerializer {
23+
return new JsonProtoSerializer(databaseId, /* useProto3Json= */ true);
24+
}

0 commit comments

Comments
 (0)