Jelajahi Sumber

booking refresh: skip headless login, clear stale profile locks

Headless password auth always fails; skip it and go straight to the
headed browser when the session is expired. Also clear SingletonLock/
Socket/Cookie files before every launchPersistentContext so stale locks
from a previous container restart don't block launch.
ZiB 4 bulan lalu
induk
melakukan
4a4fe3442f

+ 6 - 36
room_cal/service_api/typescript/booking/refresh-cookies.ts

@@ -285,45 +285,15 @@ export async function refresh(mode: string): Promise<CredentialsPayload> {
     await page.waitForLoadState('domcontentloaded');
 
     if (!page.url().includes('ses=')) {
-      if (email && password && page.url().includes('account.booking.com/sign-in')) {
-        console.error('Session expired — attempting auto-login (headless)...');
-        let autoLoginOk = false;
-        try {
-          await performLogin(page, email, password);
-          await page.waitForURL(
-            url => url.toString().includes('ses=') || needsChallenge(url.toString()),
-            { timeout: 60_000 },
-          );
-          if (needsChallenge(page.url())) {
-            await handlePostLoginChallenge(page, smsMasked);
-            await page.waitForURL('**ses=**', { timeout: 120_000 });
-          }
-          autoLoginOk = true;
-        } catch (err) {
-          console.error(`[booking] Headless auto-login failed (${(err as Error).message}) — falling back to headed browser.`);
-        }
-        if (!autoLoginOk) {
-          if (FORCE_HEADLESS) {
-            await context.close();
-            throw new Error('Session expired and headless auto-login failed — re-run without HEADLESS=1.');
-          }
-          // Reset so the headed browser can attempt login cleanly.
-          loginDisabledReason = null;
-          await context.close();
-          headless = false;
-          context = await openCtx(false);
-          page = context.pages()[0] ?? await context.newPage();
-        }
-      } else if (FORCE_HEADLESS) {
+      if (FORCE_HEADLESS) {
         await context.close();
         throw new Error('Session expired — re-run without HEADLESS=1 to re-authenticate.');
-      } else {
-        console.error('Profile session expired — switching to headed browser for login...');
-        await context.close();
-        headless = false;
-        context = await openCtx(false);
-        page = context.pages()[0] ?? await context.newPage();
       }
+      console.error('Session expired — switching to headed browser for login...');
+      await context.close();
+      headless = false;
+      context = await openCtx(false);
+      page = context.pages()[0] ?? await context.newPage();
     } else {
       console.error('Session valid — continuing silently.');
     }

+ 6 - 0
room_cal/service_api/typescript/shared/browser.ts

@@ -2,6 +2,7 @@ import { chromium } from 'playwright';
 import type { BrowserContext } from 'playwright';
 import * as path from 'path';
 import * as os from 'os';
+import * as fs from 'fs';
 
 const DATA_HOME = process.env.ROOM_CAL_DATA_HOME ?? path.join(os.homedir(), '.local', 'room_cal');
 
@@ -11,6 +12,11 @@ export function profileDir(service: string, mode: string): string {
 }
 
 export async function openPersistentContext(profilePath: string, headless: boolean): Promise<BrowserContext> {
+  // Remove stale lock files left by a previous process or container restart.
+  for (const lock of ['SingletonLock', 'SingletonSocket', 'SingletonCookie']) {
+    const p = path.join(profilePath, lock);
+    try { fs.unlinkSync(p); } catch { /* not present */ }
+  }
   return chromium.launchPersistentContext(profilePath, {
     headless,
     args: ['--disable-blink-features=AutomationControlled'],