Skip to content

Commit

Permalink
feat: Support direct url routing from config (#797)
Browse files Browse the repository at this point in the history
  • Loading branch information
rmi22186 authored Nov 13, 2023
1 parent 6b9f602 commit 449aec9
Show file tree
Hide file tree
Showing 6 changed files with 496 additions and 79 deletions.
6 changes: 3 additions & 3 deletions src/apiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
SDKEvent,
} from './sdkRuntimeModels';
import KitBlocker from './kitBlocking';
import { Dictionary, getRampNumber, isEmpty } from './utils';
import { Dictionary, getRampNumber, isEmpty, parseNumber } from './utils';
import { IUploadObject } from './serverModel';

export type ForwardingStatsData = Dictionary<any>;
Expand Down Expand Up @@ -42,9 +42,9 @@ export default function APIClient(
const self = this;
this.queueEventForBatchUpload = function(event: SDKEvent) {
if (!this.uploader) {
const millis = mpInstance._Helpers.getFeatureFlag(
const millis: number = parseNumber(mpInstance._Helpers.getFeatureFlag(
Constants.FeatureFlags.EventBatchingIntervalMillis
);
));
this.uploader = new BatchUploader(mpInstance, millis);
}
this.uploader.queueEvent(event);
Expand Down
5 changes: 3 additions & 2 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ const Constants = {
integrationDelayTimeout: 5000, // Milliseconds for forcing the integration delay to un-suspend event queueing due to integration partner errors
maxCookieSize: 3000, // Number of bytes for cookie size to not exceed
aliasMaxWindow: 90, // Max age of Alias request startTime, in days
uploadInterval: 0, // Maximum milliseconds in between batch uploads, below 500 will mean immediate upload
uploadInterval: 0, // Maximum milliseconds in between batch uploads, below 500 will mean immediate upload. The server returns this as a string, but we are using it as a number internally
},
DefaultUrls: {
DefaultBaseUrls: {
v1SecureServiceUrl: 'jssdks.mparticle.com/v1/JS/',
v2SecureServiceUrl: 'jssdks.mparticle.com/v2/JS/',
v3SecureServiceUrl: 'jssdks.mparticle.com/v3/JS/',
Expand Down Expand Up @@ -166,6 +166,7 @@ const Constants = {
ReportBatching: 'reportBatching',
EventBatchingIntervalMillis: 'eventBatchingIntervalMillis',
OfflineStorage: 'offlineStorage',
DirectUrlRouting: 'directURLRouting',
},
DefaultInstance: 'default_instance',
CCPAPurpose: 'data_sale_opt_out',
Expand Down
3 changes: 1 addition & 2 deletions src/mp-instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -1523,9 +1523,8 @@ function createKitBlocker(config, mpInstance) {

function runPreConfigFetchInitialization(mpInstance, apiKey, config) {
mpInstance.Logger = new Logger(config);
mpInstance._Store = new Store(config, mpInstance);
mpInstance._Store = new Store(config, mpInstance, apiKey);
window.mParticle.Store = mpInstance._Store;
mpInstance._Store.devToken = apiKey || null;
mpInstance.Logger.verbose(
Messages.InformationMessages.StartingInitialization
);
Expand Down
190 changes: 137 additions & 53 deletions src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
SDKInitConfig,
SDKProduct,
} from './sdkRuntimeModels';
import { isNumber, isDataPlanSlug, Dictionary } from './utils';
import { isNumber, isDataPlanSlug, Dictionary, parseNumber } from './utils';
import { SDKConsentState } from './consent';

// This represents the runtime configuration of the SDK AFTER
Expand All @@ -44,7 +44,7 @@ export interface SDKConfig {
appName?: string;
appVersion?: string;
package?: string;
flags?: { [key: string]: string | number | boolean };
flags?: IFeatureFlags;
kitConfigs: IKitConfigs[];
kits: Dictionary<Kit>;
logLevel?: LogLevelType;
Expand Down Expand Up @@ -90,8 +90,8 @@ function createSDKConfig(config: SDKInitConfig): SDKConfig {
}
}

for (const prop in Constants.DefaultUrls) {
sdkConfig[prop] = Constants.DefaultUrls[prop];
for (const prop in Constants.DefaultBaseUrls) {
sdkConfig[prop] = Constants.DefaultBaseUrls[prop];
}

return sdkConfig;
Expand All @@ -111,6 +111,14 @@ interface WrapperSDKInfo {
isInfoSet: boolean;
}

// https://go.mparticle.com/work/SQDSDKS-5954
export interface IFeatureFlags {
reportBatching?: string;
eventBatchingIntervalMillis?: number;
offlineStorage?: string;
directURLRouting?: boolean;
}

// Temporary Interface until Store can be refactored as a class
export interface IStore {
isEnabled: boolean;
Expand Down Expand Up @@ -160,7 +168,8 @@ export interface IStore {
export default function Store(
this: IStore,
config: SDKInitConfig,
mpInstance: MParticleWebSDK
mpInstance: MParticleWebSDK,
apiKey?: string
) {
const defaultStore: Partial<IStore> = {
isEnabled: true,
Expand Down Expand Up @@ -210,12 +219,21 @@ export default function Store(
for (var key in defaultStore) {
this[key] = defaultStore[key];
}
this.devToken = apiKey || null;

this.integrationDelayTimeoutStart = Date.now();

this.SDKConfig = createSDKConfig(config);
// Set configuration to default settings
this.SDKConfig = createSDKConfig(config);

if (config) {
if (!config.hasOwnProperty('flags')) {
this.SDKConfig.flags = {};
}

this.SDKConfig.flags = processFlags(config, this
.SDKConfig as SDKConfig);

if (config.deviceId) {
this.deviceId = config.deviceId;
}
Expand All @@ -227,28 +245,14 @@ export default function Store(
this.SDKConfig.isDevelopmentMode = false;
}

if (config.hasOwnProperty('v1SecureServiceUrl')) {
this.SDKConfig.v1SecureServiceUrl = config.v1SecureServiceUrl;
}

if (config.hasOwnProperty('v2SecureServiceUrl')) {
this.SDKConfig.v2SecureServiceUrl = config.v2SecureServiceUrl;
}
const baseUrls: Dictionary<string> = processBaseUrls(
config,
this.SDKConfig.flags,
apiKey
);

if (config.hasOwnProperty('v3SecureServiceUrl')) {
this.SDKConfig.v3SecureServiceUrl = config.v3SecureServiceUrl;
}

if (config.hasOwnProperty('identityUrl')) {
this.SDKConfig.identityUrl = config.identityUrl;
}

if (config.hasOwnProperty('aliasUrl')) {
this.SDKConfig.aliasUrl = config.aliasUrl;
}

if (config.hasOwnProperty('configUrl')) {
this.SDKConfig.configUrl = config.configUrl;
for (const baseUrlKeys in baseUrls) {
this.SDKConfig[baseUrlKeys] = baseUrls[baseUrlKeys];
}

if (config.hasOwnProperty('logLevel')) {
Expand Down Expand Up @@ -413,32 +417,112 @@ export default function Store(
this.SDKConfig.onCreateBatch = undefined;
}
}
}
}

if (!config.hasOwnProperty('flags')) {
this.SDKConfig.flags = {};
}
if (
!this.SDKConfig.flags.hasOwnProperty(
Constants.FeatureFlags.EventBatchingIntervalMillis
)
) {
this.SDKConfig.flags[
Constants.FeatureFlags.EventBatchingIntervalMillis
] = Constants.DefaultConfig.uploadInterval;
}
if (
!this.SDKConfig.flags.hasOwnProperty(
Constants.FeatureFlags.ReportBatching
)
) {
this.SDKConfig.flags[Constants.FeatureFlags.ReportBatching] = false;
}
if (
!this.SDKConfig.flags.hasOwnProperty(
Constants.FeatureFlags.OfflineStorage
)
) {
this.SDKConfig.flags[Constants.FeatureFlags.OfflineStorage] = 0;
}
export function processFlags(
config: SDKInitConfig,
SDKConfig: SDKConfig
): IFeatureFlags {
const flags: IFeatureFlags = {};
const {
ReportBatching,
EventBatchingIntervalMillis,
OfflineStorage,
DirectUrlRouting,
} = Constants.FeatureFlags;

if (!config.flags) {
return {};
}

// Passed in config flags take priority over defaults
flags[ReportBatching] = config.flags[ReportBatching] || false;
// The server returns stringified numbers, sowe need to parse
flags[EventBatchingIntervalMillis] =
parseNumber(config.flags[EventBatchingIntervalMillis]) ||
Constants.DefaultConfig.uploadInterval;
flags[OfflineStorage] = config.flags[OfflineStorage] || '0';
flags[DirectUrlRouting] = config.flags[DirectUrlRouting] === 'True';

return flags;
}

export function processBaseUrls(
config: SDKInitConfig,
flags: IFeatureFlags,
apiKey?: string
): Dictionary<string> {
// an API key is not present in a webview only mode. In this case, no baseUrls are needed
if (!apiKey) {
return {};
}

// Set default baseUrls
let baseUrls: Dictionary<string>;

// When direct URL routing is false, update baseUrls based custom urls
// passed to the config
if (flags.directURLRouting) {
return processDirectBaseUrls(config, apiKey);
} else {
return processCustomBaseUrls(config);
}
}

function processCustomBaseUrls(config: SDKInitConfig): Dictionary<string> {
const defaultBaseUrls: Dictionary<string> = Constants.DefaultBaseUrls;
const newBaseUrls: Dictionary<string> = {};

// If there is no custo base url, we use the default base url
for (let baseUrlKey in defaultBaseUrls) {
newBaseUrls[baseUrlKey] =
config[baseUrlKey] || defaultBaseUrls[baseUrlKey];
}

return newBaseUrls;
}

function processDirectBaseUrls(
config: SDKInitConfig,
apiKey: string
): Dictionary {
const defaultBaseUrls = Constants.DefaultBaseUrls;
const directBaseUrls: Dictionary<string> = {};
// When Direct URL Routing is true, we create a new set of baseUrls that
// include the silo in the urls. mParticle API keys are prefixed with the
// silo and a hyphen (ex. "us1-", "us2-", "eu1-"). us1 was the first silo,
// and before other silos existed, there were no prefixes and all apiKeys
// were us1. As such, if we split on a '-' and the resulting array length
// is 1, then it is an older APIkey that should route to us1.
// When splitKey.length is greater than 1, then splitKey[0] will be
// us1, us2, eu1, au1, or st1, etc as new silos are added
const DEFAULT_SILO = 'us1';
const splitKey: Array<string> = apiKey.split('-');
const routingPrefix: string =
splitKey.length <= 1 ? DEFAULT_SILO : splitKey[0];

for (let baseUrlKey in defaultBaseUrls) {
// Any custom endpoints passed to mpConfig will take priority over direct
// mapping to the silo. The most common use case is a customer provided CNAME.
if (baseUrlKey === 'configUrl') {
directBaseUrls[baseUrlKey] =
config[baseUrlKey] || defaultBaseUrls[baseUrlKey];
continue;
}

if (config.hasOwnProperty(baseUrlKey)) {
directBaseUrls[baseUrlKey] = config[baseUrlKey];
} else {
const urlparts = defaultBaseUrls[baseUrlKey].split('.');

directBaseUrls[baseUrlKey] = [
urlparts[0],
routingPrefix,
...urlparts.slice(1),
].join('.');
}
}

return directBaseUrls;
}
Loading

0 comments on commit 449aec9

Please sign in to comment.