#!/usr/bin/env bash # open_onlyoffice_file — abre un archivo en una INSTANCIA AISLADA de ONLYOFFICE # Desktop Editors (Linux/X11), sin perturbar la instancia personal del usuario. # # Funcion impura: lanza un proceso GUI, lee estado de ventanas (xdotool) y # escribe directorios en /tmp. Imprime una linea JSON con el resultado. # # Por que "instancia aislada": ONLYOFFICE Desktop es single-instance por # usuario — un segundo `onlyoffice-desktopeditors ` se reenvia a la # instancia viva y abre el archivo como PESTAÑA en su ventana. El lock # single-instance NO se rompe con XDG_CONFIG_HOME, pero SI se rompe lanzando # con HOME y XDG_RUNTIME_DIR propios. Por eso cada "slot" nombrado (instance) # usa su propio HOME/XDG_RUNTIME_DIR/XDG_CONFIG_HOME bajo /tmp. # Sin -e: las busquedas de ventana (xdotool search) pueden no matchear y # devolver exit !=0; no deben abortar la funcion. -u y pipefail se mantienen. set -uo pipefail open_onlyoffice_file() { local file_path="${1:-}" local instance="${2:-demo}" if [[ -z "$file_path" ]]; then echo "open_onlyoffice_file: falta " >&2 echo "uso: open_onlyoffice_file [instance]" >&2 return 2 fi # 1. Dependencias del sistema. local dep for dep in onlyoffice-desktopeditors wmctrl xdotool; do if ! command -v "$dep" >/dev/null 2>&1; then echo "open_onlyoffice_file: falta dependencia '$dep' (instala el paquete correspondiente)" >&2 return 1 fi done # 2. El archivo DEBE existir — esta funcion no crea archivos. if [[ ! -f "$file_path" ]]; then echo "open_onlyoffice_file: el archivo no existe: $file_path (esta funcion no crea archivos)" >&2 return 1 fi # Ruta absoluta y basename para titular/buscar la ventana. local abs_path base abs_path=$(readlink -f -- "$file_path") base=$(basename -- "$abs_path") # 3. Slot aislado: HOME/XDG_RUNTIME_DIR/XDG_CONFIG_HOME propios bajo /tmp. local oo_home="/tmp/oo_${instance}" local oo_run="/tmp/oo_${instance}_run" local oo_cfg="${oo_home}/.config" mkdir -p "$oo_home" "$oo_cfg" "$oo_run" chmod 700 "$oo_run" 2>/dev/null || true # 4. Idempotencia: si ya hay ventana para ese basename, no relanzar. local existing_wid existing_wid=$(xdotool search --name -- "$base" 2>/dev/null | head -1 || true) if [[ -n "$existing_wid" ]]; then local wid_hex wid_hex=$(printf '0x%x' "$existing_wid" 2>/dev/null || echo "$existing_wid") printf '{"instance":"%s","file":"%s","wid":"%s","pid":null,"status":"open"}\n' \ "$instance" "$abs_path" "$wid_hex" return 0 fi # 5. Lanzar la instancia aislada con su env propio. setsid lo desacopla de # la terminal; redirige todo a un log del slot. env HOME="$oo_home" XDG_RUNTIME_DIR="$oo_run" XDG_CONFIG_HOME="$oo_cfg" \ setsid onlyoffice-desktopeditors "$abs_path" \ >"/tmp/oo_${instance}.log" 2>&1 ~83 iteraciones. local wid="" i=0 max=83 while [[ $i -lt $max ]]; do wid=$(xdotool search --name -- "$base" 2>/dev/null | head -1 || true) [[ -n "$wid" ]] && break read -t 0.3 _ /dev/null || true i=$((i + 1)) done if [[ -z "$wid" ]]; then printf '{"instance":"%s","file":"%s","wid":null,"pid":%s,"status":"timeout"}\n' \ "$instance" "$abs_path" "$launch_pid" return 1 fi local wid_hex wid_hex=$(printf '0x%x' "$wid" 2>/dev/null || echo "$wid") # El pid del proceso real (DesktopEditors) puede diferir del launcher; el # launcher reexec/fork. Reportamos el pid del launcher (best-effort). printf '{"instance":"%s","file":"%s","wid":"%s","pid":%s,"status":"open"}\n' \ "$instance" "$abs_path" "$wid_hex" "$launch_pid" return 0 } # Ejecutable directo: `bash open_onlyoffice_file.sh [instance]`. # Sourceado: define la funcion sin ejecutarla. if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then open_onlyoffice_file "$@" fi