Skip to content

Commit 4f997bc

Browse files
Adding experimentalAutoDetectLongPolling (#3724)
* Upgrade to latest version of closure * Adding changeset * Updating changeset message * Fixing stylization in changeset copy * WIP * Updating to match new patterns * Making member names match conventions on others * Making the linter happy * Fixing bug caught by unit tests and misc polish * Turning auto detection on by default * Turning auto detection on by default * Update packages/firestore/src/util/input_validation.ts Co-authored-by: Sebastian Schmidt <[email protected]> * Update packages/firebase/index.d.ts Co-authored-by: Sebastian Schmidt <[email protected]> * Changing default to false * Fixing grammar * Adding integration test * Undoing formatting changes * Resetting hard code to false * Update packages/firestore/src/core/database_info.ts Co-authored-by: Sebastian Schmidt <[email protected]> * Update packages/firestore/test/integration/api/database.test.ts Co-authored-by: Sebastian Schmidt <[email protected]> * Create yellow-turkeys-lay.md * Update .changeset/yellow-turkeys-lay.md Co-authored-by: Sebastian Schmidt <[email protected]> * Update .changeset/yellow-turkeys-lay.md Co-authored-by: Sebastian Schmidt <[email protected]> * Update index.d.ts Adding back-ticks for literal * Update yellow-turkeys-lay.md Bumping firebase minor version * Updating unit test to contain proper error string Co-authored-by: Sebastian Schmidt <[email protected]>
1 parent 5af6e1c commit 4f997bc

File tree

15 files changed

+132
-14
lines changed

15 files changed

+132
-14
lines changed

.changeset/yellow-turkeys-lay.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"@firebase/firestore-types": minor
3+
"@firebase/firestore": minor
4+
"@firebase/webchannel-wrapper": minor
5+
"firebase": minor
6+
---
7+
8+
Adds a new `experimentalAutoDetectLongPolling` to FirestoreSettings. When
9+
enabled, the SDK's underlying transport (WebChannel) automatically detects if
10+
long-polling should be used. This is very similar to
11+
`experimentalForceLongPolling`, but only uses long-polling if required.

packages/firebase/index.d.ts

+16-4
Original file line numberDiff line numberDiff line change
@@ -7879,15 +7879,27 @@ declare namespace firebase.firestore {
78797879
* buffer traffic indefinitely. Use of this option will cause some
78807880
* performance degradation though.
78817881
*
7882-
* This setting may be removed in a future release. If you find yourself
7883-
* using it to work around a specific network reliability issue, please
7884-
* tell us about it in
7885-
* https://github.com/firebase/firebase-js-sdk/issues/1674.
7882+
* This setting cannot be used with `experimentalAutoDetectLongPolling` and
7883+
* may be removed in a future release. If you find yourself using it to
7884+
* work around a specific network reliability issue, please tell us about
7885+
* it in https://github.com/firebase/firebase-js-sdk/issues/1674.
78867886
*
78877887
* @webonly
78887888
*/
78897889
experimentalForceLongPolling?: boolean;
78907890

7891+
/**
7892+
* Configures the SDK's underlying transport (WebChannel) to automatically detect if
7893+
* long-polling should be used. This is very similar to `experimentalForceLongPolling`,
7894+
* but only uses long-polling if required.
7895+
*
7896+
* This setting will likely be enabled by default in future releases and cannot be
7897+
* combined with `experimentalForceLongPolling`.
7898+
*
7899+
* @webonly
7900+
*/
7901+
experimentalAutoDetectLongPolling?: boolean;
7902+
78917903
/**
78927904
* Whether to skip nested properties that are set to `undefined` during
78937905
* object serialization. If set to `true`, these properties are skipped

packages/firestore-types/index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface Settings {
2929
timestampsInSnapshots?: boolean;
3030
cacheSizeBytes?: number;
3131
experimentalForceLongPolling?: boolean;
32+
experimentalAutoDetectLongPolling?: boolean;
3233
ignoreUndefinedProperties?: boolean;
3334
merge?: boolean;
3435
}

packages/firestore/exp/src/api/database.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ export class FirebaseFirestore
121121
this._persistenceKey,
122122
settings.host ?? DEFAULT_HOST,
123123
settings.ssl ?? DEFAULT_SSL,
124-
/* forceLongPolling= */ false
124+
/* forceLongPolling= */ false,
125+
/* forceAutoDetectLongPolling= */ true
125126
);
126127
return {
127128
asyncQueue: this._queue,

packages/firestore/lite/src/api/components.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ export function getDatastore(firestore: FirebaseFirestore): Datastore {
5959
firestore._persistenceKey,
6060
settings.host ?? DEFAULT_HOST,
6161
settings.ssl ?? DEFAULT_SSL,
62-
/* forceLongPolling= */ false
62+
/* forceLongPolling= */ false,
63+
/* forceAutoDetectLongPolling= */ true
6364
);
6465

6566
const connection = newConnection(databaseInfo);

packages/firestore/src/api/database.ts

+27-2
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ import {
106106
validateOptionNames,
107107
validatePositiveNumber,
108108
validateStringEnum,
109-
valueDescription
109+
valueDescription,
110+
validateIsNotUsedTogether
110111
} from '../util/input_validation';
111112
import { getLogLevel, logError, LogLevel, setLogLevel } from '../util/log';
112113
import { AutoId } from '../util/misc';
@@ -146,6 +147,7 @@ const DEFAULT_HOST = 'firestore.googleapis.com';
146147
const DEFAULT_SSL = true;
147148
const DEFAULT_TIMESTAMPS_IN_SNAPSHOTS = true;
148149
const DEFAULT_FORCE_LONG_POLLING = false;
150+
const DEFAULT_FORCE_AUTO_DETECT_LONG_POLLING = false;
149151
const DEFAULT_IGNORE_UNDEFINED_PROPERTIES = false;
150152

151153
/**
@@ -191,6 +193,8 @@ class FirestoreSettings {
191193

192194
readonly experimentalForceLongPolling: boolean;
193195

196+
readonly experimentalAutoDetectLongPolling: boolean;
197+
194198
readonly ignoreUndefinedProperties: boolean;
195199

196200
// Can be a google-auth-library or gapi client.
@@ -221,6 +225,7 @@ class FirestoreSettings {
221225
'timestampsInSnapshots',
222226
'cacheSizeBytes',
223227
'experimentalForceLongPolling',
228+
'experimentalAutoDetectLongPolling',
224229
'ignoreUndefinedProperties'
225230
]);
226231

@@ -294,6 +299,23 @@ class FirestoreSettings {
294299
);
295300
this.experimentalForceLongPolling =
296301
settings.experimentalForceLongPolling ?? DEFAULT_FORCE_LONG_POLLING;
302+
303+
validateNamedOptionalType(
304+
'settings',
305+
'boolean',
306+
'experimentalAutoDetectLongPolling',
307+
settings.experimentalAutoDetectLongPolling
308+
);
309+
this.experimentalAutoDetectLongPolling =
310+
settings.experimentalAutoDetectLongPolling ??
311+
DEFAULT_FORCE_AUTO_DETECT_LONG_POLLING;
312+
313+
validateIsNotUsedTogether(
314+
'experimentalForceLongPolling',
315+
settings.experimentalForceLongPolling,
316+
'experimentalAutoDetectLongPolling',
317+
settings.experimentalAutoDetectLongPolling
318+
);
297319
}
298320

299321
isEqual(other: FirestoreSettings): boolean {
@@ -305,6 +327,8 @@ class FirestoreSettings {
305327
this.cacheSizeBytes === other.cacheSizeBytes &&
306328
this.experimentalForceLongPolling ===
307329
other.experimentalForceLongPolling &&
330+
this.experimentalAutoDetectLongPolling ===
331+
other.experimentalAutoDetectLongPolling &&
308332
this.ignoreUndefinedProperties === other.ignoreUndefinedProperties
309333
);
310334
}
@@ -552,7 +576,8 @@ export class Firestore implements PublicFirestore, FirebaseService {
552576
this._persistenceKey,
553577
this._settings.host,
554578
this._settings.ssl,
555-
this._settings.experimentalForceLongPolling
579+
this._settings.experimentalForceLongPolling,
580+
this._settings.experimentalAutoDetectLongPolling
556581
);
557582
}
558583

packages/firestore/src/core/database_info.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,16 @@ export class DatabaseInfo {
2929
* @param ssl Whether to use SSL when connecting.
3030
* @param forceLongPolling Whether to use the forceLongPolling option
3131
* when using WebChannel as the network transport.
32+
* @param autoDetectLongPolling Whether to use the detectBufferingProxy
33+
* option when using WebChannel as the network transport.
3234
*/
3335
constructor(
3436
readonly databaseId: DatabaseId,
3537
readonly persistenceKey: string,
3638
readonly host: string,
3739
readonly ssl: boolean,
38-
readonly forceLongPolling: boolean
40+
readonly forceLongPolling: boolean,
41+
readonly autoDetectLongPolling: boolean
3942
) {}
4043
}
4144

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,12 @@ const XHR_TIMEOUT_SECS = 15;
5757

5858
export class WebChannelConnection extends RestConnection {
5959
private readonly forceLongPolling: boolean;
60+
private readonly autoDetectLongPolling: boolean;
6061

6162
constructor(info: DatabaseInfo) {
6263
super(info);
6364
this.forceLongPolling = info.forceLongPolling;
65+
this.autoDetectLongPolling = info.autoDetectLongPolling;
6466
}
6567

6668
protected performRPCRequest<Req, Resp>(
@@ -183,7 +185,8 @@ export class WebChannelConnection extends RestConnection {
183185
// timeouts to kick in if the request isn't working.
184186
forwardChannelRequestTimeoutMs: 10 * 60 * 1000
185187
},
186-
forceLongPolling: this.forceLongPolling
188+
forceLongPolling: this.forceLongPolling,
189+
detectBufferingProxy: this.autoDetectLongPolling
187190
};
188191

189192
this.modifyHeadersForRequest(request.initMessageHeaders!, token);

packages/firestore/src/util/input_validation.ts

+17
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,23 @@ export function validateNamedOptionalType(
199199
}
200200
}
201201

202+
/**
203+
* Validates that two boolean options are not set at the same time.
204+
*/
205+
export function validateIsNotUsedTogether(
206+
optionName1: string,
207+
argument1: boolean | undefined,
208+
optionName2: string,
209+
argument2: boolean | undefined
210+
): void {
211+
if (argument1 === true && argument2 === true) {
212+
throw new FirestoreError(
213+
Code.INVALID_ARGUMENT,
214+
`${optionName1} and ${optionName2} cannot be used together.`
215+
);
216+
}
217+
}
218+
202219
export function validateArrayElements<T>(
203220
functionName: string,
204221
optionName: string,

packages/firestore/test/integration/api/database.test.ts

+28-1
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@ import * as firebaseExport from '../util/firebase_export';
2626
import {
2727
apiDescribe,
2828
withTestCollection,
29+
withTestDbsSettings,
2930
withTestDb,
3031
withTestDbs,
3132
withTestDoc,
3233
withTestDocAndInitialData
3334
} from '../util/helpers';
34-
import { DEFAULT_SETTINGS } from '../util/settings';
35+
import { DEFAULT_SETTINGS, DEFAULT_PROJECT_ID } from '../util/settings';
3536

3637
use(chaiAsPromised);
3738

@@ -1600,4 +1601,30 @@ apiDescribe('Database', (persistence: boolean) => {
16001601
});
16011602
});
16021603
});
1604+
1605+
it('can set and get data with auto detect long polling enabled', () => {
1606+
const settings = {
1607+
...DEFAULT_SETTINGS,
1608+
experimentalAutoDetectLongPolling: true
1609+
};
1610+
1611+
return withTestDbsSettings(
1612+
persistence,
1613+
DEFAULT_PROJECT_ID,
1614+
settings,
1615+
1,
1616+
async ([db]) => {
1617+
const data = { name: 'Rafi', email: '[email protected]' };
1618+
const doc = await db.collection('users').doc();
1619+
1620+
return doc
1621+
.set(data)
1622+
.then(() => doc.get())
1623+
.then(snapshot => {
1624+
expect(snapshot.exists).to.be.ok;
1625+
expect(snapshot.data()).to.deep.equal(data);
1626+
});
1627+
}
1628+
);
1629+
});
16031630
});

