1
0
Fork 0
mirror of https://gitlab.com/futo-org/fcast.git synced 2025-06-24 21:25:23 +00:00

Receivers: Store connection state in main process

This commit is contained in:
Michael Hollister 2025-04-29 13:03:10 -05:00
parent 75f2f3dded
commit 5782fcc3ca
8 changed files with 32 additions and 16 deletions

View file

@ -1,27 +1,27 @@
import { Opcode } from 'common/Packets'; import { Opcode } from 'common/Packets';
const connectionPingTimeout = 2500; const connectionPingTimeout = 2500;
const connections = [];
const heartbeatRetries = {}; const heartbeatRetries = {};
let connections = [];
let uiUpdateCallbacks = { let uiUpdateCallbacks = {
onConnect: null, onConnect: null,
onDisconnect: null, onDisconnect: null,
} }
// Window might be re-created while devices are still connected
export function setUiUpdateCallbacks(callbacks: any) { export function setUiUpdateCallbacks(callbacks: any) {
uiUpdateCallbacks = callbacks; uiUpdateCallbacks = callbacks;
window.targetAPI.getSessions().then((sessions: string[]) => {
connections = sessions;
if (connections.length > 0) {
uiUpdateCallbacks.onConnect(connections, true);
}
});
} }
// Window might be re-created while devices are still connected
function onPingPong(value: any) { function onPingPong(value: any) {
if (value) { heartbeatRetries[value.sessionId] = 0;
heartbeatRetries[value.sessionId] = 0;
if (!connections.includes(value.sessionId)) {
connections.push(value.sessionId);
uiUpdateCallbacks.onConnect(connections, value.sessionId);
}
}
} }
window.targetAPI.onPing((_event, value: any) => onPingPong(value)); window.targetAPI.onPing((_event, value: any) => onPingPong(value));
window.targetAPI.onPong((_event, value: any) => onPingPong(value)); window.targetAPI.onPong((_event, value: any) => onPingPong(value));
@ -29,7 +29,7 @@ window.targetAPI.onPong((_event, value: any) => onPingPong(value));
window.targetAPI.onConnect((_event, value: any) => { window.targetAPI.onConnect((_event, value: any) => {
console.log(`Device connected: ${JSON.stringify(value)}`); console.log(`Device connected: ${JSON.stringify(value)}`);
connections.push(value.sessionId); connections.push(value.sessionId);
uiUpdateCallbacks.onConnect(connections, value); uiUpdateCallbacks.onConnect(connections);
}); });
window.targetAPI.onDisconnect((_event, value: any) => { window.targetAPI.onDisconnect((_event, value: any) => {
console.log(`Device disconnected: ${JSON.stringify(value)}`); console.log(`Device disconnected: ${JSON.stringify(value)}`);

View file

@ -50,6 +50,10 @@ export class TcpListenerService {
this.sessionMap[sessionId]?.socket.destroy(); this.sessionMap[sessionId]?.socket.destroy();
} }
public getSessions(): string[] {
return Object.keys(this.sessionMap);
}
private async handleServerError(err: NodeJS.ErrnoException) { private async handleServerError(err: NodeJS.ErrnoException) {
errorHandler(err); errorHandler(err);
} }

View file

@ -49,6 +49,10 @@ export class WebSocketListenerService {
this.sessionMap[sessionId]?.close(); this.sessionMap[sessionId]?.close();
} }
public getSessions(): string[] {
return Object.keys(this.sessionMap);
}
private async handleServerError(err: NodeJS.ErrnoException) { private async handleServerError(err: NodeJS.ErrnoException) {
errorHandler(err); errorHandler(err);
} }

View file

@ -25,6 +25,7 @@ if (TARGET === 'electron') {
electronAPI.contextBridge.exposeInMainWorld('targetAPI', { electronAPI.contextBridge.exposeInMainWorld('targetAPI', {
onDeviceInfo: (callback: any) => electronAPI.ipcRenderer.on('device-info', callback), onDeviceInfo: (callback: any) => electronAPI.ipcRenderer.on('device-info', callback),
getDeviceInfo: () => preloadData.deviceInfo, getDeviceInfo: () => preloadData.deviceInfo,
getSessions: () => electronAPI.ipcRenderer.invoke('get-sessions'),
sendSessionMessage: (opcode: Opcode, message: any) => electronAPI.ipcRenderer.send('send-session-message', { opcode: opcode, message: message }), sendSessionMessage: (opcode: Opcode, message: any) => electronAPI.ipcRenderer.send('send-session-message', { opcode: opcode, message: message }),
disconnectDevice: (session: string) => electronAPI.ipcRenderer.send('disconnect-device', session), disconnectDevice: (session: string) => electronAPI.ipcRenderer.send('disconnect-device', session),
onConnect: (callback: any) => electronAPI.ipcRenderer.on('connect', callback), onConnect: (callback: any) => electronAPI.ipcRenderer.on('connect', callback),

View file

@ -15,12 +15,12 @@ let qrWidth = null;
window.addEventListener('resize', (event) => calculateQRCodeWidth()); window.addEventListener('resize', (event) => calculateQRCodeWidth());
connectionMonitor.setUiUpdateCallbacks({ connectionMonitor.setUiUpdateCallbacks({
onConnect: (connections: string[], connectionInfo: any) => { onConnect: (connections: string[], initialUpdate: boolean = false) => {
connectionStatusText.textContent = connections.length > 1 ? 'Multiple devices connected:\r\n Ready to cast' : 'Connected: Ready to cast'; connectionStatusText.textContent = connections.length > 1 ? 'Multiple devices connected:\r\n Ready to cast' : 'Connected: Ready to cast';
connectionStatusSpinner.style.display = 'none'; connectionStatusSpinner.style.display = 'none';
connectionStatusCheck.style.display = 'inline-block'; connectionStatusCheck.style.display = 'inline-block';
}, },
onDisconnect: (connections: string[], connectionInfo: any) => { onDisconnect: (connections: string[]) => {
if (connections.length === 0) { if (connections.length === 0) {
connectionStatusText.textContent = 'Waiting for a connection'; connectionStatusText.textContent = 'Waiting for a connection';
connectionStatusSpinner.style.display = 'inline-block'; connectionStatusSpinner.style.display = 'inline-block';

View file

@ -28,6 +28,7 @@ if (TARGET === 'electron') {
onPause: (callback: any) => electronAPI.ipcRenderer.on("pause", callback), onPause: (callback: any) => electronAPI.ipcRenderer.on("pause", callback),
onResume: (callback: any) => electronAPI.ipcRenderer.on("resume", callback), onResume: (callback: any) => electronAPI.ipcRenderer.on("resume", callback),
onSeek: (callback: any) => electronAPI.ipcRenderer.on("seek", callback), onSeek: (callback: any) => electronAPI.ipcRenderer.on("seek", callback),
getSessions: () => electronAPI.ipcRenderer.invoke('get-sessions'),
sendSessionMessage: (opcode: Opcode, message: any) => electronAPI.ipcRenderer.send('send-session-message', { opcode: opcode, message: message }), sendSessionMessage: (opcode: Opcode, message: any) => electronAPI.ipcRenderer.send('send-session-message', { opcode: opcode, message: message }),
disconnectDevice: (session: string) => electronAPI.ipcRenderer.send('disconnect-device', session), disconnectDevice: (session: string) => electronAPI.ipcRenderer.send('disconnect-device', session),
onConnect: (callback: any) => electronAPI.ipcRenderer.on('connect', callback), onConnect: (callback: any) => electronAPI.ipcRenderer.on('connect', callback),

View file

@ -333,10 +333,12 @@ function onPlay(_event, value: PlayMessage) {
}; };
connectionMonitor.setUiUpdateCallbacks({ connectionMonitor.setUiUpdateCallbacks({
onConnect: (connections: string[], connectionInfo: any) => { onConnect: (connections: string[], initialUpdate: boolean = false) => {
toast('Device connected', ToastIcon.INFO); if (!initialUpdate) {
toast('Device connected', ToastIcon.INFO);
}
}, },
onDisconnect: (connections: string[], connectionInfo: any) => { onDisconnect: (connections: string[]) => {
toast('Device disconnected. If you experience playback issues, please reconnect.', ToastIcon.INFO); toast('Device disconnected. If you experience playback issues, please reconnect.', ToastIcon.INFO);
}, },
}); });

View file

@ -281,6 +281,10 @@ export class Main {
window.setFullScreen(false); window.setFullScreen(false);
}); });
ipcMain.handle('get-sessions', () => {
return [].concat(Main.tcpListenerService.getSessions(), Main.webSocketListenerService.getSessions());
});
if (Main.shouldOpenMainWindow) { if (Main.shouldOpenMainWindow) {
Main.openMainWindow(); Main.openMainWindow();
} }