iidrak-analytics-react 1.5.0 → 1.5.1
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.
|
@@ -52,53 +52,35 @@ class MetaStreamIONetwork {
|
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
// Background heartbeat to auto-flush stuck events gracefully
|
|
56
55
|
this._flushInterval = setInterval(() => {
|
|
57
56
|
this.flushEvents();
|
|
58
|
-
}, 3000); //
|
|
57
|
+
}, 3000); // Reverted back to 3 seconds. (Locking guarantees safety)
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
reset() {
|
|
62
61
|
this.endpoint = null;
|
|
62
|
+
this._testingPromise = null;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
async testConnection() {
|
|
66
|
-
if (
|
|
66
|
+
if (this.endpoint) return Promise.resolve(this.endpoint);
|
|
67
|
+
if (this._testingPromise) return this._testingPromise;
|
|
68
|
+
|
|
69
|
+
this._testingPromise = (async () => {
|
|
67
70
|
for (let _e in this.endpoints) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return this.endpoints[_e];
|
|
73
|
-
}
|
|
74
|
-
return false;
|
|
75
|
-
} catch (err) {
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
})
|
|
79
|
-
.catch(() => { return false; });
|
|
80
|
-
if (this.endpoint) {
|
|
81
|
-
this.logger.log(
|
|
82
|
-
"network",
|
|
83
|
-
this.constant.MetaStreamIO_Network_EndpointSet.format(this.endpoint)
|
|
84
|
-
);
|
|
71
|
+
let testEp = await this.getData({ endpoint: this.endpoints[_e] });
|
|
72
|
+
if (testEp && testEp.status > 0) {
|
|
73
|
+
this.logger.log("network", this.constant.MetaStreamIO_Network_EndpointSet.format(this.endpoints[_e]));
|
|
74
|
+
this.endpoint = this.endpoints[_e];
|
|
85
75
|
break;
|
|
86
76
|
} else {
|
|
87
|
-
this.logger.log(
|
|
88
|
-
"network",
|
|
89
|
-
this.constant.MetaStreamIO_Network_EndpointTestFailed.format(
|
|
90
|
-
this.endpoint
|
|
91
|
-
)
|
|
92
|
-
);
|
|
93
|
-
this.logger.log(
|
|
94
|
-
"network",
|
|
95
|
-
this.constant.MetaStreamIO_Network_SilentModeEnabled
|
|
96
|
-
);
|
|
77
|
+
this.logger.log("network", this.constant.MetaStreamIO_Network_EndpointTestFailed.format(this.endpoints[_e]));
|
|
97
78
|
}
|
|
98
79
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
80
|
+
this._testingPromise = null;
|
|
81
|
+
return this.endpoint;
|
|
82
|
+
})();
|
|
83
|
+
return this._testingPromise;
|
|
102
84
|
}
|
|
103
85
|
|
|
104
86
|
async getData({ endpoint = this.endpoint } = {}) {
|
|
@@ -115,14 +97,16 @@ class MetaStreamIONetwork {
|
|
|
115
97
|
get_config.headers = Object.assign(get_config.headers, this.headers);
|
|
116
98
|
}
|
|
117
99
|
|
|
100
|
+
const controller = new AbortController();
|
|
101
|
+
const timeoutId = setTimeout(() => controller.abort(), 3000);
|
|
102
|
+
get_config.signal = controller.signal;
|
|
103
|
+
|
|
118
104
|
try {
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
fetch(endpoint, get_config),
|
|
122
|
-
timeoutPromise
|
|
123
|
-
]);
|
|
105
|
+
const response = await fetch(endpoint, get_config);
|
|
106
|
+
clearTimeout(timeoutId);
|
|
124
107
|
return { status: response.status, body: "OK" };
|
|
125
108
|
} catch (err) {
|
|
109
|
+
clearTimeout(timeoutId);
|
|
126
110
|
return { status: 0, body: String(err) };
|
|
127
111
|
}
|
|
128
112
|
}
|
|
@@ -229,13 +213,13 @@ class MetaStreamIONetwork {
|
|
|
229
213
|
return { status: 200, body: "Stored offline" };
|
|
230
214
|
}
|
|
231
215
|
|
|
232
|
-
const
|
|
216
|
+
const controller = new AbortController();
|
|
217
|
+
const timeoutId = setTimeout(() => controller.abort(), 3000);
|
|
218
|
+
post_config.signal = controller.signal;
|
|
233
219
|
|
|
234
|
-
await
|
|
235
|
-
fetch(endpoint, post_config),
|
|
236
|
-
timeoutPromise
|
|
237
|
-
])
|
|
220
|
+
await fetch(endpoint, post_config)
|
|
238
221
|
.then((response) => {
|
|
222
|
+
clearTimeout(timeoutId);
|
|
239
223
|
rx.status = response.status;
|
|
240
224
|
let _contentType = response.headers.get("content-type");
|
|
241
225
|
if (!_contentType || !_contentType.includes("application/json")) {
|
|
@@ -252,6 +236,7 @@ class MetaStreamIONetwork {
|
|
|
252
236
|
}
|
|
253
237
|
})
|
|
254
238
|
.catch(async (err) => {
|
|
239
|
+
clearTimeout(timeoutId);
|
|
255
240
|
this.logger.warn("network", "fetch() error in post()", err.message || err);
|
|
256
241
|
rx.status = 500;
|
|
257
242
|
rx.body = "fetch error";
|
|
@@ -303,11 +288,18 @@ class MetaStreamIONetwork {
|
|
|
303
288
|
// Pre-flight check: Do not spam the Native Bridge with 20 offline events if the server route is down
|
|
304
289
|
const pingEndpoint = this.endpoint || (this.endpoints.length > 0 ? this.endpoints[0] : null);
|
|
305
290
|
if (pingEndpoint) {
|
|
306
|
-
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
291
|
+
let routeValid = false;
|
|
292
|
+
const controller = new AbortController();
|
|
293
|
+
const timeoutId = setTimeout(() => controller.abort(), 1500);
|
|
294
|
+
|
|
295
|
+
try {
|
|
296
|
+
await fetch(pingEndpoint, { method: "OPTIONS", signal: controller.signal });
|
|
297
|
+
routeValid = true;
|
|
298
|
+
} catch (err) {
|
|
299
|
+
routeValid = false;
|
|
300
|
+
} finally {
|
|
301
|
+
clearTimeout(timeoutId);
|
|
302
|
+
}
|
|
311
303
|
|
|
312
304
|
if (!routeValid) {
|
|
313
305
|
this.logger.log("network", "flushEvents aborted: Node route not fully established natively yet.");
|
|
@@ -322,17 +314,17 @@ class MetaStreamIONetwork {
|
|
|
322
314
|
if (this.headers) {
|
|
323
315
|
reqHeaders = Object.assign(reqHeaders, this.headers);
|
|
324
316
|
}
|
|
325
|
-
const
|
|
317
|
+
const controller = new AbortController();
|
|
318
|
+
const timeoutId = setTimeout(() => controller.abort(), 3000);
|
|
326
319
|
|
|
327
320
|
try {
|
|
328
|
-
const response = await
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
]);
|
|
321
|
+
const response = await fetch(e.endpoint, {
|
|
322
|
+
method: "POST",
|
|
323
|
+
headers: reqHeaders,
|
|
324
|
+
body: JSON.stringify(e.payload),
|
|
325
|
+
signal: controller.signal
|
|
326
|
+
});
|
|
327
|
+
clearTimeout(timeoutId);
|
|
336
328
|
|
|
337
329
|
if (response.ok) {
|
|
338
330
|
this.logger.log("network", "Retried & sent event successfully.");
|
|
@@ -340,6 +332,7 @@ class MetaStreamIONetwork {
|
|
|
340
332
|
this.logger.warn("network", `Retry got non-OK status (${response.status}), dropping event.`);
|
|
341
333
|
}
|
|
342
334
|
} catch (err) {
|
|
335
|
+
clearTimeout(timeoutId);
|
|
343
336
|
this.logger.log("network", "Retry failed (still offline or bad host), keeping event.", err.message);
|
|
344
337
|
remainingEvents.push(e);
|
|
345
338
|
}
|
|
@@ -57,12 +57,19 @@ Queue.prototype.peek = function () {
|
|
|
57
57
|
* The MetaStreamIO SAUCE
|
|
58
58
|
*
|
|
59
59
|
*/
|
|
60
|
-
Queue.prototype.run = function (callback) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
Queue.prototype.run = async function (callback) {
|
|
61
|
+
if (this._isRunning) return;
|
|
62
|
+
this._isRunning = true;
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
while (this.size() > 0) {
|
|
66
|
+
await callback(this.dequeue()).catch(err => {
|
|
67
|
+
console.error('<queue callback>', err);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
} finally {
|
|
71
|
+
this._isRunning = false;
|
|
65
72
|
}
|
|
66
73
|
};
|
|
67
74
|
|
|
68
|
-
export {Queue};
|
|
75
|
+
export { Queue };
|
|
@@ -139,9 +139,14 @@ class MetaStreamIORecorder {
|
|
|
139
139
|
// Note: We use a separate fetch here because the payload format is different from standard analytics
|
|
140
140
|
const url = `${this.endpoint}/api/apps/${this.app_id}/sessions`;
|
|
141
141
|
this.logger.log("recorder", `Sending session creation request to: ${url}`);
|
|
142
|
+
|
|
143
|
+
const controller = new AbortController();
|
|
144
|
+
const timeoutId = setTimeout(() => controller.abort(), 3000);
|
|
145
|
+
|
|
142
146
|
await fetch(url, {
|
|
143
147
|
method: 'POST',
|
|
144
148
|
headers: { 'Content-Type': 'application/json' },
|
|
149
|
+
signal: controller.signal,
|
|
145
150
|
body: JSON.stringify({
|
|
146
151
|
session_id: this.sessionId,
|
|
147
152
|
device_info: {
|
|
@@ -152,6 +157,7 @@ class MetaStreamIORecorder {
|
|
|
152
157
|
}
|
|
153
158
|
})
|
|
154
159
|
}).then(async res => {
|
|
160
|
+
clearTimeout(timeoutId);
|
|
155
161
|
this.logger.log("recorder", "Session creation response status: " + res.status);
|
|
156
162
|
if (res.ok) {
|
|
157
163
|
const data = await res.json();
|
|
@@ -164,6 +170,7 @@ class MetaStreamIORecorder {
|
|
|
164
170
|
this.logger.error("recorder", "Failed to start session on recording server: " + res.status);
|
|
165
171
|
}
|
|
166
172
|
}).catch(e => {
|
|
173
|
+
clearTimeout(timeoutId);
|
|
167
174
|
this.logger.error("recorder", "Connection error to recording server: " + e + " to " + url);
|
|
168
175
|
});
|
|
169
176
|
|
|
@@ -200,6 +207,9 @@ class MetaStreamIORecorder {
|
|
|
200
207
|
console.log("Starting loop");
|
|
201
208
|
this.intervalId = setInterval(async () => {
|
|
202
209
|
if (!viewRef.current) return;
|
|
210
|
+
if (this._isCapturing) return;
|
|
211
|
+
|
|
212
|
+
this._isCapturing = true;
|
|
203
213
|
|
|
204
214
|
try {
|
|
205
215
|
// Capture as base64 for comparison and direct upload
|
|
@@ -241,13 +251,15 @@ class MetaStreamIORecorder {
|
|
|
241
251
|
// Measure privacy zones
|
|
242
252
|
const zones = await this.measurePrivacyZones(viewRef);
|
|
243
253
|
|
|
244
|
-
console.log("DBG:: Uploading frame with " + zones.length + " privacy zones");
|
|
245
|
-
this.uploadFrame(base64, isDuplicate, zones);
|
|
254
|
+
// console.log("DBG:: Uploading frame with " + zones.length + " privacy zones");
|
|
255
|
+
await this.uploadFrame(base64, isDuplicate, zones);
|
|
246
256
|
this.lastUploadTime = now;
|
|
247
257
|
this.lastBase64 = base64;
|
|
248
258
|
}
|
|
249
259
|
} catch (e) {
|
|
250
260
|
// Silent fail on capture error to avoid log spam
|
|
261
|
+
} finally {
|
|
262
|
+
this._isCapturing = false;
|
|
251
263
|
}
|
|
252
264
|
}, intervalMs);
|
|
253
265
|
}
|
|
@@ -277,13 +289,18 @@ class MetaStreamIORecorder {
|
|
|
277
289
|
}
|
|
278
290
|
|
|
279
291
|
try {
|
|
292
|
+
const controller = new AbortController();
|
|
293
|
+
const timeoutId = setTimeout(() => controller.abort(), 1500);
|
|
294
|
+
|
|
280
295
|
await fetch(`${this.endpoint}/api/apps/${this.app_id}/sessions/${this.recorderSessionId}/screenshot`, {
|
|
281
296
|
method: 'POST',
|
|
282
297
|
body: formData,
|
|
283
298
|
headers: {
|
|
284
299
|
'Content-Type': 'multipart/form-data',
|
|
285
|
-
}
|
|
300
|
+
},
|
|
301
|
+
signal: controller.signal
|
|
286
302
|
});
|
|
303
|
+
clearTimeout(timeoutId);
|
|
287
304
|
} catch (e) {
|
|
288
305
|
// Network error, drop frame
|
|
289
306
|
}
|
|
@@ -304,11 +321,15 @@ class MetaStreamIORecorder {
|
|
|
304
321
|
};
|
|
305
322
|
|
|
306
323
|
try {
|
|
324
|
+
const controller = new AbortController();
|
|
325
|
+
const timeoutId = setTimeout(() => controller.abort(), 1500);
|
|
326
|
+
|
|
307
327
|
fetch(`${this.endpoint}/api/apps/${this.app_id}/sessions/${this.recorderSessionId}/events`, {
|
|
308
328
|
method: 'POST',
|
|
309
329
|
headers: { 'Content-Type': 'application/json' },
|
|
310
|
-
body: JSON.stringify([event])
|
|
311
|
-
|
|
330
|
+
body: JSON.stringify([event]),
|
|
331
|
+
signal: controller.signal
|
|
332
|
+
}).then(() => clearTimeout(timeoutId)).catch(() => clearTimeout(timeoutId));
|
|
312
333
|
} catch (e) { }
|
|
313
334
|
}
|
|
314
335
|
}
|