packages/firestore/test/integration/util/internal_helpers.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ export function getDefaultDatabaseInfo(): DatabaseInfo {
4444
'persistenceKey',
4545
DEFAULT_SETTINGS.host!,
4646
!!DEFAULT_SETTINGS.ssl,
47-
!!DEFAULT_SETTINGS.experimentalForceLongPolling
47+
!!DEFAULT_SETTINGS.experimentalForceLongPolling,
48+
!!DEFAULT_SETTINGS.experimentalAutoDetectLongPolling
4849
);
4950
}
5051

packages/firestore/test/unit/api/database.test.ts

+13
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,19 @@ describe('Settings', () => {
170170
);
171171
});
172172

173+
it('can not use mutually exclusive settings together', () => {
174+
// Use a new instance of Firestore in order to configure settings.
175+
const firestoreClient = newTestFirestore();
176+
expect(
177+
firestoreClient.settings.bind(firestoreClient.settings, {
178+
experimentalForceLongPolling: true,
179+
experimentalAutoDetectLongPolling: true
180+
})
181+
).to.throw(
182+
`experimentalForceLongPolling and experimentalAutoDetectLongPolling cannot be used together.`
183+
);
184+
});
185+
173186
it('can merge settings', () => {
174187
// Use a new instance of Firestore in order to configure settings.
175188
const firestoreClient = newTestFirestore();

packages/firestore/test/unit/remote/rest_connection.test.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ describe('RestConnection', () => {
6060
'persistenceKey',
6161
'example.com',
6262
/*ssl=*/ false,
63-
/*forceLongPolling=*/ false
63+
/*forceLongPolling=*/ false,
64+
/*autoDetectLongPolling=*/ false
6465
);
6566
const connection = new TestRestConnection(testDatabaseInfo);
6667

packages/firestore/test/unit/specs/spec_test_runner.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,8 @@ abstract class TestRunner {
241241
TEST_PERSISTENCE_KEY,
242242
'host',
243243
/*ssl=*/ false,
244-
/*forceLongPolling=*/ false
244+
/*forceLongPolling=*/ false,
245+
/*autoDetectLongPolling=*/ false
245246
);
246247

247248
// TODO(mrschmidt): During client startup in `firestore_client`, we block

packages/webchannel-wrapper/src/index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export interface WebChannelOptions {
8989
httpSessionIdParam?: string;
9090
httpHeadersOverwriteParam?: string;
9191
forceLongPolling?: boolean;
92+
detectBufferingProxy?: boolean;
9293
fastHandshake?: boolean;
9394
disableRedac?: boolean;
9495
clientProfile?: string;

0 commit comments

Comments
 (0)