From 2836af347e2d21ca98ca3b86860f37855f86ef71 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 15 Apr 2025 13:49:49 -0300 Subject: [PATCH] Add checkIfServerSide utility function and update client and server-side detection --- src/storages/inMemory/TelemetryCacheInMemory.ts | 3 ++- src/storages/pluggable/index.ts | 3 ++- src/sync/polling/fetchers/splitChangesFetcher.ts | 3 ++- src/sync/streaming/SSEClient/index.ts | 3 ++- src/sync/streaming/pushManager.ts | 4 ++-- src/sync/submitters/telemetrySubmitter.ts | 7 ++++--- src/utils/key/index.ts | 5 +++++ 7 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/storages/inMemory/TelemetryCacheInMemory.ts b/src/storages/inMemory/TelemetryCacheInMemory.ts index 7e7e3f98..b6247f18 100644 --- a/src/storages/inMemory/TelemetryCacheInMemory.ts +++ b/src/storages/inMemory/TelemetryCacheInMemory.ts @@ -1,5 +1,6 @@ import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies, StreamingEvent, Method, OperationType, MethodExceptions, MethodLatencies, TelemetryUsageStatsPayload, UpdatesFromSSEEnum, UpdatesFromSSE } from '../../sync/submitters/types'; import { DEDUPED, DROPPED, LOCALHOST_MODE, QUEUED } from '../../utils/constants'; +import { checkIfServerSide } from '../../utils/key'; import { findLatencyIndex } from '../findLatencyIndex'; import { ISegmentsCacheSync, ISplitsCacheSync, IStorageFactoryParams, ITelemetryCacheSync } from '../types'; @@ -20,7 +21,7 @@ const ACCEPTANCE_RANGE = 0.001; * All factory instances track telemetry on server-side, and 0.1% on client-side. */ export function shouldRecordTelemetry({ settings }: IStorageFactoryParams) { - return settings.mode !== LOCALHOST_MODE && (settings.core.key === undefined || Math.random() <= ACCEPTANCE_RANGE); + return settings.mode !== LOCALHOST_MODE && (checkIfServerSide(settings) || Math.random() <= ACCEPTANCE_RANGE); } export class TelemetryCacheInMemory implements ITelemetryCacheSync { diff --git a/src/storages/pluggable/index.ts b/src/storages/pluggable/index.ts index a5dba66e..7f020fa6 100644 --- a/src/storages/pluggable/index.ts +++ b/src/storages/pluggable/index.ts @@ -21,6 +21,7 @@ import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS import { metadataBuilder } from '../utils'; import { LOG_PREFIX } from '../pluggable/constants'; import { RBSegmentsCachePluggable } from './RBSegmentsCachePluggable'; +import { checkIfServerSide } from '../../utils/key'; const NO_VALID_WRAPPER = 'Expecting pluggable storage `wrapper` in options, but no valid wrapper instance was provided.'; const NO_VALID_WRAPPER_INTERFACE = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.'; @@ -83,7 +84,7 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn new ImpressionCountsCachePluggable(log, keys.buildImpressionsCountKey(), wrapper); const uniqueKeysCache = isPartialConsumer ? - settings.core.key === undefined ? new UniqueKeysCacheInMemory() : new UniqueKeysCacheInMemoryCS() : + checkIfServerSide(settings) ? new UniqueKeysCacheInMemory() : new UniqueKeysCacheInMemoryCS() : new UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper); // Connects to wrapper and emits SDK_READY event on main client diff --git a/src/sync/polling/fetchers/splitChangesFetcher.ts b/src/sync/polling/fetchers/splitChangesFetcher.ts index 58f87e9a..b109eaec 100644 --- a/src/sync/polling/fetchers/splitChangesFetcher.ts +++ b/src/sync/polling/fetchers/splitChangesFetcher.ts @@ -6,6 +6,7 @@ import { FLAG_SPEC_VERSION } from '../../../utils/constants'; import { base } from '../../../utils/settingsValidation'; import { ISplitChangesFetcher } from './types'; import { LOG_PREFIX_SYNC_SPLITS } from '../../../logger/constants'; +import { checkIfServerSide } from '../../../utils/key'; const PROXY_CHECK_INTERVAL_MILLIS_CS = 60 * 60 * 1000; // 1 hour in Client Side const PROXY_CHECK_INTERVAL_MILLIS_SS = 24 * PROXY_CHECK_INTERVAL_MILLIS_CS; // 24 hours in Server Side @@ -22,7 +23,7 @@ function sdkEndpointOverriden(settings: ISettings) { export function splitChangesFetcherFactory(fetchSplitChanges: IFetchSplitChanges, settings: ISettings, storage: Pick): ISplitChangesFetcher { const log = settings.log; - const PROXY_CHECK_INTERVAL_MILLIS = settings.core.key !== undefined ? PROXY_CHECK_INTERVAL_MILLIS_CS : PROXY_CHECK_INTERVAL_MILLIS_SS; + const PROXY_CHECK_INTERVAL_MILLIS = checkIfServerSide(settings) ? PROXY_CHECK_INTERVAL_MILLIS_SS : PROXY_CHECK_INTERVAL_MILLIS_CS; let lastProxyCheckTimestamp: number | undefined; return function splitChangesFetcher( diff --git a/src/sync/streaming/SSEClient/index.ts b/src/sync/streaming/SSEClient/index.ts index c19c2817..bf6a2ee3 100644 --- a/src/sync/streaming/SSEClient/index.ts +++ b/src/sync/streaming/SSEClient/index.ts @@ -2,6 +2,7 @@ import { IPlatform } from '../../../sdkFactory/types'; import { decorateHeaders } from '../../../services/decorateHeaders'; import { IEventSourceConstructor } from '../../../services/types'; import { ISettings } from '../../../types'; +import { checkIfServerSide } from '../../../utils/key'; import { isString } from '../../../utils/lang'; import { objectAssign } from '../../../utils/lang/objectAssign'; import { IAuthTokenPushEnabled } from '../AuthClient/types'; @@ -73,7 +74,7 @@ export class SSEClient implements ISSEClient { return encodeURIComponent(params + channel); }).join(','); const url = `${this.settings.urls.streaming}/sse?channels=${channelsQueryParam}&accessToken=${authToken.token}&v=${ABLY_API_VERSION}&heartbeats=true`; // same results using `&heartbeats=false` - const isServerSide = !this.settings.core.key; + const isServerSide = checkIfServerSide(this.settings); this.connection = new this.eventSource!( // For client-side SDKs, metadata is passed as query param to avoid CORS issues and because native EventSource implementations in browsers do not support headers diff --git a/src/sync/streaming/pushManager.ts b/src/sync/streaming/pushManager.ts index 9122c176..f0a5ac4e 100644 --- a/src/sync/streaming/pushManager.ts +++ b/src/sync/streaming/pushManager.ts @@ -10,7 +10,7 @@ import { SplitsUpdateWorker } from './UpdateWorkers/SplitsUpdateWorker'; import { authenticateFactory, hashUserKey } from './AuthClient'; import { forOwn } from '../../utils/lang'; import { SSEClient } from './SSEClient'; -import { getMatching } from '../../utils/key'; +import { checkIfServerSide, getMatching } from '../../utils/key'; import { MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, RB_SEGMENT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP, ControlType } from './constants'; import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT, STREAMING_PARSING_MEMBERSHIPS_UPDATE } from '../../logger/constants'; import { IMembershipMSUpdateData, IMembershipLSUpdateData, KeyList, UpdateStrategy } from './SSEHandler/types'; @@ -34,7 +34,7 @@ export function pushManagerFactory( // `userKey` is the matching key of main client in client-side SDK. // It can be used to check if running on client-side or server-side SDK. - const userKey = settings.core.key ? getMatching(settings.core.key) : undefined; + const userKey = checkIfServerSide(settings) ? undefined : getMatching(settings.core.key); const log = settings.log; let sseClient: ISSEClient; diff --git a/src/sync/submitters/telemetrySubmitter.ts b/src/sync/submitters/telemetrySubmitter.ts index 7a2e2ee7..52bde5b1 100644 --- a/src/sync/submitters/telemetrySubmitter.ts +++ b/src/sync/submitters/telemetrySubmitter.ts @@ -11,6 +11,7 @@ import { timer } from '../../utils/timeTracker/timer'; import { ISdkFactoryContextSync } from '../../sdkFactory/types'; import { objectAssign } from '../../utils/lang/objectAssign'; import { ISplitFiltersValidation } from '../../dtos/types'; +import { checkIfServerSide } from '../../utils/key'; const OPERATION_MODE_MAP = { [STANDALONE_MODE]: STANDALONE_ENUM, @@ -71,7 +72,7 @@ export function telemetryCacheConfigAdapter(telemetry: ITelemetryCacheSync, sett pop(): TelemetryConfigStatsPayload { const { urls, scheduler } = settings; - const isClientSide = settings.core.key !== undefined; + const isServerSide = checkIfServerSide(settings); const { flagSetsTotal, flagSetsIgnored } = getTelemetryFlagSetsStats(settings.sync.__splitFiltersValidation); @@ -79,8 +80,8 @@ export function telemetryCacheConfigAdapter(telemetry: ITelemetryCacheSync, sett sE: settings.streamingEnabled, rR: { sp: scheduler.featuresRefreshRate / 1000, - se: isClientSide ? undefined : scheduler.segmentsRefreshRate / 1000, - ms: isClientSide ? scheduler.segmentsRefreshRate / 1000 : undefined, + se: isServerSide ? scheduler.segmentsRefreshRate / 1000 : undefined, + ms: isServerSide ? undefined : scheduler.segmentsRefreshRate / 1000, im: scheduler.impressionsRefreshRate / 1000, ev: scheduler.eventsPushRate / 1000, te: scheduler.telemetryRefreshRate / 1000, diff --git a/src/utils/key/index.ts b/src/utils/key/index.ts index fc763b6e..2fb1e0f1 100644 --- a/src/utils/key/index.ts +++ b/src/utils/key/index.ts @@ -1,4 +1,5 @@ import SplitIO from '../../../types/splitio'; +import { ISettings } from '../../types'; import { isObject } from '../lang'; // function isSplitKeyObject(key: any): key is SplitIO.SplitKeyObject { @@ -32,3 +33,7 @@ export function keyParser(key: SplitIO.SplitKey): SplitIO.SplitKeyObject { }; } } + +export function checkIfServerSide(settings: ISettings) { + return !settings.core.key; +}