fix: huddles not launching reliably
Closes #160 Race condition preventing proper initialization.
This commit is contained in:
Vendored
-1
@@ -19,7 +19,6 @@ declare global {
|
|||||||
closeHuddle: () => void;
|
closeHuddle: () => void;
|
||||||
};
|
};
|
||||||
electronHuddle: {
|
electronHuddle: {
|
||||||
onConnect: (callback: (data: { token: string; serverUrl: string }) => void) => () => void;
|
|
||||||
getScreenSources: () => Promise<ScreenSource[]>;
|
getScreenSources: () => Promise<ScreenSource[]>;
|
||||||
};
|
};
|
||||||
electronAutoplay: {
|
electronAutoplay: {
|
||||||
|
|||||||
@@ -24,14 +24,15 @@ import { RoomEvent, Track } from 'livekit-client';
|
|||||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||||
import { ScreenSourcePicker } from '@/components/screen-source-picker';
|
import { ScreenSourcePicker } from '@/components/screen-source-picker';
|
||||||
|
|
||||||
export function HuddleApp() {
|
function readConnectionFromHash(): { token: string; serverUrl: string } | null {
|
||||||
const [connection, setConnection] = useState<{ token: string; serverUrl: string } | null>(null);
|
const params = new URLSearchParams(window.location.hash.slice(1));
|
||||||
|
const token = params.get('token');
|
||||||
|
const serverUrl = params.get('serverUrl');
|
||||||
|
return token && serverUrl ? { token, serverUrl } : null;
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
export function HuddleApp() {
|
||||||
return window.electronHuddle.onConnect((data) => {
|
const [connection] = useState(readConnectionFromHash);
|
||||||
setConnection(data);
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleDisconnected = () => {
|
const handleDisconnected = () => {
|
||||||
window.electronWindow.closeHuddle();
|
window.electronWindow.closeHuddle();
|
||||||
@@ -40,7 +41,7 @@ export function HuddleApp() {
|
|||||||
if (!connection) {
|
if (!connection) {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen items-center justify-center bg-background text-foreground">
|
<div className="flex h-screen items-center justify-center bg-background text-foreground">
|
||||||
<p className="text-muted-foreground text-sm">Connecting to huddle...</p>
|
<p className="text-muted-foreground text-sm">Missing huddle connection data.</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-20
@@ -162,10 +162,7 @@ const createAutoplayWindow = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const createHuddleWindow = () => {
|
const createHuddleWindow = () => {
|
||||||
if (huddleWindow) {
|
if (huddleWindow) return;
|
||||||
huddleWindow.focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
huddleWindow = new BrowserWindow({
|
huddleWindow = new BrowserWindow({
|
||||||
width: 1024,
|
width: 1024,
|
||||||
@@ -180,19 +177,28 @@ const createHuddleWindow = () => {
|
|||||||
});
|
});
|
||||||
hardenWindow(huddleWindow);
|
hardenWindow(huddleWindow);
|
||||||
|
|
||||||
if (HUDDLE_WINDOW_VITE_DEV_SERVER_URL) {
|
|
||||||
huddleWindow.loadURL(HUDDLE_WINDOW_VITE_DEV_SERVER_URL);
|
|
||||||
} else {
|
|
||||||
huddleWindow.loadFile(
|
|
||||||
path.join(__dirname, `../renderer/${HUDDLE_WINDOW_VITE_NAME}/index.html`),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
huddleWindow.on('closed', () => {
|
huddleWindow.on('closed', () => {
|
||||||
huddleWindow = null;
|
huddleWindow = null;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Connection data is passed via URL hash so it's available synchronously on
|
||||||
|
// renderer mount — avoids the IPC race where `huddle:connect` could be sent
|
||||||
|
// before React attached its listener.
|
||||||
|
const loadHuddleWindow = (data: { token: string; serverUrl: string }) => {
|
||||||
|
if (!huddleWindow) return;
|
||||||
|
const params = new URLSearchParams({ token: data.token, serverUrl: data.serverUrl });
|
||||||
|
const hash = params.toString();
|
||||||
|
if (HUDDLE_WINDOW_VITE_DEV_SERVER_URL) {
|
||||||
|
huddleWindow.loadURL(`${HUDDLE_WINDOW_VITE_DEV_SERVER_URL}#${hash}`);
|
||||||
|
} else {
|
||||||
|
huddleWindow.loadFile(
|
||||||
|
path.join(__dirname, `../renderer/${HUDDLE_WINDOW_VITE_NAME}/index.html`),
|
||||||
|
{ hash },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function positionAutoplayWindow() {
|
function positionAutoplayWindow() {
|
||||||
if (!autoplayWindow) return;
|
if (!autoplayWindow) return;
|
||||||
const { width } = screen.getPrimaryDisplay().workAreaSize;
|
const { width } = screen.getPrimaryDisplay().workAreaSize;
|
||||||
@@ -261,14 +267,8 @@ ipcMain.on('window:fullscreen', (event) => {
|
|||||||
// Secondary window IPC handlers
|
// Secondary window IPC handlers
|
||||||
ipcMain.on('window:open-huddle', (_event, data: { token: string; serverUrl: string }) => {
|
ipcMain.on('window:open-huddle', (_event, data: { token: string; serverUrl: string }) => {
|
||||||
createHuddleWindow();
|
createHuddleWindow();
|
||||||
// Send connection data once the huddle window is ready
|
loadHuddleWindow(data);
|
||||||
huddleWindow?.webContents.once('did-finish-load', () => {
|
huddleWindow?.focus();
|
||||||
huddleWindow?.webContents.send('huddle:connect', data);
|
|
||||||
});
|
|
||||||
// If already loaded, send immediately
|
|
||||||
if (!huddleWindow?.webContents.isLoading()) {
|
|
||||||
huddleWindow?.webContents.send('huddle:connect', data);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
ipcMain.on('window:close-huddle', () => {
|
ipcMain.on('window:close-huddle', () => {
|
||||||
huddleWindow?.close();
|
huddleWindow?.close();
|
||||||
|
|||||||
@@ -12,11 +12,6 @@ contextBridge.exposeInMainWorld('electronWindow', {
|
|||||||
});
|
});
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('electronHuddle', {
|
contextBridge.exposeInMainWorld('electronHuddle', {
|
||||||
onConnect: (callback: (data: { token: string; serverUrl: string }) => void) => {
|
|
||||||
const handler = (_event: Electron.IpcRendererEvent, data: { token: string; serverUrl: string }) => callback(data);
|
|
||||||
ipcRenderer.on('huddle:connect', handler);
|
|
||||||
return () => { ipcRenderer.removeListener('huddle:connect', handler); };
|
|
||||||
},
|
|
||||||
getScreenSources: () => ipcRenderer.invoke('screen:get-sources'),
|
getScreenSources: () => ipcRenderer.invoke('screen:get-sources'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user