@newtonschool/react_proctoring_library 0.0.133-beta.0 → 0.0.133-beta.2

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.
@@ -7,18 +7,21 @@ exports.updateCurrentDeviceStatus = exports.setupDeviceStatusListeners = exports
7
7
  var _defaults = require("../constants/defaults");
8
8
  var _proctoringDebugUtils = require("./proctoringDebugUtils");
9
9
  const HEARTBEAT_INTERVAL_MS = 5000;
10
- const OTHER_DEVICE_HEARTBEAT_TIMEOUT_MS = 15000;
10
+ const OTHER_DEVICE_HEARTBEAT_TIMEOUT_MS = 20000;
11
+ const SERVER_TIMESTAMP = {
12
+ '.sv': 'timestamp'
13
+ };
11
14
  const getErrorPayload = error => ({
12
15
  name: (error === null || error === void 0 ? void 0 : error.name) || null,
13
16
  message: (error === null || error === void 0 ? void 0 : error.message) || String(error)
14
17
  });
15
18
  const getObservedStatusPayload = function getObservedStatusPayload(status) {
16
- let now = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Date.now();
19
+ let now = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
17
20
  return {
18
21
  connected: Boolean(status === null || status === void 0 ? void 0 : status.connected),
19
22
  allPermissionGranted: typeof (status === null || status === void 0 ? void 0 : status.allPermissionGranted) === 'boolean' ? status.allPermissionGranted : null,
20
23
  lastHeartbeatAt: typeof (status === null || status === void 0 ? void 0 : status.lastHeartbeatAt) === 'number' ? status.lastHeartbeatAt : null,
21
- heartbeatAgeMs: typeof (status === null || status === void 0 ? void 0 : status.lastHeartbeatAt) === 'number' ? now - status.lastHeartbeatAt : null,
24
+ heartbeatAgeMs: typeof now === 'number' && typeof (status === null || status === void 0 ? void 0 : status.lastHeartbeatAt) === 'number' ? now - status.lastHeartbeatAt : null,
22
25
  deviceId: (status === null || status === void 0 ? void 0 : status.deviceId) || null
23
26
  };
24
27
  };
