#!/usr/bin/env bash # Shared helpers for GREE Controller operational scripts. set -Eeuo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" SERVICE_NAME="gree-controller.service" SERVICE_USER="gree-controller" SERVICE_GROUP="gree-controller" INSTALL_DIR="/opt/gree-controller" INSTALL_BINARY="$INSTALL_DIR/gree-controller" DATA_DIR="/var/lib/gree-controller" ENV_FILE="/etc/gree-controller.env" SERVICE_FILE="/etc/systemd/system/$SERVICE_NAME" BACKUP_ROOT="/var/backups/gree-controller" say() { printf '\033[1;32m==>\033[0m %s\n' "$*"; } warn() { printf '\033[1;33mWARNING:\033[0m %s\n' "$*" >&2; } fail() { printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2; exit 1; } require_root() { [[ ${EUID:-$(id -u)} -eq 0 ]] || fail "Run this script as root (for example: sudo $0)." } require_systemd() { command -v systemctl >/dev/null 2>&1 || fail "systemd/systemctl is required for the LXC installation." } run_privileged() { if [[ ${EUID:-$(id -u)} -eq 0 ]]; then "$@" elif command -v sudo >/dev/null 2>&1; then sudo "$@" else fail "Root/sudo privileges are required: $*" fi } install_build_dependencies() { local missing=0 for cmd in curl cc make pkg-config; do command -v "$cmd" >/dev/null 2>&1 || missing=1 done command -v python3 >/dev/null 2>&1 || missing=1 [[ "$missing" -eq 1 ]] || return 0 if command -v apt-get >/dev/null 2>&1; then say "Installing build dependencies" run_privileged apt-get update run_privileged apt-get install -y --no-install-recommends \ build-essential curl ca-certificates pkg-config python3 elif command -v dnf >/dev/null 2>&1; then say "Installing build dependencies" run_privileged dnf install -y gcc gcc-c++ make curl ca-certificates pkgconf-pkg-config python3 elif command -v apk >/dev/null 2>&1; then say "Installing build dependencies" run_privileged apk add --no-cache build-base curl ca-certificates pkgconf python3 else fail "Unsupported package manager. Install a C compiler, make, curl, pkg-config, Python 3 and CA certificates." fi } ensure_rust() { if command -v cargo >/dev/null 2>&1; then return 0 fi command -v curl >/dev/null 2>&1 || fail "curl is required to install Rust." say "Installing stable Rust with rustup" curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal export PATH="${CARGO_HOME:-$HOME/.cargo}/bin:$PATH" command -v cargo >/dev/null 2>&1 || fail "Cargo is unavailable after rustup installation." } project_version() { awk ' /^\[package\]/ { package=1; next } /^\[/ && package { exit } package && /^version[[:space:]]*=/ { gsub(/.*=[[:space:]]*"|".*/, "", $0); print; exit } ' "$PROJECT_ROOT/Cargo.toml" } read_env_value() { local key="$1" default_value="${2:-}" value="" if [[ -f "$ENV_FILE" ]]; then value="$(grep -E "^[[:space:]]*${key}=" "$ENV_FILE" | tail -n1 | cut -d= -f2- || true)" value="${value%\"}"; value="${value#\"}" value="${value%\'}"; value="${value#\'}" fi printf '%s' "${value:-$default_value}" } health_url() { local bind port bind="$(read_env_value GREE_CONTROLLER_BIND '0.0.0.0:8787')" port="${bind##*:}" printf 'http://127.0.0.1:%s/api/health' "$port" } database_path() { local db db="$(read_env_value GREE_CONTROLLER_DATABASE "$DATA_DIR/gree-controller.db")" if [[ "$db" != /* ]]; then db="$DATA_DIR/$db" fi printf '%s' "$db" } panel_url() { local bind port ip bind="$(read_env_value GREE_CONTROLLER_BIND '0.0.0.0:8787')" port="${bind##*:}" ip="$(hostname -I 2>/dev/null | awk '{print $1}')" printf 'http://%s:%s' "${ip:-LXC_ADDRESS}" "$port" } wait_for_health() { local url attempts="${1:-60}" url="$(health_url)" for _ in $(seq 1 "$attempts"); do if curl -fsS --max-time 2 "$url" >/dev/null 2>&1; then return 0 fi sleep 0.5 done return 1 } backup_timestamp() { date -u +'%Y%m%dT%H%M%SZ' }