Mnovich/windows deep links (#2125)
This commit is contained in:
+99
-27
@@ -39,40 +39,124 @@ if (started) app.quit();
|
|||||||
|
|
||||||
app.setAsDefaultProtocolClient('goose');
|
app.setAsDefaultProtocolClient('goose');
|
||||||
|
|
||||||
// Triggered when the user opens "goose://..." links
|
const gotTheLock = app.requestSingleInstanceLock();
|
||||||
let firstOpenWindow: BrowserWindow;
|
|
||||||
let pendingDeepLink: string | null = null; // Store deep link if sent before React is ready
|
|
||||||
app.on('open-url', async (_event, url) => {
|
|
||||||
pendingDeepLink = url;
|
|
||||||
|
|
||||||
// Parse the URL to determine the type
|
if (!gotTheLock) {
|
||||||
|
app.quit();
|
||||||
|
} else {
|
||||||
|
app.on('second-instance', (event, commandLine) => {
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
const protocolUrl = commandLine.find((arg) => arg.startsWith('goose://'));
|
||||||
|
if (protocolUrl) {
|
||||||
|
handleProtocolUrl(protocolUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingWindows = BrowserWindow.getAllWindows();
|
||||||
|
if (existingWindows.length > 0) {
|
||||||
|
const mainWindow = existingWindows[0];
|
||||||
|
if (mainWindow.isMinimized()) {
|
||||||
|
mainWindow.restore();
|
||||||
|
}
|
||||||
|
mainWindow.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
const protocolUrl = process.argv.find((arg) => arg.startsWith('goose://'));
|
||||||
|
if (protocolUrl) {
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
handleProtocolUrl(protocolUrl);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let firstOpenWindow: BrowserWindow;
|
||||||
|
let pendingDeepLink = null;
|
||||||
|
|
||||||
|
async function handleProtocolUrl(url: string) {
|
||||||
|
if (!url) return;
|
||||||
|
|
||||||
|
pendingDeepLink = url;
|
||||||
const parsedUrl = new URL(url);
|
const parsedUrl = new URL(url);
|
||||||
|
|
||||||
const recentDirs = loadRecentDirs();
|
const recentDirs = loadRecentDirs();
|
||||||
const openDir = recentDirs.length > 0 ? recentDirs[0] : null;
|
const openDir = recentDirs.length > 0 ? recentDirs[0] : null;
|
||||||
|
|
||||||
if (parsedUrl.hostname !== 'bot') {
|
if (parsedUrl.hostname !== 'bot') {
|
||||||
// For non URL types, reuse existing window if available
|
|
||||||
const existingWindows = BrowserWindow.getAllWindows();
|
const existingWindows = BrowserWindow.getAllWindows();
|
||||||
if (existingWindows.length > 0) {
|
if (existingWindows.length > 0) {
|
||||||
firstOpenWindow = existingWindows[0];
|
firstOpenWindow = existingWindows[0];
|
||||||
if (firstOpenWindow.isMinimized()) firstOpenWindow.restore();
|
if (firstOpenWindow.isMinimized()) {
|
||||||
|
firstOpenWindow.restore();
|
||||||
|
}
|
||||||
firstOpenWindow.focus();
|
firstOpenWindow.focus();
|
||||||
} else {
|
} else {
|
||||||
firstOpenWindow = await createChat(app, undefined, openDir);
|
firstOpenWindow = await createChat(app, undefined, openDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle extension install links and sessions
|
if (firstOpenWindow) {
|
||||||
|
const webContents = firstOpenWindow.webContents;
|
||||||
|
if (webContents.isLoadingMainFrame()) {
|
||||||
|
webContents.once('did-finish-load', () => {
|
||||||
|
processProtocolUrl(parsedUrl, firstOpenWindow);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
processProtocolUrl(parsedUrl, firstOpenWindow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function processProtocolUrl(parsedUrl: URL, window: BrowserWindow) {
|
||||||
|
const recentDirs = loadRecentDirs();
|
||||||
|
const openDir = recentDirs.length > 0 ? recentDirs[0] : null;
|
||||||
|
|
||||||
if (parsedUrl.hostname === 'extension') {
|
if (parsedUrl.hostname === 'extension') {
|
||||||
firstOpenWindow.webContents.send('add-extension', pendingDeepLink);
|
window.webContents.send('add-extension', pendingDeepLink);
|
||||||
} else if (parsedUrl.hostname === 'sessions') {
|
} else if (parsedUrl.hostname === 'sessions') {
|
||||||
firstOpenWindow.webContents.send('open-shared-session', pendingDeepLink);
|
window.webContents.send('open-shared-session', pendingDeepLink);
|
||||||
} else if (parsedUrl.hostname === 'bot') {
|
} else if (parsedUrl.hostname === 'bot') {
|
||||||
let botConfig = null;
|
let botConfig = null;
|
||||||
|
const configParam = parsedUrl.searchParams.get('config');
|
||||||
|
if (configParam) {
|
||||||
|
try {
|
||||||
|
botConfig = JSON.parse(Buffer.from(configParam, 'base64').toString('utf-8'));
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to parse bot config:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createChat(app, undefined, openDir, undefined, undefined, botConfig);
|
||||||
|
}
|
||||||
|
pendingDeepLink = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Extract bot config if it's a bot (miniagent) URL
|
app.on('open-url', async (event, url) => {
|
||||||
if (parsedUrl.hostname === 'bot') {
|
if (process.platform !== 'win32') {
|
||||||
|
pendingDeepLink = url;
|
||||||
|
const parsedUrl = new URL(url);
|
||||||
|
|
||||||
|
const recentDirs = loadRecentDirs();
|
||||||
|
const openDir = recentDirs.length > 0 ? recentDirs[0] : null;
|
||||||
|
|
||||||
|
if (parsedUrl.hostname !== 'bot') {
|
||||||
|
const existingWindows = BrowserWindow.getAllWindows();
|
||||||
|
if (existingWindows.length > 0) {
|
||||||
|
firstOpenWindow = existingWindows[0];
|
||||||
|
if (firstOpenWindow.isMinimized()) firstOpenWindow.restore();
|
||||||
|
firstOpenWindow.focus();
|
||||||
|
} else {
|
||||||
|
firstOpenWindow = await createChat(app, undefined, openDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedUrl.hostname === 'extension') {
|
||||||
|
firstOpenWindow.webContents.send('add-extension', pendingDeepLink);
|
||||||
|
} else if (parsedUrl.hostname === 'sessions') {
|
||||||
|
firstOpenWindow.webContents.send('open-shared-session', pendingDeepLink);
|
||||||
|
} else if (parsedUrl.hostname === 'bot') {
|
||||||
|
let botConfig = null;
|
||||||
const configParam = parsedUrl.searchParams.get('config');
|
const configParam = parsedUrl.searchParams.get('config');
|
||||||
if (configParam) {
|
if (configParam) {
|
||||||
try {
|
try {
|
||||||
@@ -81,9 +165,8 @@ app.on('open-url', async (_event, url) => {
|
|||||||
console.error('Failed to parse bot config:', e);
|
console.error('Failed to parse bot config:', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
firstOpenWindow = await createChat(app, undefined, openDir, undefined, undefined, botConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
firstOpenWindow = await createChat(app, undefined, openDir, undefined, undefined, botConfig);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -390,18 +473,7 @@ ipcMain.on('react-ready', () => {
|
|||||||
|
|
||||||
if (pendingDeepLink) {
|
if (pendingDeepLink) {
|
||||||
console.log('Processing pending deep link:', pendingDeepLink);
|
console.log('Processing pending deep link:', pendingDeepLink);
|
||||||
const parsedUrl = new URL(pendingDeepLink);
|
handleProtocolUrl(pendingDeepLink);
|
||||||
|
|
||||||
// Handle different deep link types
|
|
||||||
if (parsedUrl.hostname === 'extension') {
|
|
||||||
console.log('Sending add-extension event');
|
|
||||||
firstOpenWindow.webContents.send('add-extension', pendingDeepLink);
|
|
||||||
} else if (parsedUrl.hostname === 'sessions') {
|
|
||||||
console.log('Sending open-shared-session event');
|
|
||||||
firstOpenWindow.webContents.send('open-shared-session', pendingDeepLink);
|
|
||||||
}
|
|
||||||
// Bot URLs are handled directly through botConfig in additionalArguments
|
|
||||||
pendingDeepLink = null;
|
|
||||||
} else {
|
} else {
|
||||||
console.log('No pending deep link to process');
|
console.log('No pending deep link to process');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user