@@ -166,8 +169,16 @@ const setupDeviceStatusListeners = _ref2 => {
166
169
  const secondaryDeviceStatusRef = ref(myFirebaseDB, "".concat(_defaults.PROCTORING_STATUS_PATH, "/").concat(userUuid, "/secondaryDevice"));
167
170
  const currentDeviceStatusRef = isSecondaryDevice ? secondaryDeviceStatusRef : primaryDeviceStatusRef;
168
171
  const otherDeviceStatusRef = isSecondaryDevice ? primaryDeviceStatusRef : secondaryDeviceStatusRef;
172
+ const serverTimeOffsetRef = ref(myFirebaseDB, '.info/serverTimeOffset');
169
173
  let latestPrimaryDeviceStatus = null;
170
174
  let latestSecondaryDeviceStatus = null;
175
+ let serverTimeOffsetMs = null;
176
+ const getComparableNow = () => {
177
+ if (typeof serverTimeOffsetMs !== 'number') {
178
+ return null;
179
+ }
180
+ return Date.now() + serverTimeOffsetMs;
181
+ };
171
182
 
172
183
  // When this client disconnects (tab close, network loss)
173
184
  onDisconnect(currentDeviceStatusRef).update({
@@ -208,7 +219,7 @@ const setupDeviceStatusListeners = _ref2 => {
208
219
  deviceType,
209
220
  observedDeviceType: 'secondary',
210
221
  source,
211
- observedStatus: getObservedStatusPayload(val)
222
+ observedStatus: getObservedStatusPayload(val, getComparableNow())
212
223
  }, firebaseClient);
213
224
  }
214
225
  onSecondaryDeviceStatusChange(Boolean(val === null || val === void 0 ? void 0 : val.connected), val === null || val === void 0 ? void 0 : val.allPermissionGranted);
@@ -227,16 +238,22 @@ const setupDeviceStatusListeners = _ref2 => {
227
238
  const unsubscribeSecondary = onValue(secondaryDeviceStatusRef, snapshot => {
228
239
  applySecondarySnapshot(snapshot);
229
240
  });
241
+ const unsubscribeServerTimeOffset = onValue(serverTimeOffsetRef, snapshot => {
242
+ var _snapshot$val5, _snapshot$val6;
243
+ const offsetValue = (_snapshot$val5 = snapshot === null || snapshot === void 0 ? void 0 : (_snapshot$val6 = snapshot.val) === null || _snapshot$val6 === void 0 ? void 0 : _snapshot$val6.call(snapshot)) !== null && _snapshot$val5 !== void 0 ? _snapshot$val5 : snapshot;
244
+ serverTimeOffsetMs = typeof offsetValue === 'number' ? offsetValue : serverTimeOffsetMs;
245
+ });
230
246
 
231
247
  // Start heartbeat interval
232
248
  let heartbeatIntervalId = null;
233
249
  if (typeof window !== 'undefined' && typeof setInterval === 'function') {
234
250
  heartbeatIntervalId = setInterval(() => {
235
- const now = Date.now();
251
+ const clientNow = Date.now();
252
+ const comparableNow = getComparableNow();
236
253
  if (isCurrentDeviceActive) {
237
254
  update(currentDeviceStatusRef, {
238
255
  connected: true,
239
- lastHeartbeatAt: now
256
+ lastHeartbeatAt: SERVER_TIMESTAMP
240
257
  }).then(() => {}).catch(error => {
241
258
  if (!isSecondaryDevice) {
242
259
  return;
@@ -245,7 +262,7 @@ const setupDeviceStatusListeners = _ref2 => {
245
262
  deviceType,
246
263
  userUuid,
247
264
  isCurrentDeviceActive,
248
- now,
265
+ now: comparableNow !== null && comparableNow !== void 0 ? comparableNow : clientNow,
249
266
  isSecondaryDevice,
250
267
  error: getErrorPayload(error)
251
268
  }, firebaseClient);
@@ -262,7 +279,7 @@ const setupDeviceStatusListeners = _ref2 => {
262
279
  (0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_current_device_marked_inactive', {
263
280
  deviceType,
264
281
  userUuid,
265
- now,
282
+ now: comparableNow !== null && comparableNow !== void 0 ? comparableNow : clientNow,
266
283
  isSecondaryDevice
267
284
  }, firebaseClient);
268
285
  }).catch(error => {
@@ -272,7 +289,7 @@ const setupDeviceStatusListeners = _ref2 => {
272
289
  (0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_device_status_write_failed', {
273
290
  deviceType,
274
291
  userUuid,
275
- now,
292
+ now: comparableNow !== null && comparableNow !== void 0 ? comparableNow : clientNow,
276
293
  payload: {
277
294
  connected: false,
278
295
  source: 'inactive_page_state'
@@ -287,10 +304,28 @@ const setupDeviceStatusListeners = _ref2 => {
287
304
  const otherDeviceStatus = isSecondaryDevice ? latestPrimaryDeviceStatus : latestSecondaryDeviceStatus;
288
305
  const lastBeat = otherDeviceStatus === null || otherDeviceStatus === void 0 ? void 0 : otherDeviceStatus.lastHeartbeatAt;
289
306
  const isConnected = Boolean(otherDeviceStatus === null || otherDeviceStatus === void 0 ? void 0 : otherDeviceStatus.connected);
290
- if (isConnected && typeof lastBeat === 'number' && now - lastBeat > OTHER_DEVICE_HEARTBEAT_TIMEOUT_MS) {
307
+ if (typeof comparableNow === 'number' && isConnected && typeof lastBeat === 'number' && comparableNow - lastBeat > OTHER_DEVICE_HEARTBEAT_TIMEOUT_MS) {
291
308
  update(otherDeviceStatusRef, {
292
309
  connected: false
293
- }).then(() => {}).catch(otherErr => {
310
+ }).then(() => {
311
+ const isMarkingSecondaryDeviceStale = !isSecondaryDevice;
312
+ if (!isMarkingSecondaryDeviceStale) {
313
+ return;
314
+ }
315
+ (0, _proctoringDebugUtils.emitProctoringDebugLog)('primary_marked_secondary_inactive_due_to_stale_heartbeat', {
316
+ deviceType: 'primary',
317
+ userUuid,
318
+ now: comparableNow,
319
+ timeoutMs: OTHER_DEVICE_HEARTBEAT_TIMEOUT_MS,
320
+ heartbeatDiffMs: comparableNow - lastBeat,
321
+ payload: {
322
+ connected: false,
323
+ source: 'stale_other_device',
324
+ otherDeviceType: 'secondary',
325
+ otherDeviceStatus: getObservedStatusPayload(otherDeviceStatus, comparableNow)
326
+ }
327
+ }, firebaseClient);
328
+ }).catch(otherErr => {
294
329
  const isMarkingSecondaryDeviceStale = !isSecondaryDevice;
295
330
  if (!isMarkingSecondaryDeviceStale) {
296
331
  return;
@@ -298,12 +333,12 @@ const setupDeviceStatusListeners = _ref2 => {
298
333
  (0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_device_status_write_failed', {
299
334
  deviceType: 'secondary',
300
335
  userUuid,
301
- now,
336
+ now: comparableNow,
302
337
  payload: {
303
338
  connected: false,
304
339
  source: 'stale_other_device',
305
340
  otherDeviceType: 'secondary',
306
- otherDeviceStatus: getObservedStatusPayload(otherDeviceStatus, now)
341
+ otherDeviceStatus: getObservedStatusPayload(otherDeviceStatus, comparableNow)
307
342
  },
308
343
  error: getErrorPayload(otherErr)
309
344
  }, firebaseClient);
@@ -315,6 +350,7 @@ const setupDeviceStatusListeners = _ref2 => {
315
350
  return () => {
316
351
  unsubscribePrimary();
317
352
  unsubscribeSecondary();
353
+ unsubscribeServerTimeOffset();
318
354
  if (heartbeatIntervalId) {
319
355
  clearInterval(heartbeatIntervalId);
320
356
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newtonschool/react_proctoring_library",
3
- "version": "0.0.133-beta.0",
3
+ "version": "0.0.133-beta.2",
4
4
  "description": "Used to proctor online tests",
5
5
  "author": "ayushkagrawal,shreyachandra,weastel",
6
6
  "main": "dist/index.js",