Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions src/services/__tests__/splitApi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,25 @@ describe('splitApi', () => {
assertHeaders(settings, headers);
expect(url).toBe(expectedConfigsUrl(-1, 100, settings.validateFilters || false, settings));

splitApi.fetchConfigsSegmentChanges(-1, 'segmentName', false, 100);
[url, { headers }] = fetchMock.mock.calls[5];
assertHeaders(settings, headers);
expect(url).toBe('configs/v1/segmentChanges/segmentName?since=-1&till=100');

splitApi.postEventsBulk('fake-body');
assertHeaders(settings, fetchMock.mock.calls[5][1].headers);
assertHeaders(settings, fetchMock.mock.calls[6][1].headers);

splitApi.postTestImpressionsBulk('fake-body');
assertHeaders(settings, fetchMock.mock.calls[6][1].headers);
expect(fetchMock.mock.calls[6][1].headers['SplitSDKImpressionsMode']).toBe(settings.sync.impressionsMode);
assertHeaders(settings, fetchMock.mock.calls[7][1].headers);
expect(fetchMock.mock.calls[7][1].headers['SplitSDKImpressionsMode']).toBe(settings.sync.impressionsMode);

splitApi.postTestImpressionsCount('fake-body');
assertHeaders(settings, fetchMock.mock.calls[7][1].headers);
assertHeaders(settings, fetchMock.mock.calls[8][1].headers);

splitApi.postMetricsConfig('fake-body');
assertHeaders(settings, fetchMock.mock.calls[8][1].headers);
splitApi.postMetricsUsage('fake-body');
assertHeaders(settings, fetchMock.mock.calls[9][1].headers);
splitApi.postMetricsUsage('fake-body');
assertHeaders(settings, fetchMock.mock.calls[10][1].headers);

expect(telemetryTrackerMock.trackHttp).toBeCalledTimes(9);

Expand All @@ -78,7 +83,7 @@ describe('splitApi', () => {

function expectedConfigsUrl(since: number, till: number, usesFilter: boolean, settings: ISettings) {
const filterQueryString = settings.sync.__splitFiltersValidation && settings.sync.__splitFiltersValidation.queryString;
return `sdk/v1/configs?since=${since}${usesFilter ? filterQueryString : ''}${till ? '&till=' + till : ''}`;
return `configs/v1/configs?since=${since}${usesFilter ? filterQueryString : ''}${till ? '&till=' + till : ''}`;
}
});

Expand Down
13 changes: 9 additions & 4 deletions src/services/splitApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,20 @@ export function splitApiFactory(
});
},

fetchSegmentChanges(since: number, segmentName: string, noCache?: boolean, till?: number) {
const url = `${urls.sdk}/segmentChanges/${segmentName}?since=${since}${till ? '&till=' + till : ''}`;
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SEGMENT));
},

// @TODO support filterQueryString and handle ERROR_TOO_MANY_SETS error
fetchConfigs(since: number, noCache?: boolean, till?: number) {
const url = `${urls.sdk}/v1/configs?since=${since}${filterQueryString || ''}${till ? '&till=' + till : ''}`;
const url = `${urls.configs}/v1/configs?since=${since}${filterQueryString || ''}${till ? '&till=' + till : ''}`;
return (secureSplitHttpClient || splitHttpClient)(url, noCache ? noCacheHeaderOptions : undefined);
},

fetchSegmentChanges(since: number, segmentName: string, noCache?: boolean, till?: number) {
const url = `${urls.sdk}/segmentChanges/${segmentName}?since=${since}${till ? '&till=' + till : ''}`;
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SEGMENT));
fetchConfigsSegmentChanges(since: number, segmentName: string, noCache?: boolean, till?: number) {
const url = `${urls.configs}/v1/segmentChanges/${segmentName}?since=${since}${till ? '&till=' + till : ''}`;
return (secureSplitHttpClient || splitHttpClient)(url, noCache ? noCacheHeaderOptions : undefined);
},

