Files
clash-for-linux/scripts/service_lib.sh
2026-03-21 13:58:10 +08:00

159 lines
3.1 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
set -euo pipefail
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
RUNTIME_DIR="$PROJECT_DIR/runtime"
PID_FILE="$RUNTIME_DIR/clash.pid"
STATE_FILE="$RUNTIME_DIR/state.env"
SERVICE_NAME="clash-for-linux.service"
mkdir -p "$RUNTIME_DIR"
# =========================
# 基础能力
# =========================
has_systemd() {
command -v systemctl >/dev/null 2>&1
}
service_unit_exists() {
has_systemd || return 1
systemctl show "$SERVICE_NAME" -p LoadState --value 2>/dev/null | grep -q '^loaded$'
}
read_pid() {
[ -s "$PID_FILE" ] || return 1
tr -d '[:space:]' < "$PID_FILE"
}
is_pid_running() {
local pid="$1"
[ -n "$pid" ] && kill -0 "$pid" 2>/dev/null
}
is_script_running() {
local pid
pid="$(read_pid 2>/dev/null || true)"
is_pid_running "$pid"
}
# =========================
# 清理僵尸 PID关键
# =========================
cleanup_dead_pid() {
local pid
pid="$(read_pid 2>/dev/null || true)"
if [ -n "${pid:-}" ] && ! is_pid_running "$pid"; then
rm -f "$PID_FILE"
fi
}
# =========================
# 模式检测(统一)
# =========================
detect_mode() {
cleanup_dead_pid
if service_unit_exists && systemctl is-active --quiet "$SERVICE_NAME"; then
echo "systemd"
elif is_script_running; then
echo "script"
elif service_unit_exists; then
echo "systemd-installed"
else
echo "none"
fi
}
# =========================
# state 写入(唯一实现)
# =========================
write_state_kv() {
local key="$1"
local value="$2"
mkdir -p "$RUNTIME_DIR"
touch "$STATE_FILE"
if grep -q "^${key}=" "$STATE_FILE" 2>/dev/null; then
sed -i "s|^${key}=.*|${key}=${value}|" "$STATE_FILE"
else
echo "${key}=${value}" >> "$STATE_FILE"
fi
}
write_run_state() {
local status="${1:-unknown}"
local mode="${2:-unknown}"
local pid="${3:-}"
write_state_kv "LAST_RUN_STATUS" "$status"
write_state_kv "LAST_RUN_MODE" "$mode"
write_state_kv "LAST_RUN_AT" "$(date -Iseconds)"
if [ -n "$pid" ]; then
write_state_kv "LAST_RUN_PID" "$pid"
fi
}
# =========================
# systemd 模式
# =========================
start_via_systemd() {
systemctl start "$SERVICE_NAME"
}
stop_via_systemd() {
systemctl stop "$SERVICE_NAME" || true
cleanup_dead_pid
write_run_state "stopped" "systemd"
}
restart_via_systemd() {
systemctl restart "$SERVICE_NAME"
}
# =========================
# script 模式
# =========================
start_via_script() {
cleanup_dead_pid
if is_script_running; then
echo "[INFO] clash already running (script)"
return 0
fi
"$PROJECT_DIR/scripts/run_clash.sh" --daemon
}
stop_via_script() {
local pid
pid="$(read_pid 2>/dev/null || true)"
if [ -n "${pid:-}" ] && is_pid_running "$pid"; then
echo "[INFO] stopping clash pid=$pid"
kill "$pid" 2>/dev/null || true
for _ in 1 2 3 4 5; do
if ! is_pid_running "$pid"; then
break
fi
sleep 1
done
if is_pid_running "$pid"; then
kill -9 "$pid" 2>/dev/null || true
fi
fi
rm -f "$PID_FILE"
write_run_state "stopped" "script"
}
restart_via_script() {
stop_via_script || true
start_via_script
}