diff --git a/backend/app/controller/electron_browser.cjs b/backend/app/controller/electron_browser.cjs new file mode 100644 index 00000000..5b4fc698 --- /dev/null +++ b/backend/app/controller/electron_browser.cjs @@ -0,0 +1,393 @@ +const { app, BrowserWindow, ipcMain } = require('electron'); +const path = require('path'); + +// Parse command line arguments +const args = process.argv.slice(2); +const userDataDir = args[0]; +const cdpPort = args[1]; +const startUrl = args[2] || 'https://www.google.com'; + +// This must be called before app.ready +app.commandLine.appendSwitch('remote-debugging-port', cdpPort); + +console.log('[ELECTRON BROWSER] Starting with:'); +console.log(' Chrome version:', process.versions.chrome); +console.log(' User data dir (requested):', userDataDir); +console.log(' CDP port:', cdpPort); +console.log(' Start URL:', startUrl); + +// Set app paths - must be done before app.ready +// Do NOT use commandLine.appendSwitch('user-data-dir') as it conflicts with setPath +app.setPath('userData', userDataDir); +app.setPath('sessionData', userDataDir); + +app.whenReady().then(async () => { + const { session } = require('electron'); + const fs = require('fs'); + const path = require('path'); + + // Log actual paths being used + console.log('[ELECTRON BROWSER] Actual paths:'); + console.log(' app.getPath("userData"):', app.getPath('userData')); + console.log(' app.getPath("sessionData"):', app.getPath('sessionData')); + console.log(' app.getPath("cache"):', app.getPath('cache')); + console.log(' app.getPath("temp"):', app.getPath('temp')); + console.log(' process.argv:', process.argv); + + // Check command line switches + console.log('[ELECTRON BROWSER] Command line switches:'); + console.log(' user-data-dir:', app.commandLine.getSwitchValue('user-data-dir')); + console.log(' remote-debugging-port:', app.commandLine.getSwitchValue('remote-debugging-port')); + + // Log partition session info + const userLoginSession = session.fromPartition('persist:user_login'); + console.log('[ELECTRON BROWSER] Session info:'); + console.log(' Partition: persist:user_login'); + console.log(' Session storage path:', userLoginSession.getStoragePath()); + + // Check if Cookies file exists + const cookiesPath = path.join(app.getPath('userData'), 'Partitions', 'user_login', 'Cookies'); + console.log('[ELECTRON BROWSER] Cookies path:', cookiesPath); + console.log('[ELECTRON BROWSER] Cookies exists:', fs.existsSync(cookiesPath)); + if (fs.existsSync(cookiesPath)) { + const stats = fs.statSync(cookiesPath); + console.log('[ELECTRON BROWSER] Cookies file size:', stats.size, 'bytes'); + } + const win = new BrowserWindow({ + width: 1400, + height: 900, + title: 'Eigent Browser - Login', + webPreferences: { + nodeIntegration: true, + contextIsolation: false, + webviewTag: true + } + }); + + // Create navigation bar and webview HTML + const html = ` + + + + + + + + + + + + + + +`; + + win.loadURL('data:text/html;charset=UTF-8,' + encodeURIComponent(html)); + + // Show window when ready + win.once('ready-to-show', () => { + win.show(); + + // Log cookies periodically to track changes + setInterval(async () => { + try { + const cookies = await userLoginSession.cookies.get({}); + console.log('[ELECTRON BROWSER] Current cookies count:', cookies.length); + if (cookies.length > 0) { + console.log('[ELECTRON BROWSER] Cookie domains:', [...new Set(cookies.map(c => c.domain))]); + } + } catch (error) { + console.error('[ELECTRON BROWSER] Failed to get cookies:', error); + } + }, 5000); // Check every 5 seconds + }); + + win.on('closed', async () => { + console.log('[ELECTRON BROWSER] Window closed, preparing to quit...'); + + // Flush storage data before quitting to ensure cookies are saved + try { + const { session } = require('electron'); + const fs = require('fs'); + const path = require('path'); + const userLoginSession = session.fromPartition('persist:user_login'); + + // Log cookies before flush + const cookiesBeforeFlush = await userLoginSession.cookies.get({}); + console.log('[ELECTRON BROWSER] Cookies count before flush:', cookiesBeforeFlush.length); + + // Flush storage + console.log('[ELECTRON BROWSER] Flushing storage data...'); + await userLoginSession.flushStorageData(); + console.log('[ELECTRON BROWSER] Storage data flushed successfully'); + + // Check cookies file after flush + const cookiesPath = path.join(app.getPath('userData'), 'Partitions', 'user_login', 'Cookies'); + if (fs.existsSync(cookiesPath)) { + const stats = fs.statSync(cookiesPath); + console.log('[ELECTRON BROWSER] Cookies file size after flush:', stats.size, 'bytes'); + } else { + console.log('[ELECTRON BROWSER] WARNING: Cookies file does not exist after flush!'); + } + } catch (error) { + console.error('[ELECTRON BROWSER] Failed to flush storage data:', error); + } + app.quit(); + }); +}); + +let isQuitting = false; + +app.on('before-quit', async (event) => { + if (isQuitting) return; + + // Prevent immediate quit to allow storage flush and cookie sync + event.preventDefault(); + isQuitting = true; + + console.log('[ELECTRON BROWSER] before-quit event triggered'); + + try { + const { session } = require('electron'); + const fs = require('fs'); + const path = require('path'); + const userLoginSession = session.fromPartition('persist:user_login'); + + // Log cookies before flush + const cookiesBeforeQuit = await userLoginSession.cookies.get({}); + console.log('[ELECTRON BROWSER] Cookies count before quit:', cookiesBeforeQuit.length); + if (cookiesBeforeQuit.length > 0) { + console.log('[ELECTRON BROWSER] Cookie domains before quit:', [...new Set(cookiesBeforeQuit.map(c => c.domain))]); + } + + // Flush storage + console.log('[ELECTRON BROWSER] Flushing storage on quit...'); + await userLoginSession.flushStorageData(); + console.log('[ELECTRON BROWSER] Storage data flushed on quit'); + } catch (error) { + console.error('[ELECTRON BROWSER] Failed to sync cookies:', error); + } finally { + console.log('[ELECTRON BROWSER] Exiting now...'); + // Force quit after sync + app.exit(0); + } +}); + +app.on('window-all-closed', () => { + if (!isQuitting) { + app.quit(); + } +}); diff --git a/backend/app/controller/tool_controller.py b/backend/app/controller/tool_controller.py index 29320da5..b9cb7ffd 100644 --- a/backend/app/controller/tool_controller.py +++ b/backend/app/controller/tool_controller.py @@ -347,410 +347,13 @@ async def open_browser_login(): "note": "Your login data will be saved in the profile." } - # Create Electron browser script with .cjs extension for CommonJS + # Use static Electron browser script electron_script_path = os.path.join(os.path.dirname(__file__), "electron_browser.cjs") - electron_script_content = ''' -const { app, BrowserWindow, ipcMain } = require('electron'); -const path = require('path'); -// Parse command line arguments -const args = process.argv.slice(2); -const userDataDir = args[0]; -const cdpPort = args[1]; -const startUrl = args[2] || 'https://www.google.com'; + # Verify script exists + if not os.path.exists(electron_script_path): + raise FileNotFoundError(f"Electron browser script not found: {electron_script_path}") -// This must be called before app.ready -app.commandLine.appendSwitch('remote-debugging-port', cdpPort); - -console.log('[ELECTRON BROWSER] Starting with:'); -console.log(' Chrome version:', process.versions.chrome); -console.log(' User data dir (requested):', userDataDir); -console.log(' CDP port:', cdpPort); -console.log(' Start URL:', startUrl); - -// Set app paths - must be done before app.ready -// Do NOT use commandLine.appendSwitch('user-data-dir') as it conflicts with setPath -app.setPath('userData', userDataDir); -app.setPath('sessionData', userDataDir); - -app.whenReady().then(async () => { - const { session } = require('electron'); - const fs = require('fs'); - const path = require('path'); - - // Log actual paths being used - console.log('[ELECTRON BROWSER] Actual paths:'); - console.log(' app.getPath("userData"):', app.getPath('userData')); - console.log(' app.getPath("sessionData"):', app.getPath('sessionData')); - console.log(' app.getPath("cache"):', app.getPath('cache')); - console.log(' app.getPath("temp"):', app.getPath('temp')); - console.log(' process.argv:', process.argv); - - // Check command line switches - console.log('[ELECTRON BROWSER] Command line switches:'); - console.log(' user-data-dir:', app.commandLine.getSwitchValue('user-data-dir')); - console.log(' remote-debugging-port:', app.commandLine.getSwitchValue('remote-debugging-port')); - - // Log partition session info - const userLoginSession = session.fromPartition('persist:user_login'); - console.log('[ELECTRON BROWSER] Session info:'); - console.log(' Partition: persist:user_login'); - console.log(' Session storage path:', userLoginSession.getStoragePath()); - - // Check if Cookies file exists - const cookiesPath = path.join(app.getPath('userData'), 'Partitions', 'user_login', 'Cookies'); - console.log('[ELECTRON BROWSER] Cookies path:', cookiesPath); - console.log('[ELECTRON BROWSER] Cookies exists:', fs.existsSync(cookiesPath)); - if (fs.existsSync(cookiesPath)) { - const stats = fs.statSync(cookiesPath); - console.log('[ELECTRON BROWSER] Cookies file size:', stats.size, 'bytes'); - } - const win = new BrowserWindow({ - width: 1400, - height: 900, - title: 'Eigent Browser - Login', - webPreferences: { - nodeIntegration: true, - contextIsolation: false, - webviewTag: true - } - }); - - // Create navigation bar and webview - const html = ` - - - - - - - - - - - - - - -`; - - win.loadURL('data:text/html;charset=UTF-8,' + encodeURIComponent(html)); - - // Show window when ready - win.once('ready-to-show', () => { - win.show(); - - // Log cookies periodically to track changes - setInterval(async () => { - try { - const cookies = await userLoginSession.cookies.get({}); - console.log('[ELECTRON BROWSER] Current cookies count:', cookies.length); - if (cookies.length > 0) { - console.log('[ELECTRON BROWSER] Cookie domains:', [...new Set(cookies.map(c => c.domain))]); - } - } catch (error) { - console.error('[ELECTRON BROWSER] Failed to get cookies:', error); - } - }, 5000); // Check every 5 seconds - }); - - win.on('closed', async () => { - console.log('[ELECTRON BROWSER] Window closed, preparing to quit...'); - - // Flush storage data before quitting to ensure cookies are saved - try { - const { session } = require('electron'); - const fs = require('fs'); - const path = require('path'); - const userLoginSession = session.fromPartition('persist:user_login'); - - // Log cookies before flush - const cookiesBeforeFlush = await userLoginSession.cookies.get({}); - console.log('[ELECTRON BROWSER] Cookies count before flush:', cookiesBeforeFlush.length); - - // Flush storage - console.log('[ELECTRON BROWSER] Flushing storage data...'); - await userLoginSession.flushStorageData(); - console.log('[ELECTRON BROWSER] Storage data flushed successfully'); - - // Check cookies file after flush - const cookiesPath = path.join(app.getPath('userData'), 'Partitions', 'user_login', 'Cookies'); - if (fs.existsSync(cookiesPath)) { - const stats = fs.statSync(cookiesPath); - console.log('[ELECTRON BROWSER] Cookies file size after flush:', stats.size, 'bytes'); - } else { - console.log('[ELECTRON BROWSER] WARNING: Cookies file does not exist after flush!'); - } - } catch (error) { - console.error('[ELECTRON BROWSER] Failed to flush storage data:', error); - } - app.quit(); - }); -}); - -let isQuitting = false; - -app.on('before-quit', async (event) => { - if (isQuitting) return; - - // Prevent immediate quit to allow storage flush and cookie sync - event.preventDefault(); - isQuitting = true; - - console.log('[ELECTRON BROWSER] before-quit event triggered'); - - try { - const { session } = require('electron'); - const fs = require('fs'); - const path = require('path'); - const userLoginSession = session.fromPartition('persist:user_login'); - - // Log cookies before flush - const cookiesBeforeQuit = await userLoginSession.cookies.get({}); - console.log('[ELECTRON BROWSER] Cookies count before quit:', cookiesBeforeQuit.length); - if (cookiesBeforeQuit.length > 0) { - console.log('[ELECTRON BROWSER] Cookie domains before quit:', [...new Set(cookiesBeforeQuit.map(c => c.domain))]); - } - - // Flush storage - console.log('[ELECTRON BROWSER] Flushing storage on quit...'); - await userLoginSession.flushStorageData(); - console.log('[ELECTRON BROWSER] Storage data flushed on quit'); - } catch (error) { - console.error('[ELECTRON BROWSER] Failed to sync cookies:', error); - } finally { - console.log('[ELECTRON BROWSER] Exiting now...'); - // Force quit after sync - app.exit(0); - } -}); - -app.on('window-all-closed', () => { - if (!isQuitting) { - app.quit(); - } -}); -''' - - # Write the Electron script - with open(electron_script_path, 'w') as f: - f.write(electron_script_content) - - # Find Electron executable - # Try to use the same Electron version as the main app electron_cmd = "npx" electron_args = [ electron_cmd, @@ -775,7 +378,9 @@ app.on('window-all-closed', () => { cwd=app_dir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, # Redirect stderr to stdout - universal_newlines=True, + text=True, + encoding='utf-8', + errors='replace', # Replace undecodable chars instead of crashing bufsize=1 # Line buffered ) @@ -791,17 +396,7 @@ app.on('window-all-closed', () => { # Wait a bit for Electron to start import asyncio await asyncio.sleep(3) - - # Clean up the script file after a delay - async def cleanup_script(): - await asyncio.sleep(10) - try: - os.remove(electron_script_path) - except: - pass - - asyncio.create_task(cleanup_script()) - + logger.info(f"[PROFILE USER LOGIN] Electron browser launched with PID {process.pid}") return { diff --git a/backend/app/utils/toolkit/terminal_toolkit.py b/backend/app/utils/toolkit/terminal_toolkit.py index 9109dcab..659decd5 100644 --- a/backend/app/utils/toolkit/terminal_toolkit.py +++ b/backend/app/utils/toolkit/terminal_toolkit.py @@ -169,7 +169,7 @@ class TerminalToolkit(BaseTerminalToolkit, AbstractToolkit): source_cfg = os.path.join(source_venv, "pyvenv.cfg") python_home = None - with open(source_cfg, 'r') as f: + with open(source_cfg, 'r', encoding='utf-8') as f: for line in f: if line.startswith('home = '): python_home = line.split('=', 1)[1].strip()