fetchMemberships(userMatchingKey: string, noCache?: boolean, till?: number) {
Expand Down
3 changes: 2 additions & 1 deletion src/services/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ export interface ISplitApi {
getEventsAPIHealthCheck: IHealthCheckAPI
fetchAuth: IFetchAuth
fetchSplitChanges: IFetchDefinitionChanges
fetchConfigs: IFetchDefinitionChanges
fetchSegmentChanges: IFetchSegmentChanges
fetchConfigs: IFetchDefinitionChanges
fetchConfigsSegmentChanges: IFetchSegmentChanges
fetchMemberships: IFetchMemberships
postEventsBulk: IPostEventsBulk
postUniqueKeysBulkCs: IPostUniqueKeysBulkCs
Expand Down
9 changes: 5 additions & 4 deletions src/sync/polling/pollingManagerSS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@ import { segmentsSyncTaskFactory } from './syncTasks/segmentsSyncTask';
import { IPollingManager, ISegmentsSyncTask, IDefinitionsSyncTask } from './types';
import { POLLING_START, POLLING_STOP, LOG_PREFIX_SYNC_POLLING } from '../../logger/constants';
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
import { IDefinitionChangesFetcher } from './fetchers/types';
import { IDefinitionChangesFetcher, ISegmentChangesFetcher } from './fetchers/types';

/**
* Expose start / stop mechanism for pulling data from services.
*/
export function pollingManagerSSFactory(
params: ISdkFactoryContextSync,
definitionChangesFetcher: IDefinitionChangesFetcher
definitionChangesFetcher: IDefinitionChangesFetcher,
segmentChangesFetcher: ISegmentChangesFetcher
): IPollingManager {

const { splitApi, storage, readiness, settings } = params;
const { storage, readiness, settings } = params;
const log = settings.log;

const definitionsSyncTask: IDefinitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings);
const segmentsSyncTask: ISegmentsSyncTask = segmentsSyncTaskFactory(splitApi.fetchSegmentChanges, storage, readiness, settings);
const segmentsSyncTask: ISegmentsSyncTask = segmentsSyncTaskFactory(segmentChangesFetcher, storage, readiness, settings);

return {
definitionsSyncTask,
Expand Down
7 changes: 3 additions & 4 deletions src/sync/polling/syncTasks/segmentsSyncTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ import { IStorageSync } from '../../../storages/types';
import { IReadinessManager } from '../../../readiness/types';
import { syncTaskFactory } from '../../syncTask';
import { ISegmentsSyncTask } from '../types';
import { segmentChangesFetcherFactory } from '../fetchers/segmentChangesFetcher';
import { IFetchSegmentChanges } from '../../../services/types';
import { ISettings } from '../../../types';
import { segmentChangesUpdaterFactory } from '../updaters/segmentChangesUpdater';
import { ISegmentChangesFetcher } from '../fetchers/types';

/**
* Creates a sync task that periodically executes a `segmentChangesUpdater` task
*/
export function segmentsSyncTaskFactory(
fetchSegmentChanges: IFetchSegmentChanges,
segmentChangesFetcher: ISegmentChangesFetcher,
storage: IStorageSync,
readiness: IReadinessManager,
settings: ISettings,
Expand All @@ -20,7 +19,7 @@ export function segmentsSyncTaskFactory(
settings.log,
segmentChangesUpdaterFactory(
settings.log,
segmentChangesFetcherFactory(fetchSegmentChanges),
segmentChangesFetcher,
storage.segments,
readiness,
settings.startup.requestTimeoutBeforeReady,
Expand Down
12 changes: 7 additions & 5 deletions src/sync/syncManagerOnline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import { ISdkFactoryContextSync } from '../sdkFactory/types';
import { SDK_DEFINITIONS_CACHE_LOADED } from '../readiness/constants';
import { usesSegmentsSync } from '../storages/AbstractDefinitionsCacheSync';
import { splitChangesFetcherFactory } from './polling/fetchers/splitChangesFetcher';
import { IDefinitionChangesFetcher } from './polling/fetchers/types';
import { IDefinitionChangesFetcher, ISegmentChangesFetcher } from './polling/fetchers/types';
import { segmentChangesFetcherFactory } from './polling/fetchers/segmentChangesFetcher';

/**
* Online SyncManager factory.
Expand All @@ -24,9 +25,10 @@ import { IDefinitionChangesFetcher } from './polling/fetchers/types';
* @param definitionChangesFetcherFactory - optional to replace the default split changes fetcher
*/
export function syncManagerOnlineFactory(
pollingManagerFactory?: (params: ISdkFactoryContextSync, definitionChangesFetcher: IDefinitionChangesFetcher) => IPollingManager,
pollingManagerFactory?: (params: ISdkFactoryContextSync, definitionChangesFetcher: IDefinitionChangesFetcher, segmentChangesFetcher: ISegmentChangesFetcher) => IPollingManager,
pushManagerFactory?: (params: ISdkFactoryContextSync, pollingManager: IPollingManager) => IPushManager | undefined,
definitionChangesFetcherFactory = splitChangesFetcherFactory
definitionFetcherFactory = splitChangesFetcherFactory,
segmentFetcherFactory = (params: ISdkFactoryContextSync) => segmentChangesFetcherFactory(params.splitApi.fetchSegmentChanges)
): (params: ISdkFactoryContextSync) => ISyncManagerCS {

/**
Expand All @@ -37,15 +39,15 @@ export function syncManagerOnlineFactory(
const { settings, settings: { log, streamingEnabled, sync: { enabled: syncEnabled } }, telemetryTracker, storage, readiness } = params;

/** Polling Manager */
const pollingManager = pollingManagerFactory && pollingManagerFactory(params, definitionChangesFetcherFactory(params));
const pollingManager = pollingManagerFactory && pollingManagerFactory(params, definitionFetcherFactory(params), segmentFetcherFactory(params));

/** Push Manager */
const pushManager = syncEnabled && streamingEnabled && pollingManager && pushManagerFactory ?
pushManagerFactory(params, pollingManager) :
undefined;

/** Submitter Manager */
// It is not inyected as push and polling managers, because at the moment it is required
// It is not injected as push and polling managers, because at the moment it is required
const submitterManager = submitterManagerFactory(params);

/** Sync Manager logic */
Expand Down
2 changes: 2 additions & 0 deletions src/utils/settingsValidation/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ describe('settingsValidation', () => {
auth: 'https://auth.split.io/api',
streaming: 'https://streaming.split.io',
telemetry: 'https://telemetry.split.io/api',
configs: 'https://configs.split.io/api',
});
expect(settings.sync.impressionsMode).toBe(OPTIMIZED);
expect(settings.sync.enabled).toBe(true);
Expand Down Expand Up @@ -82,6 +83,7 @@ describe('settingsValidation', () => {
auth: 'auth-url',
streaming: 'streaming-url',
telemetry: 'telemetry-url',
configs: 'configs-url',
};

const settings = settingsValidation({
Expand Down
6 changes: 4 additions & 2 deletions src/utils/settingsValidation/__tests__/settings.mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ export const fullSettings: ISettings = {
events: 'https://events.split.io/api',
auth: 'https://auth.split.io/api',
streaming: 'https://streaming.split.io',
telemetry: 'https://telemetry.split.io/api'
telemetry: 'https://telemetry.split.io/api',
configs: 'https://configs.split.io/api'
},
log: loggerMock,
userConsent: undefined
Expand All @@ -105,7 +106,8 @@ export const settingsSplitApi = {
sdk: 'sdk',
auth: 'auth',
streaming: 'streaming',
telemetry: 'telemetry'
telemetry: 'telemetry',
configs: 'configs'
},
sync: {
impressionsMode: 'DEBUG',
Expand Down
2 changes: 2 additions & 0 deletions src/utils/settingsValidation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ export const base = {
streaming: 'https://streaming.split.io',
// Telemetry Server
telemetry: 'https://telemetry.split.io/api',
// Configs Server
configs: 'https://configs.split.io/api',
},

// Defines which kind of storage we should instantiate.
Expand Down
6 changes: 5 additions & 1 deletion src/utils/settingsValidation/url.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ISettings } from '../../types';

const telemetryEndpointMatcher = /^\/v1\/metrics\/(config|usage)/;
const telemetryEndpointMatcher = /^\/v1\/(metrics|keys)\/(config|usage|ss|cs)/;
const eventsEndpointMatcher = /^\/(testImpressions|metrics|events)/;
const authEndpointMatcher = /^\/(v2|v3)\/auth/;
const streamingEndpointMatcher = /^\/(sse|event-stream)/;
const configsEndpointMatcher = /^\/v1\/(configs|segmentChanges)/;

/**
* Get URL based on a given target (path).
Expand All @@ -26,5 +27,8 @@ export function url(settings: ISettings, target: string) {
if (streamingEndpointMatcher.test(target)) {
return `${settings.urls.streaming}${target}`;
}
if (configsEndpointMatcher.test(target)) {
return `${settings.urls.configs}${target}`;
}
return `${settings.urls.sdk}${target}`;
}
7 changes: 4 additions & 3 deletions types/splitio.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,7 @@ declare namespace SplitIO {
auth: string;
streaming: string;
telemetry: string;
configs: string;
};
readonly integrations?: IntegrationFactory[];
readonly logger?: Logger;
Expand Down Expand Up @@ -2356,11 +2357,11 @@ declare namespace SplitIO {
*/
auth?: string;
/**
* String property to override the base URL where the SDK will get rollout plan related data, like feature flags and segments definitions.
* String property to override the base URL where the SDK will get rollout plan related data, like configs and segments definitions.
*
* @defaultValue `'https://appconfig.split.io/api'`
* @defaultValue `'https://configs.split.io/api'`
*/
sdk?: string;
configs?: string;
/**
* String property to override the base URL where the SDK will post event-related information like impressions.
*
Expand Down