Skip to content

Commit 47b3415

Browse files
committed
implement dynamic identify timestamps
1 parent 3a43bbe commit 47b3415

4 files changed

Lines changed: 170 additions & 0 deletions

File tree

src/identityApiClient.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ export default function IdentityAPIClient(
193193
mpid: MPID,
194194
knownIdentities: UserIdentities
195195
) {
196+
// START
197+
const requestCounter = mpInstance._Store.getAndIncrementIdentityRequestCounter();
198+
const startTimestamp = new Date().getTime();
199+
const startEventType = `identity${requestCounter}RequestStart`;
200+
mpInstance._TimingEventsClient.sendTimingEvent(startEventType, startTimestamp);
196201
const { invokeCallback } = mpInstance._Helpers;
197202
const { Logger } = mpInstance;
198203
Logger.verbose(Messages.InformationMessages.SendIdentityBegin);
@@ -289,6 +294,16 @@ export default function IdentityAPIClient(
289294
mpInstance._Store.identityCallInFlight = false;
290295

291296
Logger.verbose(message);
297+
298+
// END
299+
const requestNumber = mpInstance._Store.currentIdentityRequestNumber;
300+
if (requestNumber !== null) {
301+
const endTimestamp = new Date().getTime();
302+
const endEventType = `identity${requestNumber}RequestEnd`;
303+
mpInstance._TimingEventsClient.sendTimingEvent(endEventType, endTimestamp);
304+
mpInstance._Store.currentIdentityRequestNumber = null;
305+
}
306+
292307
parseIdentityResponse(
293308
identityResponse,
294309
previousMPID,
@@ -301,6 +316,15 @@ export default function IdentityAPIClient(
301316
} catch (err) {
302317
mpInstance._Store.identityCallInFlight = false;
303318

319+
// END
320+
const requestNumber = mpInstance._Store.currentIdentityRequestNumber;
321+
if (requestNumber !== null) {
322+
const endTimestamp = new Date().getTime();
323+
const endEventType = `identity${requestNumber}RequestEnd`;
324+
mpInstance._TimingEventsClient.sendTimingEvent(endEventType, endTimestamp);
325+
mpInstance._Store.currentIdentityRequestNumber = null;
326+
}
327+
304328
const errorMessage = (err as Error).message || err.toString();
305329

306330
Logger.error('Error sending identity request to servers' + ' - ' + errorMessage);

src/mp-instance.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import Consent, { IConsent } from './consent';
3636
import KitBlocker from './kitBlocking';
3737
import ConfigAPIClient, { IKitConfigs } from './configAPIClient';
3838
import IdentityAPIClient from './identityApiClient';
39+
import TimingEventsClient, { ITimingEventsClient } from './timingEventsClient';
3940
import { isFunction, parseConfig, valueof, generateDeprecationMessage } from './utils';
4041
import { LocalStorageVault } from './vault';
4142
import { removeExpiredIdentityCacheDates } from './identity-utils';
@@ -80,6 +81,7 @@ export interface IMParticleWebSDKInstance extends MParticleWebSDK {
8081
_Helpers: SDKHelpersApi;
8182
_Identity: IIdentity;
8283
_IdentityAPIClient: typeof IdentityAPIClient;
84+
_TimingEventsClient: ITimingEventsClient;
8385
_IntegrationCapture: IntegrationCapture;
8486
_NativeSdkHelpers: INativeSdkHelpers;
8587
_Persistence: IPersistence;
@@ -127,6 +129,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan
127129
this._ForwardingStatsUploader = new ForwardingStatsUploader(this);
128130
this._Consent = new Consent(this);
129131
this._IdentityAPIClient = new IdentityAPIClient(this);
132+
this._TimingEventsClient = new TimingEventsClient(this);
130133
this._preInit = {
131134
readyQueue: [],
132135
integrationDelays: {},
@@ -158,6 +161,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan
158161
}
159162
}
160163
this.init = function(apiKey, config) {
164+
console.log("woohoo");
161165
if (!config) {
162166
console.warn(
163167
'You did not pass a config object to init(). mParticle will not initialize properly'

src/store.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ export interface IStore {
182182
context: Context | null;
183183
configurationLoaded: boolean;
184184
identityCallInFlight: boolean;
185+
identityRequestCounter: number;
186+
currentIdentityRequestNumber: number | null;
185187
SDKConfig: Partial<SDKConfig>;
186188
nonCurrentUserMPIDs: Record<MPID, Dictionary>;
187189
identifyCalled: boolean;
@@ -225,6 +227,7 @@ export interface IStore {
225227
addMpidToSessionHistory?(mpid: MPID, previousMpid?: MPID): void;
226228
hasInvalidIdentifyRequest?: () => boolean;
227229
nullifySession?: () => void;
230+
getAndIncrementIdentityRequestCounter?: () => number;
228231
processConfig(config: SDKInitConfig): void;
229232
syncPersistenceData?: () => void;
230233
}
@@ -266,6 +269,8 @@ export default function Store(
266269
context: null,
267270
configurationLoaded: false,
268271
identityCallInFlight: false,
272+
identityRequestCounter: 0,
273+
currentIdentityRequestNumber: null,
269274
SDKConfig: {},
270275
nonCurrentUserMPIDs: {},
271276
identifyCalled: false,
@@ -682,13 +687,23 @@ export default function Store(
682687

683688
this.nullifySession = (): void => {
684689
this.sessionId = null;
690+
this.identityRequestCounter = 0;
691+
this.currentIdentityRequestNumber = null;
685692
this.dateLastEventSent = null;
686693
this.sessionStartDate = null;
687694
this.sessionAttributes = {};
688695
this.localSessionAttributes = {};
689696
mpInstance._Persistence.update();
690697
};
691698

699+
this.getAndIncrementIdentityRequestCounter = (): number => {
700+
if (this.identityRequestCounter < 99) {
701+
this.identityRequestCounter++;
702+
}
703+
this.currentIdentityRequestNumber = this.identityRequestCounter;
704+
return this.identityRequestCounter;
705+
};
706+
692707
this.processConfig = (config: SDKInitConfig) => {
693708
const { workspaceToken, requiredWebviewBridgeName } = config;
694709

src/timingEventsClient.ts

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { AsyncUploader, FetchUploader, XHRUploader, IFetchPayload } from './uploaders';
2+
import { IMParticleWebSDKInstance } from './mp-instance';
3+
import Constants from './constants';
4+
5+
interface TimingEventsRequestPayload extends IFetchPayload {
6+
headers: {
7+
Accept: string;
8+
'Content-Type': string;
9+
[key: string]: string;
10+
};
11+
}
12+
13+
interface TimingEventsRequestBody {
14+
timingMetrics: Array<{
15+
name: string;
16+
value: number;
17+
}>;
18+
}
19+
20+
export interface ITimingEventsClient {
21+
sendTimingEvent: (eventType: string, timestamp: number) => Promise<void>;
22+
}
23+
24+
export default function TimingEventsClient(
25+
this: ITimingEventsClient,
26+
mpInstance: IMParticleWebSDKInstance
27+
) {
28+
const launcherInstanceGuidKey = Constants.Rokt.LauncherInstanceGuidKey;
29+
30+
const getLauncherInstanceGuid = (): string | undefined => {
31+
if (typeof window === 'undefined') {
32+
return undefined;
33+
}
34+
if (window[launcherInstanceGuidKey] && typeof window[launcherInstanceGuidKey] === 'string') {
35+
return window[launcherInstanceGuidKey];
36+
}
37+
return undefined;
38+
};
39+
40+
const getRoktTraceId = (): string | undefined => {
41+
if (typeof window === 'undefined') {
42+
return undefined;
43+
}
44+
const roktTraceIdKey = '__rokt_trace_id__';
45+
if (window[roktTraceIdKey] && typeof window[roktTraceIdKey] === 'string') {
46+
return window[roktTraceIdKey];
47+
}
48+
return undefined;
49+
};
50+
51+
this.sendTimingEvent = async function(eventType: string, timestamp: number): Promise<void> {
52+
if (!mpInstance._Store) {
53+
return;
54+
}
55+
56+
const launcherInstanceGuid = getLauncherInstanceGuid();
57+
if (!launcherInstanceGuid) {
58+
return;
59+
}
60+
61+
const roktTraceId = getRoktTraceId();
62+
if (!roktTraceId) {
63+
return;
64+
}
65+
66+
const { sessionId } = mpInstance._Store;
67+
68+
const headers: Record<string, string> = {
69+
Accept: 'application/json',
70+
'Content-Type': 'application/json',
71+
};
72+
73+
headers['rokt-launcher-instance-guid'] = launcherInstanceGuid;
74+
headers['x-rokt-trace-id'] = roktTraceId;
75+
76+
if (sessionId) {
77+
headers['rokt-session-id'] = sessionId;
78+
}
79+
80+
if (Constants.sdkVersion) {
81+
headers['rokt-sdk-version'] = Constants.sdkVersion;
82+
}
83+
84+
headers['rokt-sdk-framework-type'] = 'integration-launcher';
85+
headers['rokt-integration-type'] = 'wsdk';
86+
87+
if (mpInstance._Store.context) {
88+
const context = mpInstance._Store.context as any;
89+
if (context.partnerId) {
90+
headers['rokt-tag-id'] = String(context.partnerId);
91+
}
92+
if (context.pageId) {
93+
headers['rokt-page-id'] = context.pageId;
94+
}
95+
if (context.pageInstanceGuid) {
96+
headers['rokt-page-instance-guid'] = context.pageInstanceGuid;
97+
}
98+
}
99+
100+
const timingMetricsBody: TimingEventsRequestBody = {
101+
timingMetrics: [
102+
{
103+
name: eventType,
104+
value: timestamp,
105+
},
106+
],
107+
};
108+
109+
110+
const uploadUrl = `/v1/timings/events`;
111+
112+
const uploader: AsyncUploader = (typeof window !== 'undefined' && window.fetch)
113+
? new FetchUploader(uploadUrl)
114+
: new XHRUploader(uploadUrl);
115+
116+
const fetchPayload: TimingEventsRequestPayload = {
117+
method: 'post',
118+
headers: headers as TimingEventsRequestPayload['headers'],
119+
body: JSON.stringify(timingMetricsBody),
120+
};
121+
122+
try {
123+
await uploader.upload(fetchPayload);
124+
} catch (err) {
125+
}
126+
};
127+
}

0 commit comments

Comments
 (0)