noibu-react-native 0.2.6 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -15
- package/android/build.gradle +1 -1
- package/dist/{src/api/clientConfig.d.ts → api/ClientConfig.d.ts} +19 -20
- package/dist/api/{clientConfig.js → ClientConfig.js} +82 -63
- package/dist/{src/api/helpCode.d.ts → api/HelpCode.d.ts} +3 -10
- package/dist/api/{helpCode.js → HelpCode.js} +8 -14
- package/dist/api/InputManager.d.ts +39 -0
- package/dist/api/InputManager.js +156 -0
- package/dist/{src/api/metroplexSocket.d.ts → api/MetroplexSocket.d.ts} +33 -38
- package/dist/api/{metroplexSocket.js → MetroplexSocket.js} +190 -178
- package/dist/{src/api/storedMetrics.d.ts → api/StoredMetrics.d.ts} +10 -20
- package/dist/api/StoredMetrics.js +158 -0
- package/dist/{src/api/storedPageVisit.d.ts → api/StoredPageVisit.d.ts} +11 -8
- package/dist/api/{storedPageVisit.js → StoredPageVisit.js} +62 -48
- package/dist/const_matchers.js +1 -5
- package/dist/constants.d.ts +48 -0
- package/dist/constants.js +15 -397
- package/dist/{src/entry → entry}/index.d.ts +5 -6
- package/dist/entry/index.js +3 -4
- package/dist/entry/init.d.ts +8 -0
- package/dist/entry/init.js +34 -19
- package/dist/monitors/AppNavigationMonitor.d.ts +10 -0
- package/dist/monitors/AppNavigationMonitor.js +19 -19
- package/dist/monitors/AppNavigationMonitor.test.d.ts +1 -0
- package/dist/{src/monitors → monitors}/BaseMonitor.d.ts +5 -5
- package/dist/monitors/BaseMonitor.js +9 -4
- package/dist/monitors/BaseMonitor.test.d.ts +1 -0
- package/dist/{src/monitors → monitors}/ClickMonitor.d.ts +10 -13
- package/dist/monitors/ClickMonitor.js +72 -76
- package/dist/monitors/ClickMonitor.test.d.ts +1 -0
- package/dist/{src/monitors → monitors}/ErrorMonitor.d.ts +4 -28
- package/dist/monitors/ErrorMonitor.js +45 -55
- package/dist/{src/monitors → monitors}/KeyboardInputMonitor.d.ts +1 -3
- package/dist/monitors/KeyboardInputMonitor.js +13 -11
- package/dist/{src/monitors → monitors}/PageMonitor.d.ts +1 -1
- package/dist/monitors/PageMonitor.js +25 -2
- package/dist/{src/monitors → monitors}/RequestMonitor.d.ts +9 -29
- package/dist/monitors/RequestMonitor.js +46 -57
- package/dist/monitors/http-tools/GqlErrorValidator.d.ts +35 -0
- package/dist/monitors/http-tools/GqlErrorValidator.js +42 -70
- package/dist/{src/monitors → monitors}/http-tools/HTTPDataBundler.d.ts +9 -15
- package/dist/monitors/http-tools/HTTPDataBundler.js +74 -67
- package/dist/monitors/integrations/ReactNativeNavigationIntegration.d.ts +17 -0
- package/dist/monitors/integrations/{react-native-navigation-integration.js → ReactNativeNavigationIntegration.js} +15 -12
- package/dist/{src/pageVisit → pageVisit}/EventDebouncer.d.ts +9 -10
- package/dist/pageVisit/EventDebouncer.js +43 -74
- package/dist/pageVisit/HttpEventManager.d.ts +14 -0
- package/dist/pageVisit/HttpEventManager.js +88 -0
- package/dist/pageVisit/PageVisitManager.d.ts +31 -0
- package/dist/pageVisit/PageVisitManager.js +99 -0
- package/dist/pageVisit/pageVisitEventError.d.ts +12 -0
- package/dist/pageVisit/pageVisitEventError.js +170 -280
- package/dist/{src/react → react}/ErrorBoundary.d.ts +4 -9
- package/dist/react/ErrorBoundary.js +3 -6
- package/dist/{src/sessionRecorder/sessionRecorder.d.ts → sessionRecorder/SessionRecorder.d.ts} +7 -17
- package/dist/sessionRecorder/{sessionRecorder.js → SessionRecorder.js} +60 -71
- package/dist/{src/sessionRecorder → sessionRecorder}/nativeSessionRecorderSubscription.d.ts +4 -6
- package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +3 -5
- package/dist/{src/storage/rnStorageProvider.d.ts → storage/RNStorageProvider.d.ts} +4 -8
- package/dist/storage/{rnStorageProvider.js → RNStorageProvider.js} +3 -7
- package/dist/{src/storage/storage.d.ts → storage/Storage.d.ts} +8 -18
- package/dist/storage/{storage.js → Storage.js} +17 -30
- package/dist/{src/storage/storageProvider.d.ts → storage/StorageProvider.d.ts} +5 -8
- package/dist/storage/{storageProvider.js → StorageProvider.js} +7 -8
- package/dist/types/NavigationIntegration.d.ts +1 -1
- package/dist/utils/date.d.ts +7 -0
- package/dist/utils/date.js +41 -51
- package/dist/utils/eventlistener.js +6 -14
- package/dist/{src/utils → utils}/function.d.ts +13 -43
- package/dist/utils/function.js +42 -113
- package/dist/utils/log.d.ts +4 -0
- package/dist/utils/log.js +2 -4
- package/dist/{src/utils → utils}/object.d.ts +10 -8
- package/dist/utils/object.js +12 -12
- package/dist/{src/utils → utils}/performance.d.ts +1 -1
- package/dist/utils/piiRedactor.js +31 -3
- package/dist/utils/stacktrace-parser.d.ts +8 -0
- package/dist/utils/stacktrace-parser.js +29 -21
- package/dist/utils/stacktrace-parser.test.d.ts +1 -0
- package/package.json +14 -14
- package/dist/api/inputManager.js +0 -227
- package/dist/api/storedMetrics.js +0 -198
- package/dist/pageVisit/pageVisit.js +0 -181
- package/dist/pageVisit/pageVisitEventHTTP.js +0 -98
- package/dist/pageVisit/userStep.js +0 -20
- package/dist/src/api/inputManager.d.ts +0 -87
- package/dist/src/constants.d.ts +0 -290
- package/dist/src/entry/init.d.ts +0 -5
- package/dist/src/monitors/AppNavigationMonitor.d.ts +0 -18
- package/dist/src/monitors/http-tools/GqlErrorValidator.d.ts +0 -59
- package/dist/src/monitors/integrations/react-native-navigation-integration.d.ts +0 -20
- package/dist/src/pageVisit/pageVisit.d.ts +0 -52
- package/dist/src/pageVisit/pageVisitEventError.d.ts +0 -15
- package/dist/src/pageVisit/pageVisitEventHTTP.d.ts +0 -25
- package/dist/src/pageVisit/userStep.d.ts +0 -5
- package/dist/src/utils/date.d.ts +0 -6
- package/dist/src/utils/log.d.ts +0 -4
- package/dist/src/utils/stacktrace-parser.d.ts +0 -7
- package/dist/types/Config.d.ts +0 -31
- package/dist/types/Metroplex.types.d.ts +0 -73
- package/dist/types/PageVisit.types.d.ts +0 -8
- package/dist/types/PageVisitErrors.types.d.ts +0 -114
- package/dist/types/PageVisitEvents.types.d.ts +0 -91
- package/dist/types/PageVisitMetrics.types.d.ts +0 -27
- package/dist/types/Storage.d.ts +0 -14
- package/dist/types/StoredPageVisit.types.d.ts +0 -11
- package/dist/types/WrappedObjects.d.ts +0 -6
- /package/dist/{src/api/clientConfig.test.d.ts → api/ClientConfig.test.d.ts} +0 -0
- /package/dist/{src/monitors/BaseMonitor.test.d.ts → api/MetroplexSocket.test.d.ts} +0 -0
- /package/dist/{src/const_matchers.d.ts → const_matchers.d.ts} +0 -0
- /package/dist/{src/sessionRecorder → sessionRecorder}/types.d.ts +0 -0
- /package/dist/{src/utils → utils}/eventlistener.d.ts +0 -0
- /package/dist/{src/utils → utils}/piiRedactor.d.ts +0 -0
- /package/dist/{src/utils → utils}/polyfills.d.ts +0 -0
|
@@ -1,17 +1,38 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
2
|
import uuid from 'react-native-uuid';
|
|
3
|
-
import {
|
|
3
|
+
import { Platform } from 'react-native';
|
|
4
|
+
import { MetroplexRoute } from '../node_modules/@noibu/metroplex-ts-bindings/dist/index.js';
|
|
5
|
+
import { getUserAgent, stringifyJSON } from '../utils/function.js';
|
|
4
6
|
import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
5
|
-
import { GET_METROPLEX_BASE_SOCKET_URL,
|
|
6
|
-
import ClientConfig from './
|
|
7
|
-
import StoredMetrics from './
|
|
8
|
-
import StoredPageVisit from './
|
|
7
|
+
import { GET_METROPLEX_BASE_SOCKET_URL, GET_METROPLEX_POST_URL, GET_MAX_METROPLEX_RECONNECTION_NUMBER, GET_METROPLEX_CONSECUTIVE_CONNECTION_DELAY, MAX_BEACON_PAYLOAD_SIZE, CURRENT_NOIBUJS_VERSION, GET_SCRIPT_ID } from '../constants.js';
|
|
8
|
+
import ClientConfig from './ClientConfig.js';
|
|
9
|
+
import StoredMetrics from './StoredMetrics.js';
|
|
10
|
+
import StoredPageVisit from './StoredPageVisit.js';
|
|
9
11
|
import { safePerformanceNow } from '../utils/performance.js';
|
|
10
12
|
import { isDateOverwritten } from '../utils/date.js';
|
|
11
13
|
import { unwrapNoibuWrapped } from '../utils/object.js';
|
|
12
14
|
import { noibuLog } from '../utils/log.js';
|
|
13
15
|
import { Singleton } from '../monitors/BaseMonitor.js';
|
|
16
|
+
import { WebsocketMessageType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/WebsocketMessageType.js';
|
|
17
|
+
import { WorkRequestMessageType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/WorkRequestMessageType.js';
|
|
18
|
+
import { EventType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/EventType.js';
|
|
19
|
+
import { Severity } from '../node_modules/@noibu/metroplex-ts-bindings/dist/Severity.js';
|
|
20
|
+
import { InboundMessageType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/InboundMessageType.js';
|
|
14
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Grab the video recorder type based on the device we run the app on.
|
|
24
|
+
*/
|
|
25
|
+
function getVideoRecorderType() {
|
|
26
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
27
|
+
if (Platform.OS === 'android') {
|
|
28
|
+
return 'AndroidNative';
|
|
29
|
+
}
|
|
30
|
+
if (Platform.OS === 'ios') {
|
|
31
|
+
return 'IOSNative';
|
|
32
|
+
}
|
|
33
|
+
return 'RRWeb'; // should never happen
|
|
34
|
+
});
|
|
35
|
+
}
|
|
15
36
|
/**
|
|
16
37
|
* Implements rolling window of specified size,
|
|
17
38
|
* but only makes a cut once array length exceeds 150%.
|
|
@@ -35,6 +56,13 @@ function createSlidingArrayOfSize(size, arraySource = [], downsizeThreshold = 1.
|
|
|
35
56
|
},
|
|
36
57
|
});
|
|
37
58
|
}
|
|
59
|
+
// gets the frequency at which the client resends the message that were not confirmed by metroplex
|
|
60
|
+
const METROPLEX_RETRY_FREQUENCY = 30000;
|
|
61
|
+
// current PageVisitManager version to be sent from front end services
|
|
62
|
+
const CURRENT_PV_VERSION = 5;
|
|
63
|
+
// maximum number of connection a single page visit can reach
|
|
64
|
+
const MAX_METROPLEX_CONNECTION_COUNT = 100;
|
|
65
|
+
const MAX_RETRY_MSG_Q_SIZE = 500;
|
|
38
66
|
/** Manages the socket to Metroplex */
|
|
39
67
|
class MetroplexSocket extends Singleton {
|
|
40
68
|
/**
|
|
@@ -59,11 +87,10 @@ class MetroplexSocket extends Singleton {
|
|
|
59
87
|
this.connectionCount = 0;
|
|
60
88
|
// session start time, used to calculate accurate end time
|
|
61
89
|
this.sessionStartTime = safePerformanceNow();
|
|
62
|
-
|
|
63
|
-
// Whether or not we have sent the page visit information after connecting the socket
|
|
90
|
+
// Whether we have sent the page visit information after connecting the socket
|
|
64
91
|
this.pageVisitInfoSent = false;
|
|
65
92
|
// socket connection url
|
|
66
|
-
this.connectionURL = `${GET_METROPLEX_BASE_SOCKET_URL()}/${
|
|
93
|
+
this.connectionURL = `${GET_METROPLEX_BASE_SOCKET_URL()}/${MetroplexRoute.PageVisitPart}`;
|
|
67
94
|
// post endpoint for the same events we would send to the socket
|
|
68
95
|
this.postURL = GET_METROPLEX_POST_URL();
|
|
69
96
|
// sequence number of the message sent to metroplex
|
|
@@ -98,75 +125,91 @@ class MetroplexSocket extends Singleton {
|
|
|
98
125
|
this.metroRetryFrequencyMS = METROPLEX_RETRY_FREQUENCY;
|
|
99
126
|
this.retryMetroplexInterval = null;
|
|
100
127
|
this.helpCodeCb = null;
|
|
101
|
-
noibuLog('Metroplex constructor', {
|
|
102
|
-
initialURL: this.initialURL,
|
|
103
|
-
scriptInstanceId,
|
|
104
|
-
});
|
|
128
|
+
noibuLog('Metroplex constructor', { initialURL: this.initialURL, scriptInstanceId });
|
|
105
129
|
this.scriptInstanceId = scriptInstanceId;
|
|
106
|
-
// Connect the WS
|
|
107
130
|
this.connectionPromise = this.connectSocket();
|
|
108
131
|
// Set up the offload events immediately
|
|
109
132
|
this._setupOffloadEvents();
|
|
110
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* connectSocket will establish a websocket connection to the metroplex
|
|
136
|
+
* service
|
|
137
|
+
*/
|
|
138
|
+
connectSocket() {
|
|
139
|
+
if (this.isConnected() || this.isConnecting()) {
|
|
140
|
+
// self resolving promise since we are already ready to send
|
|
141
|
+
// requests, if we did reach state 1, we already sent initial
|
|
142
|
+
// request, thus not sending it again.
|
|
143
|
+
return this.connectionPromise;
|
|
144
|
+
}
|
|
145
|
+
// we return a promisified socket resolver to be able to chain the
|
|
146
|
+
// opening of the socket
|
|
147
|
+
return this.handleConnect(false);
|
|
148
|
+
}
|
|
149
|
+
/** sets up events that will trigger the event queue to be emptied */
|
|
150
|
+
_setupOffloadEvents() {
|
|
151
|
+
// when the page hides we try getting all the events
|
|
152
|
+
// and empty the event and retry queue.
|
|
153
|
+
addSafeEventListener(window, 'pagehide', () => this._handleUnload(), false);
|
|
154
|
+
}
|
|
111
155
|
/**
|
|
112
156
|
* Adds the seq num field to the given payload depending on whether its
|
|
113
157
|
* a page visit part or video frag
|
|
114
158
|
*/
|
|
115
|
-
_addSeqNumToPayload(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
159
|
+
_addSeqNumToPayload(message) {
|
|
160
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
161
|
+
const { type, payload } = message;
|
|
162
|
+
/**
|
|
163
|
+
* Increasing the message sequence number for every message we send to metroplex
|
|
164
|
+
* and move the data to the retry queue.
|
|
165
|
+
*/
|
|
120
166
|
this.messageSequenceNum += 1;
|
|
121
|
-
|
|
122
|
-
|
|
167
|
+
const newMessage = {
|
|
168
|
+
type,
|
|
169
|
+
payload: Object.assign(Object.assign({}, payload), { seq_num: this.messageSequenceNum }),
|
|
170
|
+
};
|
|
171
|
+
/** push the message to the retry queue immediately in case socket isnt connected */
|
|
172
|
+
this.retryMessageQueue.push(newMessage);
|
|
173
|
+
StoredPageVisit.getInstance().checkAndStoreRetryQueue(this.retryMessageQueue, yield this.getPageInformation());
|
|
174
|
+
return newMessage;
|
|
175
|
+
});
|
|
123
176
|
}
|
|
124
177
|
/** requests help code and saves a callback to be called on response */
|
|
125
178
|
requestHelpCode(cb) {
|
|
126
179
|
this.helpCodeCb = cb;
|
|
127
|
-
return
|
|
128
|
-
[WORK_REQUEST_ATT_NAME]: HELP_CODE_ATT_NAME,
|
|
129
|
-
});
|
|
180
|
+
return this.sendMessage({ type: WebsocketMessageType.WorkRequest, payload: WorkRequestMessageType.HelpCode });
|
|
130
181
|
}
|
|
131
182
|
/**
|
|
132
183
|
* Immediately sends a message to Metroplex over the web socket
|
|
133
184
|
* Queues the message if the connection isn't open yet.
|
|
134
185
|
* returns true if message was sent succefully, false otherwise
|
|
135
186
|
*/
|
|
136
|
-
sendMessage(
|
|
187
|
+
sendMessage(message) {
|
|
137
188
|
return __awaiter(this, void 0, void 0, function* () {
|
|
189
|
+
const { type } = message;
|
|
138
190
|
noibuLog('sendMessage start', { type });
|
|
139
191
|
// if we have a lock on this specific type, we dont send it
|
|
140
|
-
if (type
|
|
141
|
-
ClientConfig.getInstance().isClientDisabled) {
|
|
192
|
+
if (this.metroplexTypeLock[type] || ClientConfig.getInstance().isClientDisabled) {
|
|
142
193
|
noibuLog('sendMessage quitting due to', {
|
|
143
|
-
typeInLock: type
|
|
194
|
+
typeInLock: this.metroplexTypeLock[type] ? `${type} locked` : false,
|
|
144
195
|
isClientDisabled: ClientConfig.getInstance().isClientDisabled,
|
|
145
196
|
});
|
|
146
197
|
return false;
|
|
147
198
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
this._addSeqNumToPayload(type, payload);
|
|
152
|
-
// push the message to the retry queue immediately in case socket isnt connected
|
|
153
|
-
this.retryMessageQueue.push({ payload, type });
|
|
154
|
-
StoredPageVisit.getInstance().checkAndStoreRetryQueue(this.retryMessageQueue, yield this.getPageInformation());
|
|
155
|
-
}
|
|
199
|
+
const withSeqNum = type === WebsocketMessageType.WorkRequest
|
|
200
|
+
? message
|
|
201
|
+
: yield this._addSeqNumToPayload(message);
|
|
156
202
|
// send the socket message if we are connected and have sent page visit info
|
|
157
203
|
if (this.isConnected() && this.pageVisitInfoSent) {
|
|
158
204
|
// sending the data to metroplex
|
|
159
|
-
yield this.
|
|
205
|
+
yield this.sendSocketMessage({ [withSeqNum.type]: withSeqNum.payload });
|
|
160
206
|
}
|
|
161
207
|
this.previousMessageType = type;
|
|
162
208
|
// Only update the last message send if its a page visit with user action
|
|
163
209
|
// ensure this is done regardless of whether socket is connected or not,
|
|
164
210
|
// so that pagehide will post PV if user is active but socket is not
|
|
165
|
-
if (type ===
|
|
166
|
-
|
|
167
|
-
? payload[PAGE_VISIT_PART_ATT_NAME][PV_EVENTS_ATT_NAME]
|
|
168
|
-
: [];
|
|
169
|
-
yield this._updateLatestPvTimestamp(events);
|
|
211
|
+
if (withSeqNum.type === WebsocketMessageType.PageVisitPart) {
|
|
212
|
+
yield this._updateLatestPvTimestamp(withSeqNum.payload.events || []);
|
|
170
213
|
}
|
|
171
214
|
return true;
|
|
172
215
|
});
|
|
@@ -175,7 +218,7 @@ class MetroplexSocket extends Singleton {
|
|
|
175
218
|
*/
|
|
176
219
|
_updateLatestPvTimestamp(events) {
|
|
177
220
|
return __awaiter(this, void 0, void 0, function* () {
|
|
178
|
-
const userstepsEvents = events.filter(ev => ev
|
|
221
|
+
const userstepsEvents = events.filter(ev => ev.type === EventType.UserStep);
|
|
179
222
|
if (userstepsEvents.length > 0) {
|
|
180
223
|
yield ClientConfig.getInstance().updateLastActiveTime(new Date());
|
|
181
224
|
}
|
|
@@ -244,18 +287,21 @@ class MetroplexSocket extends Singleton {
|
|
|
244
287
|
clearInterval(this.retryMetroplexInterval);
|
|
245
288
|
}
|
|
246
289
|
// if we tried reconnecting too many times we abandon
|
|
247
|
-
if (this.currentConnectionAttempts >=
|
|
248
|
-
GET_MAX_METROPLEX_RECONNECTION_NUMBER()) {
|
|
290
|
+
if (this.currentConnectionAttempts >= GET_MAX_METROPLEX_RECONNECTION_NUMBER()) {
|
|
249
291
|
// if we tried beyond the threshold, we block ourselves a short
|
|
250
292
|
// while fix the issue
|
|
251
|
-
yield ClientConfig.getInstance().lockClientUntilNextPage(
|
|
293
|
+
yield ClientConfig.getInstance().lockClientUntilNextPage({
|
|
294
|
+
msg: 'Too many reconnection attempts, locking until next page',
|
|
295
|
+
});
|
|
252
296
|
return;
|
|
253
297
|
}
|
|
254
298
|
// if we tried reconnecting too many times we abandon
|
|
255
299
|
if (this.connectionCount >= MAX_METROPLEX_CONNECTION_COUNT) {
|
|
256
300
|
// if we tried beyond the threshold, we block ourselves a short
|
|
257
301
|
// while fix the issue
|
|
258
|
-
yield ClientConfig.getInstance().lockClientUntilNextPage(
|
|
302
|
+
yield ClientConfig.getInstance().lockClientUntilNextPage({
|
|
303
|
+
msg: 'Too many connections, locking until next page',
|
|
304
|
+
});
|
|
259
305
|
return;
|
|
260
306
|
}
|
|
261
307
|
// try to reconnect on close but after a certain delay based off unsuccessful connections
|
|
@@ -265,7 +311,7 @@ class MetroplexSocket extends Singleton {
|
|
|
265
311
|
});
|
|
266
312
|
// everytime we get a message from the socket
|
|
267
313
|
this.socket.onmessage = event => {
|
|
268
|
-
noibuLog('metroplex handleConnect, onmessage',
|
|
314
|
+
noibuLog('metroplex handleConnect, onmessage', event);
|
|
269
315
|
this._onSocketMessage(event);
|
|
270
316
|
};
|
|
271
317
|
// the moment we open the socket
|
|
@@ -276,32 +322,14 @@ class MetroplexSocket extends Singleton {
|
|
|
276
322
|
};
|
|
277
323
|
});
|
|
278
324
|
}
|
|
279
|
-
/**
|
|
280
|
-
* connectSocket will establish a websocket connection to the metroplex
|
|
281
|
-
* service
|
|
282
|
-
*/
|
|
283
|
-
connectSocket() {
|
|
284
|
-
if (this.isConnected() || this.isConnecting()) {
|
|
285
|
-
// self resolving promise since we are already ready to send
|
|
286
|
-
// requests, if we did reach state 1, we already sent initial
|
|
287
|
-
// request, thus not sending it again.
|
|
288
|
-
return this.connectionPromise;
|
|
289
|
-
}
|
|
290
|
-
// we return a promisified socket resolver to be able to chain the
|
|
291
|
-
// opening of the socket
|
|
292
|
-
return this.handleConnect(false);
|
|
293
|
-
}
|
|
294
|
-
/** Calculates and sets the end_at field of the payload
|
|
295
|
-
* @param {} payload
|
|
296
|
-
* @param {} isPageVisit
|
|
297
|
-
*/
|
|
325
|
+
/** Calculates and sets the end_at field of the payload */
|
|
298
326
|
addEndTimeToPayload(payload, isPageVisit) {
|
|
299
327
|
const delta = Math.ceil(safePerformanceNow() - this.sessionStartTime);
|
|
300
328
|
// update session length if this is a page visit event
|
|
301
329
|
if (isPageVisit) {
|
|
302
330
|
this.sessionLength = delta;
|
|
303
331
|
}
|
|
304
|
-
return Object.assign(Object.assign({}, payload), {
|
|
332
|
+
return Object.assign(Object.assign({}, payload), { end_at: new Date(this.sessionTimestamp.getTime() + delta).toISOString() });
|
|
305
333
|
}
|
|
306
334
|
/** open handler for socket */
|
|
307
335
|
_onSocketOpen() {
|
|
@@ -310,7 +338,7 @@ class MetroplexSocket extends Singleton {
|
|
|
310
338
|
if (!this.isConnected() || ClientConfig.getInstance().isClientDisabled) {
|
|
311
339
|
return;
|
|
312
340
|
}
|
|
313
|
-
yield this.
|
|
341
|
+
yield this.sendSocketMessage(yield this.getPageInformation());
|
|
314
342
|
// Set this to allow normal page visit and video frag messages to be sent
|
|
315
343
|
this.pageVisitInfoSent = true;
|
|
316
344
|
this.currentConnectionAttempts = 0;
|
|
@@ -324,32 +352,30 @@ class MetroplexSocket extends Singleton {
|
|
|
324
352
|
this.connectionCount += 1;
|
|
325
353
|
});
|
|
326
354
|
}
|
|
327
|
-
/** message handler for socket
|
|
328
|
-
* @param {} event
|
|
329
|
-
*/
|
|
355
|
+
/** message handler for socket */
|
|
330
356
|
_onSocketMessage(event) {
|
|
331
357
|
return __awaiter(this, void 0, void 0, function* () {
|
|
332
358
|
switch (event.data) {
|
|
333
|
-
case
|
|
359
|
+
case InboundMessageType.VideoBlock:
|
|
334
360
|
// stopping vids from being sent
|
|
335
|
-
this.metroplexTypeLock
|
|
361
|
+
this.metroplexTypeLock.pvvf = true;
|
|
336
362
|
StoredMetrics.getInstance().setDidCutVideo();
|
|
337
363
|
break;
|
|
338
|
-
case
|
|
364
|
+
case InboundMessageType.PageVisitBlock:
|
|
339
365
|
// stopping pv from being sent
|
|
340
|
-
this.metroplexTypeLock
|
|
366
|
+
this.metroplexTypeLock.pvp = true;
|
|
341
367
|
StoredMetrics.getInstance().setDidCutPv();
|
|
342
368
|
break;
|
|
343
|
-
case
|
|
369
|
+
case InboundMessageType.FullBlock:
|
|
344
370
|
// we are disabling collect for 1 day if we get the
|
|
345
371
|
// block message from metroplex. We are probably on it
|
|
346
|
-
yield ClientConfig.getInstance().lockClient(1440, 'Metroplex blocked script');
|
|
372
|
+
yield ClientConfig.getInstance().lockClient(1440, { msg: 'Metroplex blocked script' });
|
|
347
373
|
this.close();
|
|
348
374
|
break;
|
|
349
|
-
case
|
|
375
|
+
case InboundMessageType.CloseConnection:
|
|
350
376
|
this.close();
|
|
351
377
|
break;
|
|
352
|
-
case
|
|
378
|
+
case InboundMessageType.OK:
|
|
353
379
|
// we do nothing on an OK
|
|
354
380
|
break;
|
|
355
381
|
default:
|
|
@@ -359,10 +385,10 @@ class MetroplexSocket extends Singleton {
|
|
|
359
385
|
// we now need to check if we receive text that contains
|
|
360
386
|
// the text SEQ_NUM. if that is true, then its a seq num
|
|
361
387
|
// and we need to clear out the retry queue.
|
|
362
|
-
if (event.data.includes(
|
|
363
|
-
const seqNumSplit = event.data.split(
|
|
388
|
+
if (event.data.includes('seq_num')) {
|
|
389
|
+
const seqNumSplit = event.data.split('seq_num:');
|
|
364
390
|
if (seqNumSplit.length < 2) {
|
|
365
|
-
ClientConfig.getInstance().
|
|
391
|
+
ClientConfig.getInstance().postInternalError({ msg: `Invalid message received from metroplex while clearing retry queue`, data: event.data }, false, Severity.ERROR);
|
|
366
392
|
break;
|
|
367
393
|
}
|
|
368
394
|
// the second element in the string split is the sequence number
|
|
@@ -399,10 +425,8 @@ class MetroplexSocket extends Singleton {
|
|
|
399
425
|
* Returns true if the message's payload has the payload type given and has a sequence
|
|
400
426
|
* number higher than seqNum
|
|
401
427
|
*/
|
|
402
|
-
_messagePayloadHasLargerSeqNum(message,
|
|
403
|
-
return
|
|
404
|
-
message.payload[payloadType][SEQ_NUM_ATT_NAME] &&
|
|
405
|
-
message.payload[payloadType][SEQ_NUM_ATT_NAME] > seqNum);
|
|
428
|
+
_messagePayloadHasLargerSeqNum(message, seqNum) {
|
|
429
|
+
return message.payload && message.payload.seq_num && message.payload.seq_num > seqNum;
|
|
406
430
|
}
|
|
407
431
|
/**
|
|
408
432
|
* removes messages from the retry queue that are smaller than the
|
|
@@ -410,8 +434,7 @@ class MetroplexSocket extends Singleton {
|
|
|
410
434
|
*/
|
|
411
435
|
_clearRetryQueue(seqNum) {
|
|
412
436
|
this.latestReceivedSeqNumStoredTime = new Date();
|
|
413
|
-
const newQueue = this.retryMessageQueue.filter(message => this._messagePayloadHasLargerSeqNum(message,
|
|
414
|
-
this._messagePayloadHasLargerSeqNum(message, PAGE_VISIT_VID_FRAG_ATT_NAME, seqNum));
|
|
437
|
+
const newQueue = this.retryMessageQueue.filter(message => this._messagePayloadHasLargerSeqNum(message, seqNum));
|
|
415
438
|
this.retryMessageQueue = createSlidingArrayOfSize(MAX_RETRY_MSG_Q_SIZE, newQueue);
|
|
416
439
|
}
|
|
417
440
|
/** will resend everything that is in the retry queue */
|
|
@@ -438,13 +461,12 @@ class MetroplexSocket extends Singleton {
|
|
|
438
461
|
}
|
|
439
462
|
}
|
|
440
463
|
// removing all the messages with a blocked type from the retry queue
|
|
441
|
-
this.retryMessageQueue = this.retryMessageQueue.filter(message => !
|
|
464
|
+
this.retryMessageQueue = this.retryMessageQueue.filter(message => !this.metroplexTypeLock[message.type]);
|
|
442
465
|
// we dont remove any items from this queue in this function
|
|
443
466
|
for (let i = 0; i < this.retryMessageQueue.length; i += 1) {
|
|
444
467
|
const { type, payload } = this.retryMessageQueue[i];
|
|
445
468
|
// sending the data to metroplex
|
|
446
|
-
|
|
447
|
-
yield this._sendSocketMessage(payload);
|
|
469
|
+
yield this.sendSocketMessage({ [type]: payload });
|
|
448
470
|
this.previousMessageType = type;
|
|
449
471
|
}
|
|
450
472
|
});
|
|
@@ -455,12 +477,6 @@ class MetroplexSocket extends Singleton {
|
|
|
455
477
|
this._sendUnconfirmedMessages(true);
|
|
456
478
|
}, METROPLEX_RETRY_FREQUENCY);
|
|
457
479
|
}
|
|
458
|
-
/** sets up events that will trigger the event queue to be emptied */
|
|
459
|
-
_setupOffloadEvents() {
|
|
460
|
-
// when the page hides we try getting all the events
|
|
461
|
-
// and empty the event and retry queue.
|
|
462
|
-
addSafeEventListener(window, 'pagehide', () => this._handleUnload(), false);
|
|
463
|
-
}
|
|
464
480
|
/**
|
|
465
481
|
* will handle the final moments of a page being active. It
|
|
466
482
|
* will try to empty both the queues with beacons.
|
|
@@ -488,26 +504,29 @@ class MetroplexSocket extends Singleton {
|
|
|
488
504
|
*/
|
|
489
505
|
postFullPageVisit(maxMessageSize) {
|
|
490
506
|
return __awaiter(this, void 0, void 0, function* () {
|
|
507
|
+
var _a;
|
|
491
508
|
if (this.retryMessageQueue.length === 0) {
|
|
492
509
|
return;
|
|
493
510
|
}
|
|
494
511
|
// debug counters
|
|
495
512
|
const postInfo = [];
|
|
496
513
|
const numDropped = {
|
|
497
|
-
|
|
498
|
-
|
|
514
|
+
pvvf: 0,
|
|
515
|
+
pvp: 0,
|
|
516
|
+
pvh: 0,
|
|
499
517
|
};
|
|
500
518
|
let currentMsgPayloadSize = 0;
|
|
501
519
|
let currentCompletePv = {
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
520
|
+
pvi: yield this.getPageInformation(),
|
|
521
|
+
pvp: [],
|
|
522
|
+
pvvf: [],
|
|
523
|
+
pvh: [],
|
|
524
|
+
vpnum: this.connectionCount,
|
|
507
525
|
};
|
|
508
|
-
currentCompletePv
|
|
526
|
+
currentCompletePv.pvi.last = true;
|
|
509
527
|
const pageInfo = yield this.getPageInformation();
|
|
510
528
|
this.retryMessageQueue.forEach(msg => {
|
|
529
|
+
var _a, _b, _c;
|
|
511
530
|
// can't use two variables types in obj deconstruction
|
|
512
531
|
// eslint-disable-next-line prefer-const
|
|
513
532
|
let { type, payload } = msg;
|
|
@@ -522,81 +541,84 @@ class MetroplexSocket extends Singleton {
|
|
|
522
541
|
if (currentMsgPayloadSize >= maxMessageSize) {
|
|
523
542
|
this.postMessage(currentCompletePv);
|
|
524
543
|
// add to post info
|
|
525
|
-
let postInfoMessage = `Vid: ${currentCompletePv
|
|
526
|
-
postInfoMessage += ` PV: ${currentCompletePv
|
|
527
|
-
postInfoMessage += ` HTTP: ${currentCompletePv
|
|
544
|
+
let postInfoMessage = `Vid: ${currentCompletePv.pvvf.length}`;
|
|
545
|
+
postInfoMessage += ` PV: ${currentCompletePv.pvp.length}`;
|
|
546
|
+
postInfoMessage += ` HTTP: ${(_a = currentCompletePv.pvh) === null || _a === void 0 ? void 0 : _a.length},`;
|
|
528
547
|
postInfo.push(postInfoMessage);
|
|
529
548
|
// resetting currentCompletePv, since we need to keep adding
|
|
530
549
|
// events to a blank object to send to metroplex.
|
|
531
550
|
// retain the video part count, so we don't overwrite anything
|
|
532
551
|
currentCompletePv = {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
552
|
+
pvi: pageInfo,
|
|
553
|
+
pvp: [],
|
|
554
|
+
pvvf: [],
|
|
555
|
+
pvh: [],
|
|
556
|
+
vpnum: currentCompletePv.vpnum,
|
|
538
557
|
};
|
|
539
|
-
currentCompletePv
|
|
540
|
-
true;
|
|
558
|
+
currentCompletePv.pvi.last = true;
|
|
541
559
|
// resetting the message size based on what is being added
|
|
542
560
|
currentMsgPayloadSize = currentPayloadSize;
|
|
543
561
|
}
|
|
544
|
-
switch (type) {
|
|
545
|
-
case
|
|
546
|
-
currentCompletePv
|
|
562
|
+
switch (msg.type) {
|
|
563
|
+
case WebsocketMessageType.PageVisitVideoFile:
|
|
564
|
+
currentCompletePv.pvvf.push(msg.payload);
|
|
547
565
|
break;
|
|
548
|
-
case
|
|
549
|
-
currentCompletePv
|
|
566
|
+
case WebsocketMessageType.PageVisitPart:
|
|
567
|
+
currentCompletePv.pvp.push(msg.payload);
|
|
550
568
|
break;
|
|
551
|
-
case
|
|
552
|
-
currentCompletePv
|
|
569
|
+
case WebsocketMessageType.PageVisitHttp:
|
|
570
|
+
(_c = (_b = currentCompletePv.pvh) === null || _b === void 0 ? void 0 : _b.push) === null || _c === void 0 ? void 0 : _c.call(_b, msg.payload);
|
|
553
571
|
break;
|
|
554
572
|
}
|
|
555
573
|
});
|
|
556
|
-
this.postMessage(currentCompletePv);
|
|
574
|
+
yield this.postMessage(currentCompletePv);
|
|
557
575
|
// debug log if large retry message queue
|
|
558
576
|
if (this.retryMessageQueue.length > 100) {
|
|
559
|
-
let postInfoMessage = `Vid: ${currentCompletePv
|
|
560
|
-
postInfoMessage += ` PV: ${currentCompletePv
|
|
561
|
-
postInfoMessage += ` HTTP: ${currentCompletePv
|
|
577
|
+
let postInfoMessage = `Vid: ${currentCompletePv.pvvf.length}`;
|
|
578
|
+
postInfoMessage += ` PV: ${currentCompletePv.pvp.length}`;
|
|
579
|
+
postInfoMessage += ` HTTP: ${(_a = currentCompletePv.pvh) === null || _a === void 0 ? void 0 : _a.length},`;
|
|
562
580
|
postInfo.push(postInfoMessage);
|
|
563
581
|
// we completed posted the full pv, send the confirmation debug logs
|
|
564
582
|
// build the debug message
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
583
|
+
const message = {
|
|
584
|
+
msg: `POST Full PV complete`,
|
|
585
|
+
postsCount: postInfo.length,
|
|
586
|
+
postsInfo: stringifyJSON(postInfo),
|
|
587
|
+
retryMessageQueueSize: this.retryMessageQueue.length,
|
|
588
|
+
};
|
|
571
589
|
// Num drops
|
|
572
|
-
if (numDropped
|
|
573
|
-
message
|
|
590
|
+
if (numDropped.pvvf > 0) {
|
|
591
|
+
message.videoPartsDropped = numDropped.pvvf;
|
|
574
592
|
}
|
|
575
|
-
if (numDropped
|
|
576
|
-
message
|
|
593
|
+
if (numDropped.pvp > 0) {
|
|
594
|
+
message.pvpPartsDropped = numDropped.pvp;
|
|
577
595
|
}
|
|
578
|
-
if (numDropped
|
|
579
|
-
message
|
|
596
|
+
if (numDropped.pvh > 0) {
|
|
597
|
+
message.httpPartsDropped = numDropped.pvh;
|
|
580
598
|
}
|
|
581
599
|
// Sequence info
|
|
582
|
-
message
|
|
583
|
-
|
|
600
|
+
message.sequenceInfo = {
|
|
601
|
+
Latest: this.messageSequenceNum,
|
|
602
|
+
acked: {
|
|
603
|
+
latestReceivedSeqNumStoredTime: this.latestReceivedSeqNumStoredTime,
|
|
604
|
+
latestReceivedSeqNumber: this.latestReceivedSeqNumber,
|
|
605
|
+
},
|
|
606
|
+
};
|
|
584
607
|
// if client was disabled (due to inactive or otherwise) enable briefly so the
|
|
585
608
|
// debug message gets through
|
|
586
609
|
const clientDisabled = ClientConfig.getInstance().isClientDisabled;
|
|
587
610
|
ClientConfig.getInstance().isClientDisabled = false;
|
|
588
|
-
ClientConfig.getInstance().
|
|
611
|
+
ClientConfig.getInstance().postInternalError(message, clientDisabled, Severity.WARN);
|
|
589
612
|
}
|
|
590
613
|
});
|
|
591
614
|
}
|
|
592
|
-
/**
|
|
593
|
-
* will send a message to metroplex via a post request that will outlive the current page
|
|
594
|
-
*/
|
|
615
|
+
/** will send a message to metroplex via a post request that will outlive the current page */
|
|
595
616
|
postMessage(msg) {
|
|
596
617
|
return __awaiter(this, void 0, void 0, function* () {
|
|
597
618
|
const updatedMsg = msg;
|
|
619
|
+
updatedMsg.vpnum || (updatedMsg.vpnum = 0);
|
|
598
620
|
// ensure a unique video part number each call
|
|
599
|
-
updatedMsg
|
|
621
|
+
updatedMsg.vpnum += 1;
|
|
600
622
|
// we send the remainder elements
|
|
601
623
|
unwrapNoibuWrapped(fetch)(this.postURL, {
|
|
602
624
|
method: 'POST',
|
|
@@ -615,18 +637,16 @@ class MetroplexSocket extends Singleton {
|
|
|
615
637
|
* is active and returns true. If inactive the session and socket are closed
|
|
616
638
|
* and this method returns false.
|
|
617
639
|
*/
|
|
618
|
-
|
|
640
|
+
sendSocketMessage(payload) {
|
|
619
641
|
return __awaiter(this, void 0, void 0, function* () {
|
|
620
|
-
noibuLog('
|
|
642
|
+
noibuLog('sendSocketMessage');
|
|
621
643
|
const closeIfInactive = yield this.closeIfInactive();
|
|
622
644
|
if (closeIfInactive) {
|
|
623
|
-
noibuLog('
|
|
645
|
+
noibuLog('sendSocketMessage dropped due to', { closeIfInactive });
|
|
624
646
|
return;
|
|
625
647
|
}
|
|
648
|
+
noibuLog(`_sendSocketMessage sending: `, payload);
|
|
626
649
|
const payloadJson = stringifyJSON(payload);
|
|
627
|
-
noibuLog(`_sendSocketMessage sending: ${PAGE_VISIT_VID_FRAG_ATT_NAME in payload
|
|
628
|
-
? PAGE_VISIT_VID_FRAG_ATT_NAME
|
|
629
|
-
: payloadJson}`);
|
|
630
650
|
if (this.socket) {
|
|
631
651
|
this.socket.send(payloadJson);
|
|
632
652
|
}
|
|
@@ -644,7 +664,7 @@ class MetroplexSocket extends Singleton {
|
|
|
644
664
|
// lock the client for 1 minute, since the lock expires
|
|
645
665
|
// only on new page loads this will lock the client until
|
|
646
666
|
// the next page is loaded.
|
|
647
|
-
yield ClientConfig.getInstance().lockClientUntilNextPage('Session is inactive, locking until next page');
|
|
667
|
+
yield ClientConfig.getInstance().lockClientUntilNextPage({ msg: 'Session is inactive, locking until next page' });
|
|
648
668
|
this.close();
|
|
649
669
|
// post metrics now so we don't include events after going inactive
|
|
650
670
|
StoredMetrics.getInstance().postMetrics();
|
|
@@ -658,29 +678,27 @@ class MetroplexSocket extends Singleton {
|
|
|
658
678
|
getPageInformation() {
|
|
659
679
|
return __awaiter(this, void 0, void 0, function* () {
|
|
660
680
|
return {
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
681
|
+
br_id: ClientConfig.getInstance().browserId,
|
|
682
|
+
pv_id: ClientConfig.getInstance().pageVisitId,
|
|
683
|
+
v: CURRENT_PV_VERSION,
|
|
684
|
+
seq: yield ClientConfig.getInstance().getPageVisitSeq(),
|
|
685
|
+
on_url: this.initialURL,
|
|
686
|
+
ref_url: this.initialReferringURL,
|
|
687
|
+
start_at: this.sessionTimestamp.toISOString(),
|
|
688
|
+
conc: this.connectionCount,
|
|
689
|
+
cv: CURRENT_NOIBUJS_VERSION,
|
|
690
|
+
last: false,
|
|
691
|
+
script_id: GET_SCRIPT_ID(),
|
|
692
|
+
script_inst_id: this.scriptInstanceId,
|
|
693
|
+
mp_sock_inst_id: this.instanceId,
|
|
694
|
+
sock_inst_id: this.socketInstanceId,
|
|
695
|
+
video_recorder: yield getVideoRecorderType(),
|
|
676
696
|
};
|
|
677
697
|
});
|
|
678
698
|
}
|
|
679
|
-
/**
|
|
680
|
-
* Try to parse help code response and fire custom event
|
|
681
|
-
*/
|
|
699
|
+
/** Try to parse help code response and fire custom event */
|
|
682
700
|
_tryProcessHelpCodeResponse(response) {
|
|
683
|
-
const prefix = `${
|
|
701
|
+
const prefix = `${WorkRequestMessageType.HelpCode}:`;
|
|
684
702
|
if (typeof response !== 'string' || !response.startsWith(prefix)) {
|
|
685
703
|
return false;
|
|
686
704
|
}
|
|
@@ -692,11 +710,5 @@ class MetroplexSocket extends Singleton {
|
|
|
692
710
|
return true;
|
|
693
711
|
}
|
|
694
712
|
}
|
|
695
|
-
MetroplexSocket.typeToPayloadPropMap = {
|
|
696
|
-
[HTTP_DATA_METROPLEX_TYPE]: PAGE_VISIT_HTTP_DATA_ATT_NAME,
|
|
697
|
-
[META_DATA_METROPLEX_TYPE]: PAGE_VISIT_META_DATA_ATT_NAME,
|
|
698
|
-
[PV_METROPLEX_TYPE]: PAGE_VISIT_PART_ATT_NAME,
|
|
699
|
-
[VIDEO_METROPLEX_TYPE]: PAGE_VISIT_VID_FRAG_ATT_NAME,
|
|
700
|
-
};
|
|
701
713
|
|
|
702
|
-
export { createSlidingArrayOfSize, MetroplexSocket as default };
|
|
714
|
+
export { createSlidingArrayOfSize, MetroplexSocket as default, getVideoRecorderType };
|