fix(webapp): keep device presence alive via heartbeats
This commit is contained in:
@@ -72,6 +72,7 @@ const DEFAULT_CAMERA_CONSTRAINTS = {
|
|||||||
height: { ideal: 360, max: 540 },
|
height: { ideal: 360, max: 540 },
|
||||||
frameRate: { ideal: 15, max: 24 }
|
frameRate: { ideal: 15, max: 24 }
|
||||||
};
|
};
|
||||||
|
const SOCKET_HEARTBEAT_INTERVAL_MS = 10_000;
|
||||||
|
|
||||||
const rtcConfig = {
|
const rtcConfig = {
|
||||||
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
||||||
@@ -81,6 +82,7 @@ let initialized = false;
|
|||||||
let initPromise = null;
|
let initPromise = null;
|
||||||
let socket = null;
|
let socket = null;
|
||||||
let pollInterval = null;
|
let pollInterval = null;
|
||||||
|
let socketHeartbeatInterval = null;
|
||||||
let localCameraStream = null;
|
let localCameraStream = null;
|
||||||
let activeMediaRecorder = null;
|
let activeMediaRecorder = null;
|
||||||
let activeRecordingChunks = [];
|
let activeRecordingChunks = [];
|
||||||
@@ -1414,10 +1416,34 @@ const handleCameraStreamRequest = async ({ streamId, requesterDeviceId }) => {
|
|||||||
addActivity('Stream', 'Accepted stream request and started WebRTC offer');
|
addActivity('Stream', 'Accepted stream request and started WebRTC offer');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const stopSocketHeartbeat = () => {
|
||||||
|
if (socketHeartbeatInterval) {
|
||||||
|
clearInterval(socketHeartbeatInterval);
|
||||||
|
socketHeartbeatInterval = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const emitSocketHeartbeat = () => {
|
||||||
|
if (!socket?.connected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('heartbeat');
|
||||||
|
};
|
||||||
|
|
||||||
|
const startSocketHeartbeat = () => {
|
||||||
|
stopSocketHeartbeat();
|
||||||
|
emitSocketHeartbeat();
|
||||||
|
socketHeartbeatInterval = setInterval(() => {
|
||||||
|
emitSocketHeartbeat();
|
||||||
|
}, SOCKET_HEARTBEAT_INTERVAL_MS);
|
||||||
|
};
|
||||||
|
|
||||||
const connectSocket = () => {
|
const connectSocket = () => {
|
||||||
const { deviceToken } = getAppState();
|
const { deviceToken } = getAppState();
|
||||||
if (!deviceToken) return;
|
if (!deviceToken) return;
|
||||||
|
|
||||||
|
stopSocketHeartbeat();
|
||||||
if (socket) socket.disconnect();
|
if (socket) socket.disconnect();
|
||||||
socket = io(getBackendUrl(), {
|
socket = io(getBackendUrl(), {
|
||||||
auth: { token: deviceToken },
|
auth: { token: deviceToken },
|
||||||
@@ -1425,6 +1451,7 @@ const connectSocket = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on('connect', () => {
|
socket.on('connect', () => {
|
||||||
|
startSocketHeartbeat();
|
||||||
setAppState({ socketConnected: true });
|
setAppState({ socketConnected: true });
|
||||||
addActivity('System', 'Connected to realtime server');
|
addActivity('System', 'Connected to realtime server');
|
||||||
if (getAppState().device?.role === 'camera') {
|
if (getAppState().device?.role === 'camera') {
|
||||||
@@ -1434,6 +1461,7 @@ const connectSocket = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on('disconnect', () => {
|
socket.on('disconnect', () => {
|
||||||
|
stopSocketHeartbeat();
|
||||||
setAppState({ socketConnected: false });
|
setAppState({ socketConnected: false });
|
||||||
void stopLocalRecording();
|
void stopLocalRecording();
|
||||||
teardownPeerConnection();
|
teardownPeerConnection();
|
||||||
@@ -1443,6 +1471,7 @@ const connectSocket = () => {
|
|||||||
|
|
||||||
socket.on('connect_error', (error) => {
|
socket.on('connect_error', (error) => {
|
||||||
const message = error?.message || 'Realtime connection failed';
|
const message = error?.message || 'Realtime connection failed';
|
||||||
|
stopSocketHeartbeat();
|
||||||
setAppState({ socketConnected: false });
|
setAppState({ socketConnected: false });
|
||||||
addActivity('System', `Realtime connection failed: ${message}`);
|
addActivity('System', `Realtime connection failed: ${message}`);
|
||||||
|
|
||||||
@@ -1675,6 +1704,7 @@ const startPolling = () => {
|
|||||||
|
|
||||||
const cleanupConnectionState = async () => {
|
const cleanupConnectionState = async () => {
|
||||||
stopPolling();
|
stopPolling();
|
||||||
|
stopSocketHeartbeat();
|
||||||
await stopLocalRecording();
|
await stopLocalRecording();
|
||||||
teardownPeerConnection();
|
teardownPeerConnection();
|
||||||
stopCameraPreview();
|
stopCameraPreview();
|
||||||
|
|||||||
Reference in New Issue
Block a user