|
1 | 1 | import subprocess |
2 | 2 | import time |
3 | 3 | import os |
| 4 | +import re |
| 5 | +from pathlib import Path |
| 6 | +from selenium import webdriver |
| 7 | +from selenium.webdriver.chrome.options import Options |
4 | 8 |
|
5 | 9 | def get_app_name(): |
6 | 10 | """Get the app name from environment variable, falling back to default""" |
7 | 11 | return os.getenv("UNITY_APP_NAME", "SampleApp") |
8 | 12 |
|
| 13 | +def get_product_name(): |
| 14 | + """Get the product name from ProjectSettings.asset""" |
| 15 | + project_settings_path = Path(__file__).resolve().parent.parent.parent / 'ProjectSettings' / 'ProjectSettings.asset' |
| 16 | + |
| 17 | + if not project_settings_path.exists(): |
| 18 | + print(f"Warning: ProjectSettings.asset not found at {project_settings_path}") |
| 19 | + return "SampleApp" # Fallback to default |
| 20 | + |
| 21 | + with open(project_settings_path, 'r') as f: |
| 22 | + content = f.read() |
| 23 | + |
| 24 | + # Extract productName using regex |
| 25 | + match = re.search(r'productName: (.+)', content) |
| 26 | + if match: |
| 27 | + product_name = match.group(1).strip() |
| 28 | + return product_name |
| 29 | + |
| 30 | + # If regex fails, return default |
| 31 | + return "SampleApp" |
| 32 | + |
| 33 | +def get_logout_url_from_unity_logs(): |
| 34 | + """Monitor Unity logs to capture logout URLs.""" |
| 35 | + import tempfile |
| 36 | + |
| 37 | + product_name = os.getenv("UNITY_APP_NAME", get_product_name()) |
| 38 | + |
| 39 | + # Unity log file locations on macOS |
| 40 | + log_paths = [ |
| 41 | + os.path.join(os.path.expanduser("~"), "Library", "Logs", "Unity", product_name, "Player.log"), |
| 42 | + os.path.join(os.path.expanduser("~"), "Library", "Logs", product_name, "Player.log"), |
| 43 | + os.path.join(tempfile.gettempdir(), "UnityPlayer.log"), |
| 44 | + "Player.log" # Current directory |
| 45 | + ] |
| 46 | + |
| 47 | + for log_path in log_paths: |
| 48 | + if os.path.exists(log_path): |
| 49 | + print(f"Monitoring Unity log for logout URL: {log_path}") |
| 50 | + try: |
| 51 | + with open(log_path, 'r', encoding='utf-8', errors='ignore') as f: |
| 52 | + content = f.read() |
| 53 | + # Look for logout URLs in Unity logs (uses same PASSPORT_AUTH_URL pattern) |
| 54 | + # Now includes [Immutable] tag from PassportLogger |
| 55 | + matches = re.findall(r'(?:\[Immutable\] PASSPORT_AUTH_URL: |PASSPORT_AUTH_URL: |LaunchAuthURL : )(https?://[^\s]+)', content) |
| 56 | + if matches: |
| 57 | + # Get the last URL and make sure it's a logout URL |
| 58 | + for url in reversed(matches): |
| 59 | + if 'logout' in url or 'im-logged-out' in url: |
| 60 | + print(f"Found logout URL: {url}") |
| 61 | + return url |
| 62 | + except Exception as e: |
| 63 | + print(f"Error reading log file {log_path}: {e}") |
| 64 | + continue |
| 65 | + |
| 66 | + print("No logout URL found in Unity logs") |
| 67 | + return None |
| 68 | + |
| 69 | +def logout_with_controlled_browser(): |
| 70 | + """Handle logout using the controlled browser instance instead of letting Unity open its own browser.""" |
| 71 | + print("Starting controlled logout process...") |
| 72 | + |
| 73 | + # Set up Chrome WebDriver options to connect to the existing browser instance |
| 74 | + chrome_options = Options() |
| 75 | + chrome_options.add_experimental_option("debuggerAddress", "localhost:9222") |
| 76 | + |
| 77 | + # Brave binary location on macOS |
| 78 | + brave_path = "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser" |
| 79 | + chrome_options.binary_location = brave_path |
| 80 | + |
| 81 | + try: |
| 82 | + # Connect to the existing browser instance |
| 83 | + driver = webdriver.Chrome(options=chrome_options) |
| 84 | + print("Connected to existing browser for logout") |
| 85 | + |
| 86 | + # Monitor Unity logs for logout URL |
| 87 | + print("Monitoring Unity logs for logout URL...") |
| 88 | + logout_url = None |
| 89 | + for attempt in range(15): # Try for 15 seconds (shorter timeout) |
| 90 | + logout_url = get_logout_url_from_unity_logs() |
| 91 | + if logout_url: |
| 92 | + break |
| 93 | + time.sleep(1) |
| 94 | + |
| 95 | + if logout_url: |
| 96 | + print(f"Navigating controlled browser to logout URL: {logout_url}") |
| 97 | + driver.get(logout_url) |
| 98 | + |
| 99 | + # Wait for logout page to load |
| 100 | + time.sleep(3) |
| 101 | + print("Logout completed in controlled browser") |
| 102 | + |
| 103 | + # Check final page |
| 104 | + current_url = driver.current_url |
| 105 | + print(f"Final logout URL: {current_url}") |
| 106 | + |
| 107 | + # Extract the deep-link from the redirect |
| 108 | + # Look for immutablerunner://logout in the response or extract from returnTo parameter |
| 109 | + if 'returnTo=' in logout_url: |
| 110 | + # Extract returnTo parameter |
| 111 | + match = re.search(r'returnTo=([^&]+)', logout_url) |
| 112 | + if match: |
| 113 | + from urllib.parse import unquote |
| 114 | + return_to = unquote(match.group(1)) |
| 115 | + print(f"Extracted returnTo deep-link: {return_to}") |
| 116 | + |
| 117 | + # Trigger the deep-link manually |
| 118 | + print(f"Triggering deep-link manually: {return_to}") |
| 119 | + subprocess.run(['open', return_to], check=False) |
| 120 | + time.sleep(2) |
| 121 | + |
| 122 | + else: |
| 123 | + print("Could not find logout URL in Unity logs - logout may complete without browser interaction") |
| 124 | + |
| 125 | + except Exception as e: |
| 126 | + print(f"Error during controlled logout: {e}") |
| 127 | + print("Logout may need to be handled by Unity directly") |
| 128 | + |
| 129 | + print("Controlled logout process completed") |
| 130 | + |
9 | 131 | def open_sample_app(): |
10 | 132 | app_name = get_app_name() |
11 | 133 | print(f"Opening Unity sample app ({app_name})...") |
|
0 commit comments