@newtonschool/react_proctoring_library 0.0.132 → 0.0.133-beta.0
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.
|
@@ -10,6 +10,7 @@ var _proctoringStatusUtils = require("../../utils/proctoringStatusUtils");
|
|
|
10
10
|
var _permission = require("../../utils/permission");
|
|
11
11
|
var _breachUtils = require("../../utils/breachUtils");
|
|
12
12
|
var _usePageActivity = _interopRequireDefault(require("../../hooks/usePageActivity"));
|
|
13
|
+
var _proctoringDebugUtils = require("../../utils/proctoringDebugUtils");
|
|
13
14
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
15
|
const SecondaryDevice = _ref => {
|
|
15
16
|
let {
|
|
@@ -27,10 +28,36 @@ const SecondaryDevice = _ref => {
|
|
|
27
28
|
const [secondaryDeviceOnline, setSecondaryDeviceOnline] = (0, _react.useState)(true);
|
|
28
29
|
const [secondaryDeviceAllPermissionGranted, setSecondaryDeviceAllPermissionGranted] = (0, _react.useState)(true);
|
|
29
30
|
const {
|
|
30
|
-
isActive: isCurrentDeviceActive
|
|
31
|
+
isActive: isCurrentDeviceActive,
|
|
32
|
+
isVisible,
|
|
33
|
+
isFocused,
|
|
34
|
+
isLifecycleActive
|
|
31
35
|
} = (0, _usePageActivity.default)();
|
|
32
36
|
const allPermissionGranted = (0, _permission.hasAllPermissions)((0, _breachUtils.getRequiredPermissionsFromProctorParams)(proctorParams), permissions);
|
|
33
37
|
const effectiveAllPermissionGranted = allPermissionGranted && isCurrentDeviceActive;
|
|
38
|
+
(0, _react.useEffect)(() => {
|
|
39
|
+
if (!isSecondaryDevice) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
(0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_session_started', {
|
|
43
|
+
deviceType: 'secondary',
|
|
44
|
+
userUuid: (firebaseClient === null || firebaseClient === void 0 ? void 0 : firebaseClient.userUuid) || null,
|
|
45
|
+
requiredPermissions: (0, _breachUtils.getRequiredPermissionsFromProctorParams)(proctorParams),
|
|
46
|
+
userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : 'unknown'
|
|
47
|
+
}, firebaseClient);
|
|
48
|
+
}, [firebaseClient === null || firebaseClient === void 0 ? void 0 : firebaseClient.userUuid, isSecondaryDevice, proctorParams]);
|
|
49
|
+
(0, _react.useEffect)(() => {
|
|
50
|
+
if (!isSecondaryDevice) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
(0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_page_activity_state_changed', {
|
|
54
|
+
deviceType: 'secondary',
|
|
55
|
+
isVisible,
|
|
56
|
+
isFocused,
|
|
57
|
+
isLifecycleActive,
|
|
58
|
+
isActive: isCurrentDeviceActive
|
|
59
|
+
}, firebaseClient);
|
|
60
|
+
}, [firebaseClient, isCurrentDeviceActive, isFocused, isLifecycleActive, isSecondaryDevice, isVisible]);
|
|
34
61
|
(0, _react.useEffect)(() => {
|
|
35
62
|
const cleanup = (0, _proctoringStatusUtils.setupDeviceStatusListeners)({
|
|
36
63
|
firebaseClient,
|
|
@@ -20,6 +20,7 @@ var _webcamMicrophoneUtils = require("../../utils/webcamMicrophoneUtils");
|
|
|
20
20
|
var _dom = require("../../constants/dom");
|
|
21
21
|
var _useBreachData = require("../../hooks/useBreachData");
|
|
22
22
|
var _proctoringStatusUtils = require("../../utils/proctoringStatusUtils");
|
|
23
|
+
var _proctoringDebugUtils = require("../../utils/proctoringDebugUtils");
|
|
23
24
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
24
25
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
25
26
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
@@ -46,6 +47,7 @@ const WebWebCam = _ref => {
|
|
|
46
47
|
references,
|
|
47
48
|
permissions
|
|
48
49
|
} = (0, _react.useContext)(proctoredContext);
|
|
50
|
+
const deviceType = isSecondaryDevice ? 'secondary' : 'primary';
|
|
49
51
|
const recurringFetchIntervalRef = (0, _react.useRef)(null);
|
|
50
52
|
const {
|
|
51
53
|
recurring = false,
|
|
@@ -108,6 +110,13 @@ const WebWebCam = _ref => {
|
|
|
108
110
|
screenshotFormat: "image/jpeg",
|
|
109
111
|
ref: webcamReference,
|
|
110
112
|
onUserMedia: () => {
|
|
113
|
+
if (isSecondaryDevice) {
|
|
114
|
+
(0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_webcam_user_media_succeeded', {
|
|
115
|
+
deviceType,
|
|
116
|
+
retryCount,
|
|
117
|
+
userUuid: (firebaseClient === null || firebaseClient === void 0 ? void 0 : firebaseClient.userUuid) || null
|
|
118
|
+
}, firebaseClient);
|
|
119
|
+
}
|
|
111
120
|
setVideoPermission(true);
|
|
112
121
|
if (firebaseClient) {
|
|
113
122
|
if (isSecondaryDevice) {
|
|
@@ -118,6 +127,17 @@ const WebWebCam = _ref => {
|
|
|
118
127
|
}
|
|
119
128
|
},
|
|
120
129
|
onUserMediaError: err => {
|
|
130
|
+
if (isSecondaryDevice) {
|
|
131
|
+
(0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_webcam_user_media_failed', {
|
|
132
|
+
deviceType,
|
|
133
|
+
retryCount,
|
|
134
|
+
userUuid: (firebaseClient === null || firebaseClient === void 0 ? void 0 : firebaseClient.userUuid) || null,
|
|
135
|
+
error: {
|
|
136
|
+
name: (err === null || err === void 0 ? void 0 : err.name) || null,
|
|
137
|
+
message: (err === null || err === void 0 ? void 0 : err.message) || String(err)
|
|
138
|
+
}
|
|
139
|
+
}, firebaseClient);
|
|
140
|
+
}
|
|
121
141
|
logger("Retry Count = ".concat(retryCount, " | Webcam error, onUserMediaError | ").concat(err.toString()));
|
|
122
142
|
if (retryCount === 0) {
|
|
123
143
|
setVideoPermission(false);
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
require("core-js/modules/es.symbol.description.js");
|
|
4
|
+
require("core-js/modules/esnext.iterator.constructor.js");
|
|
5
|
+
require("core-js/modules/esnext.iterator.filter.js");
|
|
6
|
+
require("core-js/modules/esnext.iterator.for-each.js");
|
|
7
|
+
Object.defineProperty(exports, "__esModule", {
|
|
8
|
+
value: true
|
|
9
|
+
});
|
|
10
|
+
exports.emitProctoringDebugLog = void 0;
|
|
11
|
+
require("core-js/modules/es.json.stringify.js");
|
|
12
|
+
require("core-js/modules/es.promise.js");
|
|
13
|
+
var _defaults = require("../constants/defaults");
|
|
14
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
15
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
16
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
17
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
18
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
19
|
+
const DEBUG_LOG_PREFIX = '::[secondary-device-debug]';
|
|
20
|
+
const WEB_REPORT_LOG_ENDPOINT = '/api/v1/user/report/web/';
|
|
21
|
+
const safeJsonStringify = value => {
|
|
22
|
+
try {
|
|
23
|
+
return JSON.stringify(value);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
return JSON.stringify({
|
|
26
|
+
ts: Date.now(),
|
|
27
|
+
serializationError: (error === null || error === void 0 ? void 0 : error.message) || String(error)
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const postDebugMessage = message => {
|
|
32
|
+
if (typeof window === 'undefined') {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
if (typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function') {
|
|
37
|
+
const body = new Blob([safeJsonStringify({
|
|
38
|
+
message
|
|
39
|
+
})], {
|
|
40
|
+
type: 'application/json'
|
|
41
|
+
});
|
|
42
|
+
navigator.sendBeacon(WEB_REPORT_LOG_ENDPOINT, body);
|
|
43
|
+
} else if (typeof fetch === 'function') {
|
|
44
|
+
fetch(WEB_REPORT_LOG_ENDPOINT, {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
headers: {
|
|
47
|
+
'Content-Type': 'application/json'
|
|
48
|
+
},
|
|
49
|
+
body: safeJsonStringify({
|
|
50
|
+
message
|
|
51
|
+
}),
|
|
52
|
+
keepalive: true
|
|
53
|
+
}).catch(() => {});
|
|
54
|
+
}
|
|
55
|
+
} catch (_) {}
|
|
56
|
+
};
|
|
57
|
+
const isDebugLogEnabled = async firebaseClient => {
|
|
58
|
+
if (!(firebaseClient !== null && firebaseClient !== void 0 && firebaseClient.userUuid) || !(firebaseClient !== null && firebaseClient !== void 0 && firebaseClient.myFirebaseDB) || !(firebaseClient !== null && firebaseClient !== void 0 && firebaseClient.getRef) || !(firebaseClient !== null && firebaseClient !== void 0 && firebaseClient.getValue)) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const {
|
|
62
|
+
getRef: ref,
|
|
63
|
+
getValue
|
|
64
|
+
} = firebaseClient;
|
|
65
|
+
const debugEnabledRef = ref(firebaseClient.myFirebaseDB, "".concat(_defaults.PROCTORING_STATUS_PATH, "/").concat(firebaseClient.userUuid, "/isDebugEnabled"));
|
|
66
|
+
try {
|
|
67
|
+
return await new Promise(resolve => {
|
|
68
|
+
getValue(debugEnabledRef, snapshot => {
|
|
69
|
+
var _snapshot$val, _snapshot$val2;
|
|
70
|
+
const value = (_snapshot$val = snapshot === null || snapshot === void 0 ? void 0 : (_snapshot$val2 = snapshot.val) === null || _snapshot$val2 === void 0 ? void 0 : _snapshot$val2.call(snapshot)) !== null && _snapshot$val !== void 0 ? _snapshot$val : snapshot;
|
|
71
|
+
resolve(Boolean(value));
|
|
72
|
+
}, () => resolve(false), {
|
|
73
|
+
onlyOnce: true
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
} catch (_) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const emitProctoringDebugLog = exports.emitProctoringDebugLog = function emitProctoringDebugLog(event) {
|
|
81
|
+
let payload = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
82
|
+
let firebaseClient = arguments.length > 2 ? arguments[2] : undefined;
|
|
83
|
+
const message = "".concat(DEBUG_LOG_PREFIX, " ").concat(event, " ").concat(safeJsonStringify(_objectSpread({
|
|
84
|
+
ts: Date.now()
|
|
85
|
+
}, payload)));
|
|
86
|
+
isDebugLogEnabled(firebaseClient).then(enabled => {
|
|
87
|
+
if (!enabled) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
postDebugMessage(message);
|
|
91
|
+
});
|
|
92
|
+
};
|
|
@@ -5,8 +5,28 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.updateCurrentDeviceStatus = exports.setupDeviceStatusListeners = exports.setSecondaryDeviceConnected = exports.setPrimaryDeviceConnected = void 0;
|
|
7
7
|
var _defaults = require("../constants/defaults");
|
|
8
|
+
var _proctoringDebugUtils = require("./proctoringDebugUtils");
|
|
8
9
|
const HEARTBEAT_INTERVAL_MS = 5000;
|
|
9
10
|
const OTHER_DEVICE_HEARTBEAT_TIMEOUT_MS = 15000;
|
|
11
|
+
const getErrorPayload = error => ({
|
|
12
|
+
name: (error === null || error === void 0 ? void 0 : error.name) || null,
|
|
13
|
+
message: (error === null || error === void 0 ? void 0 : error.message) || String(error)
|
|
14
|
+
});
|
|
15
|
+
const getObservedStatusPayload = function getObservedStatusPayload(status) {
|
|
16
|
+
let now = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Date.now();
|
|
17
|
+
return {
|
|
18
|
+
connected: Boolean(status === null || status === void 0 ? void 0 : status.connected),
|
|
19
|
+
allPermissionGranted: typeof (status === null || status === void 0 ? void 0 : status.allPermissionGranted) === 'boolean' ? status.allPermissionGranted : null,
|
|
20
|
+
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,
|
|
22
|
+
deviceId: (status === null || status === void 0 ? void 0 : status.deviceId) || null
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
const hasRelevantObservedChange = (previousStatus, nextStatus) => {
|
|
26
|
+
const previous = getObservedStatusPayload(previousStatus);
|
|
27
|
+
const next = getObservedStatusPayload(nextStatus);
|
|
28
|
+
return previous.connected !== next.connected || previous.allPermissionGranted !== next.allPermissionGranted || previous.deviceId !== next.deviceId;
|
|
29
|
+
};
|
|
10
30
|
|
|
11
31
|
/**
|
|
12
32
|
* Marks the primary device as connected in Firebase. Call when desktop webcam
|
|
@@ -27,7 +47,7 @@ const setPrimaryDeviceConnected = firebaseClient => {
|
|
|
27
47
|
const payload = {
|
|
28
48
|
connected: true
|
|
29
49
|
};
|
|
30
|
-
return update(primaryDeviceRef, payload).catch(error => {
|
|
50
|
+
return update(primaryDeviceRef, payload).then(() => {}).catch(error => {
|
|
31
51
|
console.error('::[proctoringStatusUtils] Failed to set primary device status online:', error);
|
|
32
52
|
});
|
|
33
53
|
};
|
|
@@ -52,7 +72,13 @@ const setSecondaryDeviceConnected = firebaseClient => {
|
|
|
52
72
|
const payload = {
|
|
53
73
|
connected: true
|
|
54
74
|
};
|
|
55
|
-
return update(secondaryDeviceRef, payload).catch(error => {
|
|
75
|
+
return update(secondaryDeviceRef, payload).then(() => {}).catch(error => {
|
|
76
|
+
(0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_device_status_write_failed', {
|
|
77
|
+
deviceType: 'secondary',
|
|
78
|
+
userUuid: firebaseClient.userUuid,
|
|
79
|
+
payload,
|
|
80
|
+
error: getErrorPayload(error)
|
|
81
|
+
}, firebaseClient);
|
|
56
82
|
console.error('::[proctoringStatusUtils] Failed to set secondary device status online:', error);
|
|
57
83
|
});
|
|
58
84
|
};
|
|
@@ -86,7 +112,16 @@ const updateCurrentDeviceStatus = _ref => {
|
|
|
86
112
|
const payload = {
|
|
87
113
|
allPermissionGranted
|
|
88
114
|
};
|
|
89
|
-
return update(deviceStatusRef, payload).catch(error => {
|
|
115
|
+
return update(deviceStatusRef, payload).then(() => {}).catch(error => {
|
|
116
|
+
if (!isSecondaryDevice) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
(0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_device_status_write_failed', {
|
|
120
|
+
deviceType: 'secondary',
|
|
121
|
+
userUuid: firebaseClient.userUuid,
|
|
122
|
+
payload,
|
|
123
|
+
error: getErrorPayload(error)
|
|
124
|
+
}, firebaseClient);
|
|
90
125
|
console.error('::[proctoringStatusUtils] Failed to update current device status:', error);
|
|
91
126
|
});
|
|
92
127
|
};
|
|
@@ -123,6 +158,7 @@ const setupDeviceStatusListeners = _ref2 => {
|
|
|
123
158
|
onDisconnect,
|
|
124
159
|
getValue: onValue
|
|
125
160
|
} = firebaseClient || {};
|
|
161
|
+
const deviceType = isSecondaryDevice ? 'secondary' : 'primary';
|
|
126
162
|
if (!userUuid || !firestoreAuthStatus || !ref || !set || !onDisconnect || !onValue) {
|
|
127
163
|
return () => {};
|
|
128
164
|
}
|
|
@@ -136,28 +172,52 @@ const setupDeviceStatusListeners = _ref2 => {
|
|
|
136
172
|
// When this client disconnects (tab close, network loss)
|
|
137
173
|
onDisconnect(currentDeviceStatusRef).update({
|
|
138
174
|
connected: false
|
|
139
|
-
}).catch(err => {
|
|
175
|
+
}).then(() => {}).catch(err => {
|
|
176
|
+
if (!isSecondaryDevice) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
(0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_device_status_write_failed', {
|
|
180
|
+
deviceType,
|
|
181
|
+
userUuid,
|
|
182
|
+
payload: {
|
|
183
|
+
connected: false,
|
|
184
|
+
source: 'onDisconnect'
|
|
185
|
+
},
|
|
186
|
+
error: getErrorPayload(err)
|
|
187
|
+
}, firebaseClient);
|
|
140
188
|
console.error('::[proctoringStatusUtils] Failed to mark current device disconnected:', err);
|
|
141
189
|
});
|
|
142
190
|
|
|
143
191
|
// Get initial values and update callbacks immediately
|
|
144
|
-
const applyPrimarySnapshot = snapshot
|
|
192
|
+
const applyPrimarySnapshot = function applyPrimarySnapshot(snapshot) {
|
|
145
193
|
var _snapshot$val, _snapshot$val2;
|
|
194
|
+
let source = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'subscription';
|
|
195
|
+
const previousValue = latestPrimaryDeviceStatus;
|
|
146
196
|
const val = (_snapshot$val = snapshot === null || snapshot === void 0 ? void 0 : (_snapshot$val2 = snapshot.val) === null || _snapshot$val2 === void 0 ? void 0 : _snapshot$val2.call(snapshot)) !== null && _snapshot$val !== void 0 ? _snapshot$val : snapshot;
|
|
147
197
|
latestPrimaryDeviceStatus = val;
|
|
148
198
|
onPrimaryDeviceStatusChange(Boolean(val === null || val === void 0 ? void 0 : val.connected));
|
|
149
199
|
};
|
|
150
|
-
const applySecondarySnapshot = snapshot
|
|
200
|
+
const applySecondarySnapshot = function applySecondarySnapshot(snapshot) {
|
|
151
201
|
var _snapshot$val3, _snapshot$val4;
|
|
202
|
+
let source = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'subscription';
|
|
203
|
+
const previousValue = latestSecondaryDeviceStatus;
|
|
152
204
|
const val = (_snapshot$val3 = snapshot === null || snapshot === void 0 ? void 0 : (_snapshot$val4 = snapshot.val) === null || _snapshot$val4 === void 0 ? void 0 : _snapshot$val4.call(snapshot)) !== null && _snapshot$val3 !== void 0 ? _snapshot$val3 : snapshot;
|
|
153
205
|
latestSecondaryDeviceStatus = val;
|
|
206
|
+
if (isSecondaryDevice && (source === 'initial_get' || hasRelevantObservedChange(previousValue, val))) {
|
|
207
|
+
(0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_device_status_observed', {
|
|
208
|
+
deviceType,
|
|
209
|
+
observedDeviceType: 'secondary',
|
|
210
|
+
source,
|
|
211
|
+
observedStatus: getObservedStatusPayload(val)
|
|
212
|
+
}, firebaseClient);
|
|
213
|
+
}
|
|
154
214
|
onSecondaryDeviceStatusChange(Boolean(val === null || val === void 0 ? void 0 : val.connected), val === null || val === void 0 ? void 0 : val.allPermissionGranted);
|
|
155
215
|
};
|
|
156
216
|
if (typeof (primaryDeviceStatusRef === null || primaryDeviceStatusRef === void 0 ? void 0 : primaryDeviceStatusRef.get) === 'function') {
|
|
157
|
-
primaryDeviceStatusRef.get().then(applyPrimarySnapshot).catch(() => {});
|
|
217
|
+
primaryDeviceStatusRef.get().then(snapshot => applyPrimarySnapshot(snapshot, 'initial_get')).catch(() => {});
|
|
158
218
|
}
|
|
159
219
|
if (typeof (secondaryDeviceStatusRef === null || secondaryDeviceStatusRef === void 0 ? void 0 : secondaryDeviceStatusRef.get) === 'function') {
|
|
160
|
-
secondaryDeviceStatusRef.get().then(applySecondarySnapshot).catch(() => {});
|
|
220
|
+
secondaryDeviceStatusRef.get().then(snapshot => applySecondarySnapshot(snapshot, 'initial_get')).catch(() => {});
|
|
161
221
|
}
|
|
162
222
|
|
|
163
223
|
// Subscribe to updates
|
|
@@ -177,14 +237,48 @@ const setupDeviceStatusListeners = _ref2 => {
|
|
|
177
237
|
update(currentDeviceStatusRef, {
|
|
178
238
|
connected: true,
|
|
179
239
|
lastHeartbeatAt: now
|
|
180
|
-
}).catch(error => {
|
|
240
|
+
}).then(() => {}).catch(error => {
|
|
241
|
+
if (!isSecondaryDevice) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
(0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_heartbeat_write_failed', {
|
|
245
|
+
deviceType,
|
|
246
|
+
userUuid,
|
|
247
|
+
isCurrentDeviceActive,
|
|
248
|
+
now,
|
|
249
|
+
isSecondaryDevice,
|
|
250
|
+
error: getErrorPayload(error)
|
|
251
|
+
}, firebaseClient);
|
|
181
252
|
console.error('::[proctoringStatusUtils] Failed to send heartbeat for current device:', error);
|
|
182
253
|
});
|
|
183
254
|
}
|
|
184
255
|
if (!isCurrentDeviceActive) {
|
|
185
256
|
update(currentDeviceStatusRef, {
|
|
186
257
|
connected: false
|
|
258
|
+
}).then(() => {
|
|
259
|
+
if (!isSecondaryDevice) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
(0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_current_device_marked_inactive', {
|
|
263
|
+
deviceType,
|
|
264
|
+
userUuid,
|
|
265
|
+
now,
|
|
266
|
+
isSecondaryDevice
|
|
267
|
+
}, firebaseClient);
|
|
187
268
|
}).catch(error => {
|
|
269
|
+
if (!isSecondaryDevice) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
(0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_device_status_write_failed', {
|
|
273
|
+
deviceType,
|
|
274
|
+
userUuid,
|
|
275
|
+
now,
|
|
276
|
+
payload: {
|
|
277
|
+
connected: false,
|
|
278
|
+
source: 'inactive_page_state'
|
|
279
|
+
},
|
|
280
|
+
error: getErrorPayload(error)
|
|
281
|
+
}, firebaseClient);
|
|
188
282
|
console.error('::[proctoringStatusUtils] Failed to mark current device inactive:', error);
|
|
189
283
|
});
|
|
190
284
|
}
|
|
@@ -196,7 +290,23 @@ const setupDeviceStatusListeners = _ref2 => {
|
|
|
196
290
|
if (isConnected && typeof lastBeat === 'number' && now - lastBeat > OTHER_DEVICE_HEARTBEAT_TIMEOUT_MS) {
|
|
197
291
|
update(otherDeviceStatusRef, {
|
|
198
292
|
connected: false
|
|
199
|
-
}).catch(otherErr => {
|
|
293
|
+
}).then(() => {}).catch(otherErr => {
|
|
294
|
+
const isMarkingSecondaryDeviceStale = !isSecondaryDevice;
|
|
295
|
+
if (!isMarkingSecondaryDeviceStale) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
(0, _proctoringDebugUtils.emitProctoringDebugLog)('secondary_device_status_write_failed', {
|
|
299
|
+
deviceType: 'secondary',
|
|
300
|
+
userUuid,
|
|
301
|
+
now,
|
|
302
|
+
payload: {
|
|
303
|
+
connected: false,
|
|
304
|
+
source: 'stale_other_device',
|
|
305
|
+
otherDeviceType: 'secondary',
|
|
306
|
+
otherDeviceStatus: getObservedStatusPayload(otherDeviceStatus, now)
|
|
307
|
+
},
|
|
308
|
+
error: getErrorPayload(otherErr)
|
|
309
|
+
}, firebaseClient);
|
|
200
310
|
console.error('::[proctoringStatusUtils] Failed to mark other device disconnected due to stale heartbeat:', otherErr);
|
|
201
311
|
});
|
|
202
312
|
}
|