Skip to content

Commit a99048e

Browse files
committed
feat: Implement polling support. (#524)
1 parent f5b81e6 commit a99048e

File tree

14 files changed

+741
-58
lines changed

14 files changed

+741
-58
lines changed

packages/sdk/react-native/example/src/welcome.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export default function Welcome() {
1616
.catch((e: any) => console.error(`error identifying ${userKey}: ${e}`));
1717
};
1818

19+
1920
const setConnectionMode = (m: ConnectionMode) => {
2021
ldc.setConnectionMode(m);
2122
};
@@ -56,7 +57,13 @@ export default function Welcome() {
5657
style={styles.buttonContainer}
5758
onPress={() => setConnectionMode('streaming')}
5859
>
59-
<Text style={styles.buttonText}>Set online</Text>
60+
<Text style={styles.buttonText}>Set streaming</Text>
61+
</TouchableOpacity>
62+
<TouchableOpacity
63+
style={styles.buttonContainer}
64+
onPress={() => setConnectionMode('polling')}
65+
>
66+
<Text style={styles.buttonText}>Set polling</Text>
6067
</TouchableOpacity>
6168
</View>
6269
);

packages/sdk/react-native/src/RNStateDetector.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import { AppState, AppStateStatus } from 'react-native';
22

33
import { ApplicationState, NetworkState, StateDetector } from './platform/ConnectionManager';
44

5+
/**
6+
* @internal
7+
*/
58
function translateAppState(state: AppStateStatus): ApplicationState {
69
switch (state) {
710
case 'active':
@@ -14,6 +17,9 @@ function translateAppState(state: AppStateStatus): ApplicationState {
1417
}
1518
}
1619

20+
/**
21+
* @internal
22+
*/
1723
export default class RNStateDetector implements StateDetector {
1824
private applicationStateListener?: (state: ApplicationState) => void;
1925
private networkStateListener?: (state: NetworkState) => void;

packages/sdk/react-native/src/ReactNativeLDClient.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,16 @@ export default class ReactNativeLDClient extends LDClientImpl {
9898
super.setConnectionMode(mode);
9999
}
100100

101+
private encodeContext(context: LDContext) {
102+
return base64UrlEncode(JSON.stringify(context), this.platform.encoding!);
103+
}
104+
101105
override createStreamUriPath(context: LDContext) {
102-
return `/meval/${base64UrlEncode(JSON.stringify(context), this.platform.encoding!)}`;
106+
return `/meval/${this.encodeContext(context)}`;
107+
}
108+
109+
override createPollUriPath(context: LDContext): string {
110+
return `/msdk/evalx/contexts/${this.encodeContext(context)}`;
103111
}
104112

105113
override async setConnectionMode(mode: ConnectionMode): Promise<void> {

packages/sdk/react-native/src/platform/ConnectionManager.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { ConnectionMode, LDLogger } from '@launchdarkly/js-client-sdk-common';
22

3+
/**
4+
* @internal
5+
*/
36
export enum ApplicationState {
47
/// The application is in the foreground.
58
Foreground = 'foreground',
@@ -11,6 +14,9 @@ export enum ApplicationState {
1114
Background = 'background',
1215
}
1316

17+
/**
18+
* @internal
19+
*/
1420
export enum NetworkState {
1521
/// There is no network available for the SDK to use.
1622
Unavailable = 'unavailable',
@@ -20,19 +26,28 @@ export enum NetworkState {
2026
Available = 'available',
2127
}
2228

29+
/**
30+
* @internal
31+
*/
2332
export interface ConnectionDestination {
2433
setNetworkAvailability(available: boolean): void;
2534
setEventSendingEnabled(enabled: boolean, flush: boolean): void;
2635
setConnectionMode(mode: ConnectionMode): Promise<void>;
2736
}
2837

38+
/**
39+
* @internal
40+
*/
2941
export interface StateDetector {
3042
setApplicationStateListener(fn: (state: ApplicationState) => void): void;
3143
setNetworkStateListener(fn: (state: NetworkState) => void): void;
3244

3345
stopListening(): void;
3446
}
3547

48+
/**
49+
* @internal
50+
*/
3651
export interface ConnectionManagerConfig {
3752
/// The initial connection mode the SDK should use.
3853
readonly initialConnectionMode: ConnectionMode;
@@ -51,6 +66,9 @@ export interface ConnectionManagerConfig {
5166
readonly automaticBackgroundHandling: boolean;
5267
}
5368

69+
/**
70+
* @internal
71+
*/
5472
export class ConnectionManager {
5573
private applicationState: ApplicationState = ApplicationState.Foreground;
5674
private networkState: NetworkState = NetworkState.Available;

packages/shared/sdk-client/src/LDClientImpl.storage.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const onChangePromise = () =>
3737
});
3838

3939
// Common setup code for all tests
40-
// 1. Sets up streamer
40+
// 1. Sets up streaming
4141
// 2. Sets up the change listener
4242
// 3. Runs identify
4343
// 4. Get all flags
@@ -58,7 +58,7 @@ const identifyGetAllFlags = async (
5858
}
5959
jest.runAllTimers();
6060

61-
// if streamer errors, don't wait for 'change' because it will not be sent.
61+
// if streaming errors, don't wait for 'change' because it will not be sent.
6262
if (waitForChange && !shouldError) {
6363
await changePromise;
6464
}
@@ -91,8 +91,8 @@ describe('sdk-client storage', () => {
9191
jest.resetAllMocks();
9292
});
9393

94-
test('initialize from storage succeeds without streamer', async () => {
95-
// make sure streamer errors
94+
test('initialize from storage succeeds without streaming', async () => {
95+
// make sure streaming errors
9696
const allFlags = await identifyGetAllFlags(true, defaultPutResponse);
9797

9898
expect(basicPlatform.storage.get).toHaveBeenCalledWith('org:Testy Pizza');
@@ -185,7 +185,7 @@ describe('sdk-client storage', () => {
185185
expect(emitter.emit).not.toHaveBeenCalled();
186186
});
187187

188-
test('no storage, cold start from streamer', async () => {
188+
test('no storage, cold start from streaming', async () => {
189189
// fake previously cached flags even though there's no storage for this context
190190
// @ts-ignore
191191
ldc.flags = defaultPutResponse;
@@ -201,7 +201,7 @@ describe('sdk-client storage', () => {
201201
JSON.stringify(defaultPutResponse),
202202
);
203203
expect(ldc.logger.debug).toHaveBeenCalledWith(
204-
'OnIdentifyResolve no changes to emit from: streamer PUT.',
204+
'OnIdentifyResolve no changes to emit from: stream PUT.',
205205
);
206206

207207
// this is defaultPutResponse

packages/shared/sdk-client/src/LDClientImpl.timeout.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ describe('sdk-client identify timeout', () => {
3434
beforeEach(() => {
3535
defaultPutResponse = clone<Flags>(mockResponseJson);
3636

37-
// simulate streamer error after a long timeout
37+
// simulate streaming error after a long timeout
3838
setupMockStreamingProcessor(true, defaultPutResponse, undefined, undefined, 30);
3939

4040
ldc = new LDClientImpl(testSdkKey, AutoEnvAttributes.Enabled, basicPlatform, {
@@ -50,14 +50,14 @@ describe('sdk-client identify timeout', () => {
5050
jest.resetAllMocks();
5151
});
5252

53-
// streamer is setup to error in beforeEach to cause a timeout
53+
// streaming is setup to error in beforeEach to cause a timeout
5454
test('rejects with default timeout of 5s', async () => {
5555
jest.advanceTimersByTimeAsync(ldc.identifyTimeout * 1000).then();
5656
await expect(ldc.identify(carContext)).rejects.toThrow(/identify timed out/);
5757
expect(logger.error).toHaveBeenCalledWith(expect.stringMatching(/identify timed out/));
5858
});
5959

60-
// streamer is setup to error in beforeEach to cause a timeout
60+
// streaming is setup to error in beforeEach to cause a timeout
6161
test('rejects with custom timeout', async () => {
6262
const timeout = 15;
6363
jest.advanceTimersByTimeAsync(timeout * 1000).then();

0 commit comments

Comments
 (0)