Skip to content

Commit

Permalink
feat: Add support for conditional event source capabilities. (#577)
Browse files Browse the repository at this point in the history
This adds the ability to specify what capabilities an even source
supports.

The idea is, for something like report, the common code can check if the
event source supports it. If it is configured, and the event source
doesn't support it, then it can take appropriate action.

The browser SDK can calculate this at runtime by checking for a polyfill
and filling out the appropriate capabilities.
  • Loading branch information
kinyoklion authored Sep 11, 2024
1 parent a2f4398 commit fe82500
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ jest.mock('../src/platform', () => ({
requests: {
createEventSource: jest.fn(),
fetch: jest.fn(),
getEventSourceCapabilities: jest.fn(),
},
encoding: new PlatformEncoding(),
storage: new PlatformStorage(logger),
Expand Down Expand Up @@ -70,6 +71,7 @@ it('uses correct default diagnostic url', () => {
requests: {
createEventSource: jest.fn(),
fetch: mockedFetch,
getEventSourceCapabilities: jest.fn(),
},
encoding: new PlatformEncoding(),
storage: new PlatformStorage(logger),
Expand Down Expand Up @@ -97,6 +99,7 @@ it('uses correct default analytics event url', async () => {
requests: {
createEventSource: createMockEventSource,
fetch: mockedFetch,
getEventSourceCapabilities: jest.fn(),
},
encoding: new PlatformEncoding(),
storage: new PlatformStorage(logger),
Expand Down Expand Up @@ -128,6 +131,7 @@ it('uses correct default polling url', async () => {
requests: {
createEventSource: jest.fn(),
fetch: mockedFetch,
getEventSourceCapabilities: jest.fn(),
},
encoding: new PlatformEncoding(),
storage: new PlatformStorage(logger),
Expand Down Expand Up @@ -158,6 +162,7 @@ it('uses correct default streaming url', (done) => {
requests: {
createEventSource: mockedCreateEventSource,
fetch: jest.fn(),
getEventSourceCapabilities: jest.fn(),
},
encoding: new PlatformEncoding(),
storage: new PlatformStorage(logger),
Expand Down Expand Up @@ -197,6 +202,7 @@ it('includes authorization header for polling', async () => {
requests: {
createEventSource: jest.fn(),
fetch: mockedFetch,
getEventSourceCapabilities: jest.fn(),
},
encoding: new PlatformEncoding(),
storage: new PlatformStorage(logger),
Expand Down Expand Up @@ -231,6 +237,7 @@ it('includes authorization header for streaming', (done) => {
requests: {
createEventSource: mockedCreateEventSource,
fetch: jest.fn(),
getEventSourceCapabilities: jest.fn(),
},
encoding: new PlatformEncoding(),
storage: new PlatformStorage(logger),
Expand Down
9 changes: 9 additions & 0 deletions packages/sdk/react-native/src/platform/PlatformRequests.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {
EventName,
EventSource,
EventSourceCapabilities,
EventSourceInitDict,
LDLogger,
Options,
Expand All @@ -21,6 +22,14 @@ export default class PlatformRequests implements Requests {
});
}

getEventSourceCapabilities(): EventSourceCapabilities {
return {
readTimeout: false,
headers: true,
customMethod: true,
};
}

fetch(url: string, options?: Options): Promise<Response> {
// @ts-ignore
return fetch(url, options);
Expand Down
9 changes: 9 additions & 0 deletions packages/sdk/server-node/src/platform/NodeRequests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { HttpsProxyAgentOptions } from 'https-proxy-agent';
import { EventSource as LDEventSource } from 'launchdarkly-eventsource';

import {
EventSourceCapabilities,
LDLogger,
LDProxyOptions,
LDTLSOptions,
Expand Down Expand Up @@ -158,6 +159,14 @@ export default class NodeRequests implements platform.Requests {
return new LDEventSource(url, expandedOptions);
}

getEventSourceCapabilities(): EventSourceCapabilities {
return {
readTimeout: true,
headers: true,
customMethod: true,
};
}

usingProxy(): boolean {
return this.hasProxy;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { Headers, NullEventSource } from '@launchdarkly/js-server-sdk-common';
import type {
EventSource,
EventSourceCapabilities,
EventSourceInitDict,
Options,
Requests,
Expand Down Expand Up @@ -41,4 +42,12 @@ export default class EdgeRequests implements Requests {
createEventSource(url: string, eventSourceInitDict: EventSourceInitDict): EventSource {
return new NullEventSource(url, eventSourceInitDict);
}

getEventSourceCapabilities(): EventSourceCapabilities {
return {
readTimeout: false,
headers: false,
customMethod: false,
};
}
}
27 changes: 27 additions & 0 deletions packages/shared/common/src/api/platform/Requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,38 @@ export interface Options {
timeout?: number;
}

export interface EventSourceCapabilities {
/**
* If true the event source supports read timeouts. A read timeout for an
* event source represents the maximum time between receiving any data.
* If you receive 1 byte, and then a period of time greater than the read
* time out elapses, and you do not receive a second byte, then that would
* cause the event source to timeout.
*
* It is not a timeout for the read of the entire body, which should be
* indefinite.
*/
readTimeout: boolean;

/**
* If true the event source supports customized verbs POST/REPORT instead of
* only the default GET.
*/
customMethod: boolean;

/**
* If true the event source supports setting HTTP headers.
*/
headers: boolean;
}

export interface Requests {
fetch(url: string, options?: Options): Promise<Response>;

createEventSource(url: string, eventSourceInitDict: EventSourceInitDict): EventSource;

getEventSourceCapabilities(): EventSourceCapabilities;

/**
* Returns true if a proxy is configured.
*/
Expand Down
1 change: 1 addition & 0 deletions packages/shared/mocks/src/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const createBasicPlatform = () => ({
requests: {
fetch: jest.fn(),
createEventSource: jest.fn(),
getEventSourceCapabilities: jest.fn(),
},
storage: {
get: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ function makeMockPlatform(storage: Storage, crypto: Crypto): Platform {
requests: {
fetch: jest.fn(),
createEventSource: jest.fn(),
getEventSourceCapabilities: jest.fn(),
},
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { waitFor } from '@testing-library/dom';

import {
EventSource,
EventSourceCapabilities,
EventSourceInitDict,
Info,
PlatformData,
Expand Down Expand Up @@ -45,6 +46,13 @@ function makeRequests(): Requests {
createEventSource(_url: string, _eventSourceInitDict: EventSourceInitDict): EventSource {
throw new Error('Function not implemented.');
},
getEventSourceCapabilities(): EventSourceCapabilities {
return {
readTimeout: false,
headers: false,
customMethod: false,
};
},
};
}

Expand Down Expand Up @@ -169,6 +177,13 @@ it('stops polling when stopped', (done) => {
createEventSource(_url: string, _eventSourceInitDict: EventSourceInitDict): EventSource {
throw new Error('Function not implemented.');
},
getEventSourceCapabilities(): EventSourceCapabilities {
return {
readTimeout: false,
headers: false,
customMethod: false,
};
},
};
const dataCallback = jest.fn();
const errorCallback = jest.fn();
Expand Down
9 changes: 9 additions & 0 deletions packages/shared/sdk-server-edge/src/platform/requests.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { NullEventSource } from '@launchdarkly/js-server-sdk-common';
import type {
EventSource,
EventSourceCapabilities,
EventSourceInitDict,
Options,
Requests,
Expand All @@ -16,4 +17,12 @@ export default class EdgeRequests implements Requests {
createEventSource(url: string, eventSourceInitDict: EventSourceInitDict): EventSource {
return new NullEventSource(url, eventSourceInitDict);
}

getEventSourceCapabilities(): EventSourceCapabilities {
return {
readTimeout: false,
headers: false,
customMethod: false,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ describe('given a requestor', () => {
createEventSource(_url: string, _eventSourceInitDict: EventSourceInitDict): EventSource {
throw new Error('Function not implemented.');
},
getEventSourceCapabilities() {
throw new Error('Function not implemented.');
},
};

requestor = new Requestor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ function makePlatform(requestState: RequestState) {
createEventSource(_url: string, _eventSourceInitDict: EventSourceInitDict): EventSource {
throw new Error('Function not implemented.');
},
getEventSourceCapabilities() {
throw new Error('Function not implemented.');
},
};
return {
info,
Expand Down

0 comments on commit fe82500

Please sign in to comment.