#!/usr/bin/env bash set -euo pipefail script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/deckless" settings_env="${DECKLESS_SETTINGS_ENV:-${config_dir}/deckless.env}" legacy_proxy_env="${HOME}/.config/network/proxy-env.sh" proxy_env="${DECKLESS_PROXY_ENV:-${config_dir}/proxy-env.sh}" steam_bin="${DECKLESS_STEAM_BIN:-/usr/bin/steam}" if [[ -r "$settings_env" ]]; then # shellcheck disable=SC1090 . "$settings_env" fi steam_root="$(readlink -e "$HOME/.steam/steam" || true)" if [[ -z "$steam_root" ]]; then steam_root="${XDG_DATA_HOME:-$HOME/.local/share}/Steam" fi target="${steam_root}/ubuntu12_64/steamwebhelper_sniper_wrap.sh" target_dir="${target%/*}" state_dir="${XDG_STATE_HOME:-$HOME/.local/state}/deckless/steam" session_state="${state_dir}/session.env" original_wrapper="${state_dir}/steamwebhelper_sniper_wrap.sh.original" sync_helper="${script_dir}/deckless-sync-webhelper-wrapper" heal_helper="${script_dir}/deckless-webhelper-heal" cleanup_helper="${script_dir}/deckless-webhelper-cleanup" cleanup_done=0 if [[ ! -d "$target_dir" ]]; then printf 'Steam runtime directory not found: %s\n' "$target_dir" >&2 exit 1 fi if [[ ! -x "$steam_bin" ]]; then printf 'Steam binary not found: %s\n' "$steam_bin" >&2 exit 1 fi for helper in "$sync_helper" "$heal_helper" "$cleanup_helper"; do if [[ ! -x "$helper" ]]; then printf 'Deckless helper not found: %s\n' "$helper" >&2 exit 1 fi done mkdir -p "$state_dir" steam_activity_running() { local args while IFS= read -r args; do if [[ "$args" == *"${steam_root}/ubuntu12_32/steam"* ]] || \ [[ "$args" == *"${steam_root}/ubuntu12_64/steamwebhelper"* ]] || \ [[ "$args" == *"${target}"* ]] || \ [[ "$args" == *"${steam_bin}"* ]]; then return 0 fi done < <(ps -ww -eo args=) return 1 } terminate_stale_helpers() { local pid local args while read -r pid args; do case "$args" in "$sync_helper"|\ "$sync_helper "*|\ "$heal_helper"|\ "$heal_helper "*|\ "$cleanup_helper"|\ "$cleanup_helper "*|\ "bash $sync_helper"|\ "bash $sync_helper "*|\ "bash $heal_helper"|\ "bash $heal_helper "*|\ "bash $cleanup_helper"|\ "bash $cleanup_helper "*|\ "/usr/bin/bash $sync_helper"|\ "/usr/bin/bash $sync_helper "*|\ "/usr/bin/bash $heal_helper"|\ "/usr/bin/bash $heal_helper "*|\ "/usr/bin/bash $cleanup_helper"|\ "/usr/bin/bash $cleanup_helper "*) kill -TERM "$pid" 2>/dev/null || true ;; esac done < <(ps -ww -eo pid=,args=) } start_detached_helper() { local helper="$1" if command -v setsid >/dev/null 2>&1; then setsid -f "$helper" >/dev/null 2>&1 /dev/null 2>&1 /dev/null && [[ -f "$original_wrapper" ]]; then cp -a "$original_wrapper" "$target" fi rm -f "$session_state" "$original_wrapper" cleanup_done=1 } apply_optional_locale() { if [[ -n "${DECKLESS_LANG:-}" ]]; then while IFS='=' read -r name _; do [[ $name == LC_* ]] && unset "$name" done < <(env) export LANG="$DECKLESS_LANG" export LC_CTYPE="$DECKLESS_LANG" fi if [[ -n "${DECKLESS_FC_LANG:-}" ]]; then export FC_LANG="$DECKLESS_FC_LANG" fi case "${DECKLESS_INPUT_METHOD:-}" in fcitx|fcitx5) export GTK_IM_MODULE='fcitx' export QT_IM_MODULE='fcitx' export XMODIFIERS='@im=fcitx' export SDL_IM_MODULE='fcitx' export INPUT_METHOD='fcitx' ;; ibus) export GTK_IM_MODULE='ibus' export QT_IM_MODULE='ibus' export XMODIFIERS='@im=ibus' export SDL_IM_MODULE='ibus' export INPUT_METHOD='ibus' ;; esac } normalize_proxy_server() { case "$1" in socks5h://*) printf 'socks5://%s\n' "${1#socks5h://}" ;; socks5://*|http://*|https://*) printf '%s\n' "$1" ;; *) return 1 ;; esac } build_chromium_bypass_list() { local raw="$1" local entry local -a entries=() if [[ "$raw" == *';'* ]]; then printf '%s\n' "$raw" return 0 fi IFS=',' read -r -a input_entries <<< "$raw" for entry in "${input_entries[@]}"; do entry="${entry//[[:space:]]/}" [[ -z "$entry" ]] && continue [[ "$entry" == .* ]] && entry="*${entry}" entries+=("$entry") done ((${#entries[@]} == 0)) && return 0 local IFS=';' printf '%s\n' "${entries[*]}" } if ! steam_activity_running; then terminate_stale_helpers restore_official_wrapper fi apply_optional_locale if [[ -z "${SDL_VIDEODRIVER:-}" ]]; then if [[ -n "${WAYLAND_DISPLAY:-}" ]]; then export SDL_VIDEODRIVER='wayland' elif [[ -n "${DISPLAY:-}" ]]; then export SDL_VIDEODRIVER='x11' fi fi if [[ -z "${XDG_RUNTIME_DIR:-}" ]]; then xdg_runtime_dir="/run/user/$(id -u)" export XDG_RUNTIME_DIR="$xdg_runtime_dir" fi if [[ -r "$proxy_env" ]]; then # shellcheck disable=SC1090 . "$proxy_env" elif [[ -r "$legacy_proxy_env" ]]; then # shellcheck disable=SC1090 . "$legacy_proxy_env" fi proxy_candidate="${DECKLESS_PROXY_SERVER:-${DECKLESS_WEBHELPER_PROXY_SERVER:-${HTTPS_PROXY:-${https_proxy:-${HTTP_PROXY:-${http_proxy:-${ALL_PROXY:-${all_proxy:-}}}}}}}}" bypass_candidate="${DECKLESS_PROXY_BYPASS_LIST:-${DECKLESS_WEBHELPER_PROXY_BYPASS_LIST:-${NO_PROXY:-${no_proxy:-steamloopback.host,localhost,127.0.0.1,::1,.local,.lan,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12}}}}" proxy_server='' proxy_bypass='' if [[ -n "$proxy_candidate" ]]; then proxy_server="$(normalize_proxy_server "$proxy_candidate" || true)" fi if [[ -n "$bypass_candidate" ]]; then proxy_bypass="$(build_chromium_bypass_list "$bypass_candidate")" fi tmp_state="$(mktemp "${state_dir}/.session.env.XXXXXX")" trap 'rm -f "${tmp_state:-}"' EXIT { printf '# deckless session state\n' printf 'DECKLESS_WEBHELPER_PROXY_SERVER=%q\n' "$proxy_server" printf 'DECKLESS_WEBHELPER_PROXY_BYPASS_LIST=%q\n' "$proxy_bypass" } >"$tmp_state" chmod 0600 "$tmp_state" mv -f "$tmp_state" "$session_state" trap - EXIT unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY unset ALL_PROXY all_proxy unset no_proxy NO_PROXY unset DECKLESS_WEBHELPER_PROXY_SERVER DECKLESS_WEBHELPER_PROXY_BYPASS_LIST trap 'restore_official_wrapper' EXIT HUP INT TERM start_detached_helper "$heal_helper" start_detached_helper "$cleanup_helper" set +e "$steam_bin" "$@" steam_status=$? set -e restore_official_wrapper trap - EXIT HUP INT TERM exit "$steam_status"