Odoo18-Base/addons/hw_drivers/browser.py
2025-01-06 10:57:38 +07:00

144 lines
4.9 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
import subprocess
from enum import Enum
from odoo.addons.hw_drivers.tools import helpers
_logger = logging.getLogger(__name__)
MIN_IMAGE_VERSION = 24.10
CHROMIUM_ARGS = [
'--incognito',
'--disable-infobars',
'--noerrdialogs',
'--no-first-run',
'--bwsi', # Use chromium without signing in
'--disable-extensions', # Disable extensions as they fill up /tmp
'--disk-cache-dir=/dev/null', # Disable disk cache
'--disk-cache-size=1', # Set disk cache size to 1 byte
'--log-level=3', # Reduce amount of logs
]
class BrowserState(Enum):
"""Enum to represent the state of the browser"""
NORMAL = 'normal'
KIOSK = 'kiosk'
FULLSCREEN = 'fullscreen'
class Browser:
"""Methods to interact with a browser"""
def __init__(self, url, _x_screen, env):
"""
:param url: URL to open in the browser
:param _x_screen: X screen number
:param env: Environment variables (e.g. os.environ.copy())
:param kiosk: Whether the browser should be in kiosk mode
"""
self.url = url
# helpers.get_version returns a string formatted as: <L|W><version> (L: Linux, W: Windows)
self.browser = 'chromium-browser' if float(helpers.get_version()[1:]) >= MIN_IMAGE_VERSION else 'firefox'
self.browser_process_name = 'chromium' if self.browser == 'chromium-browser' else self.browser
self.state = BrowserState.NORMAL
self._x_screen = _x_screen
self._set_environment(env)
def _set_environment(self, env):
"""
Set the environment variables for the browser
:param env: Environment variables (os.environ.copy())
"""
self.env = env
self.env['DISPLAY'] = f':0.{self._x_screen}'
self.env['XAUTHORITY'] = '/run/lightdm/pi/xauthority'
for key in ['HOME', 'XDG_RUNTIME_DIR', 'XDG_CACHE_HOME']:
self.env[key] = '/tmp/' + self._x_screen
def open_browser(self, url=None, state=BrowserState.NORMAL):
"""
open the browser with the given URL, or reopen it if it is already open
:param url: URL to open in the browser
:param state: State of the browser (normal, kiosk, fullscreen)
"""
self.url = url or self.url
self.state = state
# Reopen to take new url or additional args into account
self.close_browser()
browser_args = list(CHROMIUM_ARGS) if self.browser == 'chromium-browser' else []
if state == BrowserState.KIOSK:
browser_args.append("--kiosk")
elif state == BrowserState.FULLSCREEN:
browser_args.append("--start-fullscreen")
subprocess.Popen(
[
self.browser,
self.url,
*browser_args,
],
env=self.env,
)
if self.browser == 'firefox' and state == BrowserState.FULLSCREEN:
# Firefox does not support fullscreen via command line argument, so we use a keypress
self.xdotool_keystroke('F11')
helpers.save_browser_state(url=self.url)
def close_browser(self):
"""close the browser"""
# Kill browser instance (can't `instance.pkill()` as we can't keep the instance after Odoo service restarts)
# We need to terminate it because Odoo will create a new instance each time it is restarted.
subprocess.run(['pkill', self.browser_process_name], check=False)
def xdotool_keystroke(self, keystroke):
"""
Execute a keystroke using xdotool
:param keystroke: Keystroke to execute
"""
subprocess.run([
'xdotool', 'search',
'--sync', '--onlyvisible',
'--screen', self._x_screen,
'--class', self.browser_process_name,
'key', keystroke,
], check=False)
def xdotool_type(self, text):
"""
Type text using xdotool
:param text: Text to type
"""
subprocess.run([
'xdotool', 'search',
'--sync', '--onlyvisible',
'--screen', self._x_screen,
'--class', self.browser_process_name,
'type', text,
], check=False)
def open_new_tab(self, url):
"""
Open a new tab with the given URL
:param url: URL to open in the new tab
"""
self.url = url
self.xdotool_keystroke('ctrl+t')
self.xdotool_type(self.url)
self.xdotool_keystroke('Return')
def refresh(self):
"""Refresh the current tab"""
self.xdotool_keystroke('ctrl+r')
def disable_kiosk_mode(self):
"""Removes arguments to chromium-browser cli to open it without kiosk mode"""
if self.state == BrowserState.KIOSK:
self.open_browser(state=BrowserState.FULLSCREEN)