mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-07-27 02:11:19 +08:00
🗽 Sync 2026-04-04 08:46:19
This commit is contained in:
parent
cc48a1d6ad
commit
874bea09f4
@ -4,6 +4,20 @@
|
||||
|
||||
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/)。
|
||||
|
||||
## [2.0.3] - 2026-04-03
|
||||
|
||||
### 修复
|
||||
|
||||
- **微信插件安装失败 (exit: 127)**: 当 Gateway 未运行或路径检测失败时,`npx` 命令指向不存在的路径导致安装失败
|
||||
- 根因: `get_actual_install_path()` 依赖 Gateway 进程运行时返回正确路径,Gateway 未启动时返回默认值 `/opt/openclaw`,但实际安装路径可能是 `/mnt/data/openclaw` 等自定义路径
|
||||
- 修复: `action_wechat_install()` 和 `action_wechat_upgrade_plugin()` 新增多层路径校验逻辑:
|
||||
1. 先检查默认检测到的 `npx` 是否存在
|
||||
2. 不存在时回退到 UCI 配置的 `install_path`
|
||||
3. 最后遍历常见备用路径 (`/mnt/data/openclaw`, `/opt/openclaw`, `/overlay/upper/opt/openclaw`)
|
||||
4. 所有路径都无效时返回明确的错误提示,而非模糊的 exit 127
|
||||
|
||||
---
|
||||
|
||||
## [2.0.2] - 2026-03-31
|
||||
|
||||
### 新增功能
|
||||
|
||||
@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-openclaw
|
||||
PKG_VERSION:=$(strip $(shell cat $(CURDIR)/VERSION 2>/dev/null || echo "1.0.0"))
|
||||
PKG_RELEASE:=8
|
||||
PKG_RELEASE:=9
|
||||
|
||||
PKG_MAINTAINER:=10000ge10000 <10000ge10000@users.noreply.github.com>
|
||||
PKG_LICENSE:=GPL-3.0
|
||||
|
||||
@ -1 +1 @@
|
||||
2.0.2
|
||||
2.0.3
|
||||
|
||||
@ -52,62 +52,90 @@ function index()
|
||||
entry({"admin", "services", "openclaw", "wechat_status"}, call("action_wechat_status"), nil).leaf = true
|
||||
|
||||
-- 微信插件安装 API (后台安装)
|
||||
entry({"admin", "services", "openclaw", "wechat_install"}, call("action_wechat_install"), nil).leaf = true
|
||||
entry({"admin", "services", "openclaw", "wechat_install"}, post("action_wechat_install"), nil).leaf = true
|
||||
|
||||
-- 微信安装日志轮询 API
|
||||
entry({"admin", "services", "openclaw", "wechat_install_log"}, call("action_wechat_install_log"), nil).leaf = true
|
||||
|
||||
-- 微信登录 API (启动登录流程)
|
||||
entry({"admin", "services", "openclaw", "wechat_login"}, call("action_wechat_login"), nil).leaf = true
|
||||
entry({"admin", "services", "openclaw", "wechat_login"}, post("action_wechat_login"), nil).leaf = true
|
||||
|
||||
-- 微信登录状态/二维码 API
|
||||
entry({"admin", "services", "openclaw", "wechat_login_status"}, call("action_wechat_login_status"), nil).leaf = true
|
||||
|
||||
-- 微信插件卸载 API
|
||||
entry({"admin", "services", "openclaw", "wechat_uninstall"}, call("action_wechat_uninstall"), nil).leaf = true
|
||||
entry({"admin", "services", "openclaw", "wechat_uninstall"}, post("action_wechat_uninstall"), nil).leaf = true
|
||||
|
||||
-- 微信插件检测升级 API
|
||||
entry({"admin", "services", "openclaw", "wechat_check_upgrade"}, call("action_wechat_check_upgrade"), nil).leaf = true
|
||||
|
||||
-- 微信插件升级 API
|
||||
entry({"admin", "services", "openclaw", "wechat_upgrade_plugin"}, call("action_wechat_upgrade_plugin"), nil).leaf = true
|
||||
entry({"admin", "services", "openclaw", "wechat_upgrade_plugin"}, post("action_wechat_upgrade_plugin"), nil).leaf = true
|
||||
|
||||
-- 微信退出/删除账号 API
|
||||
entry({"admin", "services", "openclaw", "wechat_logout"}, call("action_wechat_logout"), nil).leaf = true
|
||||
entry({"admin", "services", "openclaw", "wechat_logout"}, post("action_wechat_logout"), nil).leaf = true
|
||||
end-- ═══════════════════════════════════════════
|
||||
-- 获取实际安装路径 (辅助函数)
|
||||
-- 获取安装路径 (唯一权威来源: UCI 配置)
|
||||
-- ═══════════════════════════════════════════
|
||||
local function get_actual_install_path()
|
||||
local sys = require "luci.sys"
|
||||
-- 核心原则: 用户在安装时输入的路径是唯一的安装位置
|
||||
-- - UCI install_path 存储用户输入的基础路径 (如 /mnt/data 或 /opt)
|
||||
-- - 实际安装路径为 ${install_path}/openclaw
|
||||
-- - 此函数始终返回 UCI 配置的路径,不做任何"智能"回退
|
||||
-- ═══════════════════════════════════════════
|
||||
local function get_install_path()
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
-- 从 UCI 读取用户配置的基础路径,默认 /opt
|
||||
local base_path = uci:get("openclaw", "main", "install_path") or "/opt"
|
||||
-- 返回完整安装路径
|
||||
return base_path .. "/openclaw"
|
||||
end
|
||||
|
||||
-- 从 UCI 读取用户配置的基础路径
|
||||
local install_path_uci = uci:get("openclaw", "main", "install_path") or "/opt"
|
||||
local uci_install_path = install_path_uci .. "/openclaw"
|
||||
-- 确保网关端口可用:检测占用并尝试优雅停止或强制杀死占用进程
|
||||
local function ensure_port_free(port)
|
||||
local sys = require "luci.sys"
|
||||
if not port or port == "" then return end
|
||||
-- 优先尝试使用 openclaw 自身的 stop 命令(如果已安装)
|
||||
sys.exec("openclaw gateway stop >/dev/null 2>&1 || true")
|
||||
|
||||
-- 方法1: 从运行中的 gateway 进程检测实际路径
|
||||
local actual_path = sys.exec("ps w 2>/dev/null | grep -E 'openclaw.*gateway|openclaw-gateway' | grep -v grep | head -1"):gsub("%s+", "")
|
||||
if actual_path and actual_path ~= "" then
|
||||
local matched_path = actual_path:match("(/[^ ]+)/data/")
|
||||
if matched_path and nixio.fs.stat(matched_path .. "/data/.openclaw/openclaw.json", "type") then
|
||||
return matched_path
|
||||
-- 查询占用端口的行
|
||||
local check_cmd = ""
|
||||
if os.execute("command -v ss >/dev/null 2>&1") == 0 then
|
||||
check_cmd = string.format("ss -tulnp 2>/dev/null | grep -E ':%%s ' || true", port)
|
||||
else
|
||||
check_cmd = string.format("netstat -tulnp 2>/dev/null | grep -E ':%%s ' || true", port)
|
||||
end
|
||||
local out = sys.exec(check_cmd)
|
||||
out = out or ""
|
||||
if out:match("%S") then
|
||||
-- 尝试解析 pid
|
||||
local pid = out:match("pid=(%d+)") or out:match(" (%d+)/") or out:match("/(%d+)")
|
||||
pid = pid and pid:gsub("%s+", "") or nil
|
||||
if pid and pid ~= "" then
|
||||
-- 再次尝试优雅停止
|
||||
sys.exec("openclaw gateway stop >/dev/null 2>&1 || true")
|
||||
-- 发送 SIGTERM
|
||||
sys.exec("kill -TERM " .. pid .. " >/dev/null 2>&1 || true")
|
||||
-- 等待释放,最多等待 5 次(每次 1s)
|
||||
for i = 1,5 do
|
||||
local still = sys.exec(check_cmd) or ""
|
||||
if not still:match("%S") then break end
|
||||
os.execute("sleep 1")
|
||||
end
|
||||
-- 如果仍然存在则强杀
|
||||
local still2 = sys.exec(check_cmd) or ""
|
||||
if still2:match("%S") then
|
||||
sys.exec("kill -9 " .. pid .. " >/dev/null 2>&1 || true")
|
||||
end
|
||||
else
|
||||
-- 未能解析 PID,则尝试批量杀死关键进程名
|
||||
sys.exec("pgrep -f openclaw-gateway 2>/dev/null | xargs -r kill -TERM 2>/dev/null || true")
|
||||
os.execute("sleep 1")
|
||||
local still3 = sys.exec(check_cmd) or ""
|
||||
if still3:match("%S") then
|
||||
sys.exec("pgrep -f openclaw-gateway 2>/dev/null | xargs -r kill -9 2>/dev/null || true")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 方法2: 检查常见安装位置 (优先检查实际存在的配置)
|
||||
local possible_paths = {
|
||||
uci_install_path, -- UCI 配置的路径
|
||||
"/mnt/data/openclaw", -- 常见的外置存储路径
|
||||
"/opt/openclaw", -- 默认路径
|
||||
}
|
||||
for _, p in ipairs(possible_paths) do
|
||||
if nixio.fs.stat(p .. "/data/.openclaw/openclaw.json", "type") then
|
||||
return p
|
||||
end
|
||||
end
|
||||
|
||||
-- 方法3: 如果都没找到,返回 UCI 配置的路径 (即使不存在,安装时会创建)
|
||||
return uci_install_path
|
||||
end
|
||||
|
||||
-- ═══════════════════════════════════════════
|
||||
@ -122,8 +150,8 @@ function action_status()
|
||||
local pty_port = uci:get("openclaw", "main", "pty_port") or "18793"
|
||||
local enabled = uci:get("openclaw", "main", "enabled") or "0"
|
||||
|
||||
-- 使用 get_actual_install_path 获取实际安装路径
|
||||
local install_path = get_actual_install_path()
|
||||
-- 使用 get_install_path 获取安装路径 (唯一来源: UCI 配置)
|
||||
local install_path = get_install_path()
|
||||
|
||||
-- 验证端口值为纯数字,防止命令注入
|
||||
if not port:match("^%d+$") then port = "18789" end
|
||||
@ -467,8 +495,19 @@ function action_uninstall()
|
||||
-- 实际安装路径
|
||||
local install_path = install_path_uci .. "/openclaw"
|
||||
|
||||
-- 停止服务
|
||||
-- 1. 停止服务 (通过 init.d 正常流程)
|
||||
sys.exec("/etc/init.d/openclaw stop >/dev/null 2>&1")
|
||||
|
||||
-- 2. 获取配置端口,确保在清理前端口对应的进程都被杀掉
|
||||
local port = uci:get("openclaw", "main", "port") or "18789"
|
||||
local pty_port = uci:get("openclaw", "main", "pty_port") or "18793"
|
||||
|
||||
-- 3. 终极无感化清理僵尸进程
|
||||
sys.exec("for p in " .. port .. " " .. pty_port .. "; do pid=$(netstat -tulnp 2>/dev/null | grep \":$p \" | awk '{print $7}' | cut -d'/' -f1); [ -n \"$pid\" ] && kill -9 \"$pid\" 2>/dev/null; done")
|
||||
sys.exec("ss -tulnp 2>/dev/null | awk '/:" .. port .. " |:" .. pty_port .. " /{print $NF}' | awk -F',' '{print $2}' | awk -F'=' '{print $2}' | xargs -r kill -9 2>/dev/null")
|
||||
sys.exec("pgrep -f 'openclaw-gateway|web-pty.js' 2>/dev/null | xargs -r kill -9 2>/dev/null")
|
||||
sys.exec("pgrep -u openclaw 2>/dev/null | xargs -r kill -9 2>/dev/null")
|
||||
|
||||
-- 禁用开机启动
|
||||
sys.exec("/etc/init.d/openclaw disable 2>/dev/null")
|
||||
-- 设置 UCI enabled=0
|
||||
@ -1028,32 +1067,8 @@ function action_wechat_status()
|
||||
local sys = require "luci.sys"
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
|
||||
-- 获取安装路径 (优先从运行环境检测)
|
||||
local install_path_uci = uci:get("openclaw", "main", "install_path") or "/opt"
|
||||
local install_path = install_path_uci .. "/openclaw"
|
||||
|
||||
-- 检测实际运行的安装路径 (通过查找 gateway 进程)
|
||||
local actual_path = sys.exec("ps w 2>/dev/null | grep -E 'openclaw.*gateway|openclaw-gateway' | grep -v grep | head -1"):gsub("%s+", "")
|
||||
if actual_path and actual_path ~= "" then
|
||||
-- 从进程命令行提取路径
|
||||
local matched_path = actual_path:match("(/[^ ]+)/data/")
|
||||
if matched_path and nixio.fs.stat(matched_path, "type") then
|
||||
install_path = matched_path
|
||||
end
|
||||
end
|
||||
|
||||
-- 也检查常见安装位置
|
||||
local possible_paths = {
|
||||
install_path,
|
||||
"/mnt/data/openclaw",
|
||||
"/opt/openclaw",
|
||||
}
|
||||
for _, p in ipairs(possible_paths) do
|
||||
if nixio.fs.stat(p .. "/data/.openclaw/openclaw.json", "type") then
|
||||
install_path = p
|
||||
break
|
||||
end
|
||||
end
|
||||
-- 使用统一的路径获取函数 (唯一来源: UCI 配置)
|
||||
local install_path = get_install_path()
|
||||
|
||||
local result = {
|
||||
plugin_installed = false,
|
||||
@ -1135,8 +1150,10 @@ end
|
||||
function action_wechat_install()
|
||||
local http = require "luci.http"
|
||||
local sys = require "luci.sys"
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
|
||||
local install_path = get_actual_install_path()
|
||||
-- 使用统一的路径获取函数 (唯一来源: UCI 配置)
|
||||
local install_path = get_install_path()
|
||||
local node_bin = install_path .. "/node/bin/node"
|
||||
local npx_bin = install_path .. "/node/bin/npx"
|
||||
local oc_data = install_path .. "/data"
|
||||
@ -1144,11 +1161,40 @@ function action_wechat_install()
|
||||
-- 清理旧日志和状态
|
||||
sys.exec("rm -f /tmp/openclaw-wechat-install.log /tmp/openclaw-wechat-install.pid /tmp/openclaw-wechat-install.exit")
|
||||
|
||||
-- 后台执行安装
|
||||
-- 校验: 确保 npx 存在 (运行环境已安装)
|
||||
if not nixio.fs.stat(npx_bin, "type") then
|
||||
-- npx 不存在,运行环境未安装或路径配置错误
|
||||
local log_content = "开始安装微信插件...\n" ..
|
||||
"安装路径: " .. install_path .. "\n" ..
|
||||
"❌ 错误: npx 命令不存在 (" .. npx_bin .. ")\n" ..
|
||||
"请先在「基本设置」页面安装运行环境。\n" ..
|
||||
"UCI install_path=" .. (uci:get("openclaw", "main", "install_path") or "未设置")
|
||||
local f = io.open("/tmp/openclaw-wechat-install.log", "w")
|
||||
if f then
|
||||
f:write(log_content)
|
||||
f:close()
|
||||
end
|
||||
local ef = io.open("/tmp/openclaw-wechat-install.exit", "w")
|
||||
if ef then
|
||||
ef:write("127")
|
||||
ef:close()
|
||||
end
|
||||
http.prepare_content("application/json")
|
||||
http.write_json({ status = "ok", message = "微信插件安装已在后台启动..." })
|
||||
return
|
||||
end
|
||||
|
||||
-- 后台执行安装
|
||||
-- 在启动安装前,确保网关端口可用(自动清理残留 gateway 进程)
|
||||
local port = uci:get("openclaw", "main", "port") or "18789"
|
||||
ensure_port_free(port)
|
||||
local install_cmd = string.format(
|
||||
"( " ..
|
||||
"echo '开始安装微信插件...' > /tmp/openclaw-wechat-install.log; " ..
|
||||
"echo '安装路径: %s' >> /tmp/openclaw-wechat-install.log; " ..
|
||||
"echo 'npx 路径: %s' >> /tmp/openclaw-wechat-install.log; " ..
|
||||
-- 修复 npm 缓存目录权限 (避免 root 创建的缓存导致 openclaw 用户写入失败)
|
||||
"chown -R openclaw:openclaw %s/.npm 2>/dev/null; " ..
|
||||
"cd %s && " ..
|
||||
"su -s /bin/sh openclaw -c 'HOME=%s OPENCLAW_HOME=%s OPENCLAW_STATE_DIR=%s/.openclaw " ..
|
||||
"PATH=%s/node/bin:%s/global/bin:$PATH " ..
|
||||
@ -1157,7 +1203,7 @@ function action_wechat_install()
|
||||
"if [ $RC -eq 0 ]; then echo '✅ 微信插件安装成功!' >> /tmp/openclaw-wechat-install.log; " ..
|
||||
"else echo '❌ 安装失败 (exit: '$RC')' >> /tmp/openclaw-wechat-install.log; fi " ..
|
||||
") & echo $! > /tmp/openclaw-wechat-install.pid",
|
||||
install_path, oc_data, oc_data, oc_data, oc_data, install_path, install_path, npx_bin
|
||||
install_path, npx_bin, oc_data, install_path, oc_data, oc_data, oc_data, install_path, install_path, npx_bin
|
||||
) sys.exec(install_cmd)
|
||||
|
||||
http.prepare_content("application/json")
|
||||
@ -1225,7 +1271,7 @@ function action_wechat_login()
|
||||
local http = require "luci.http"
|
||||
local sys = require "luci.sys"
|
||||
|
||||
local install_path = get_actual_install_path()
|
||||
local install_path = get_install_path()
|
||||
local node_bin = install_path .. "/node/bin/node"
|
||||
local oc_data = install_path .. "/data"
|
||||
local oc_entry = ""
|
||||
@ -1353,13 +1399,10 @@ function action_wechat_uninstall()
|
||||
local http = require "luci.http"
|
||||
local sys = require "luci.sys"
|
||||
|
||||
local install_path = get_actual_install_path()
|
||||
local install_path = get_install_path()
|
||||
|
||||
-- 删除微信插件目录
|
||||
local wechat_ext_dir = install_path .. "/data/.openclaw/extensions/openclaw-weixin"
|
||||
if nixio.fs.stat(wechat_ext_dir, "type") then
|
||||
sys.exec("rm -rf " .. wechat_ext_dir)
|
||||
end
|
||||
|
||||
-- 从配置中删除微信相关配置
|
||||
local config_file = install_path .. "/data/.openclaw/openclaw.json"
|
||||
@ -1398,7 +1441,7 @@ function action_wechat_check_upgrade()
|
||||
local http = require "luci.http"
|
||||
local sys = require "luci.sys"
|
||||
|
||||
local install_path = get_actual_install_path()
|
||||
local install_path = get_install_path()
|
||||
local npx_bin = install_path .. "/node/bin/npx"
|
||||
local oc_data = install_path .. "/data"
|
||||
|
||||
@ -1445,19 +1488,51 @@ end
|
||||
function action_wechat_upgrade_plugin()
|
||||
local http = require "luci.http"
|
||||
local sys = require "luci.sys"
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
|
||||
local install_path = get_actual_install_path()
|
||||
-- 使用统一的路径获取函数 (唯一来源: UCI 配置)
|
||||
local install_path = get_install_path()
|
||||
local node_bin = install_path .. "/node/bin/node"
|
||||
local npx_bin = install_path .. "/node/bin/npx"
|
||||
local oc_data = install_path .. "/data"
|
||||
|
||||
-- 清理旧日志和状态
|
||||
sys.exec("rm -f /tmp/openclaw-wechat-install.log /tmp/openclaw-wechat-install.pid /tmp/openclaw-wechat-install.exit")
|
||||
|
||||
-- 校验: 确保 npx 存在 (运行环境已安装)
|
||||
if not nixio.fs.stat(npx_bin, "type") then
|
||||
local log_content = "正在升级微信插件...\n" ..
|
||||
"安装路径: " .. install_path .. "\n" ..
|
||||
"❌ 错误: npx 命令不存在 (" .. npx_bin .. ")\n" ..
|
||||
"请先检查运行环境是否正常安装。\n" ..
|
||||
"UCI install_path=" .. (uci:get("openclaw", "main", "install_path") or "未设置")
|
||||
local f = io.open("/tmp/openclaw-wechat-install.log", "w")
|
||||
if f then
|
||||
f:write(log_content)
|
||||
f:close()
|
||||
end
|
||||
local ef = io.open("/tmp/openclaw-wechat-install.exit", "w")
|
||||
if ef then
|
||||
ef:write("127")
|
||||
ef:close()
|
||||
end
|
||||
http.prepare_content("application/json")
|
||||
http.write_json({ status = "ok", message = "微信插件升级已在后台启动..." })
|
||||
return
|
||||
end
|
||||
|
||||
-- 后台执行升级 (其实就是重新安装最新版)
|
||||
local upgrade_cmd = string.format(
|
||||
-- 在启动升级前,确保网关端口可用(自动清理残留 gateway 进程)
|
||||
local port = uci:get("openclaw", "main", "port") or "18789"
|
||||
ensure_port_free(port)
|
||||
|
||||
local upgrade_cmd = string.format(
|
||||
"( " ..
|
||||
"echo '正在升级微信插件...' > /tmp/openclaw-wechat-install.log; " ..
|
||||
"echo '安装路径: %s' >> /tmp/openclaw-wechat-install.log; " ..
|
||||
"echo 'npx 路径: %s' >> /tmp/openclaw-wechat-install.log; " ..
|
||||
-- 修复 npm 缓存目录权限 (避免 root 创建的缓存导致 openclaw 用户写入失败)
|
||||
"chown -R openclaw:openclaw %s/.npm 2>/dev/null; " ..
|
||||
"cd %s && " ..
|
||||
"su -s /bin/sh openclaw -c 'HOME=%s OPENCLAW_HOME=%s OPENCLAW_STATE_DIR=%s/.openclaw " ..
|
||||
"PATH=%s/node/bin:%s/global/bin:$PATH " ..
|
||||
@ -1466,7 +1541,7 @@ function action_wechat_upgrade_plugin()
|
||||
"if [ $RC -eq 0 ]; then echo '✅ 微信插件升级成功!' >> /tmp/openclaw-wechat-install.log; " ..
|
||||
"else echo '❌ 升级失败 (exit: '$RC')' >> /tmp/openclaw-wechat-install.log; fi " ..
|
||||
") & echo $! > /tmp/openclaw-wechat-install.pid",
|
||||
install_path, oc_data, oc_data, oc_data, oc_data, install_path, install_path, npx_bin
|
||||
install_path, npx_bin, oc_data, install_path, oc_data, oc_data, oc_data, install_path, install_path, npx_bin
|
||||
) sys.exec(upgrade_cmd)
|
||||
|
||||
http.prepare_content("application/json")
|
||||
@ -1487,7 +1562,7 @@ function action_wechat_logout()
|
||||
return
|
||||
end
|
||||
|
||||
local install_path = get_actual_install_path()
|
||||
local install_path = get_install_path()
|
||||
local node_bin = install_path .. "/node/bin/node"
|
||||
local oc_data = install_path .. "/data"
|
||||
local oc_entry = ""
|
||||
|
||||
@ -412,6 +412,7 @@ local pty_port = uci:get("openclaw", "main", "pty_port") or "18793"
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
(function() {
|
||||
var csrfToken = '<%=token%>';
|
||||
var statusUrl = '<%=luci.dispatcher.build_url("admin", "services", "openclaw", "status_api")%>';
|
||||
var wechatStatusUrl = '<%=luci.dispatcher.build_url("admin", "services", "openclaw", "wechat_status")%>';
|
||||
var wechatInstallUrl = '<%=luci.dispatcher.build_url("admin", "services", "openclaw", "wechat_install")%>';
|
||||
@ -522,7 +523,7 @@ local pty_port = uci:get("openclaw", "main", "pty_port") or "18793"
|
||||
document.getElementById('oc-install-log').textContent = '正在启动安装...\n';
|
||||
|
||||
// 启动安装
|
||||
(new XHR()).post(wechatInstallUrl, null, function(x) {
|
||||
(new XHR()).post(wechatInstallUrl, { token: csrfToken }, function(x) {
|
||||
try {
|
||||
var d = JSON.parse(x.responseText);
|
||||
if (d.status === 'ok') {
|
||||
@ -632,7 +633,7 @@ local pty_port = uci:get("openclaw", "main", "pty_port") or "18793"
|
||||
document.getElementById('oc-login-result').style.display = 'none';
|
||||
|
||||
// 启动登录流程
|
||||
(new XHR()).post(wechatLoginUrl, null, function(x) {
|
||||
(new XHR()).post(wechatLoginUrl, { token: csrfToken }, function(x) {
|
||||
try {
|
||||
var d = JSON.parse(x.responseText);
|
||||
if (d.status === 'ok') {
|
||||
@ -653,7 +654,7 @@ local pty_port = uci:get("openclaw", "main", "pty_port") or "18793"
|
||||
btn.textContent = '退出中...';
|
||||
btn.disabled = true;
|
||||
|
||||
(new XHR()).post(wechatLogoutUrl + '?account=' + encodeURIComponent(accountId), null, function(x) {
|
||||
(new XHR()).post(wechatLogoutUrl + '?account=' + encodeURIComponent(accountId), { token: csrfToken }, function(x) {
|
||||
btn.textContent = oldText;
|
||||
btn.disabled = false;
|
||||
ocRefreshWechatStatus();
|
||||
@ -833,7 +834,7 @@ local pty_port = uci:get("openclaw", "main", "pty_port") or "18793"
|
||||
|
||||
var upgradeUrl = '<%=luci.dispatcher.build_url("admin", "services", "openclaw", "wechat_upgrade_plugin")%>';
|
||||
|
||||
(new XHR()).post(upgradeUrl, null, function(x) {
|
||||
(new XHR()).post(upgradeUrl, { token: csrfToken }, function(x) {
|
||||
try {
|
||||
var d = JSON.parse(x.responseText);
|
||||
if (d.status === 'ok') {
|
||||
@ -905,7 +906,7 @@ local pty_port = uci:get("openclaw", "main", "pty_port") or "18793"
|
||||
btn.disabled = true;
|
||||
btn.textContent = '⏳ 卸载中...';
|
||||
|
||||
(new XHR()).post('<%=luci.dispatcher.build_url("admin", "services", "openclaw", "wechat_uninstall")%>', null, function(x) {
|
||||
(new XHR()).post('<%=luci.dispatcher.build_url("admin", "services", "openclaw", "wechat_uninstall")%>', { token: csrfToken }, function(x) {
|
||||
try {
|
||||
var d = JSON.parse(x.responseText);
|
||||
if (d.status === 'ok') {
|
||||
|
||||
@ -297,7 +297,7 @@ _ensure_port_free() {
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
port_pid=$(ss -tulnp 2>/dev/null | grep ":${p} " | sed -n 's/.*pid=\([0-9]*\).*/\1/p' | head -1)
|
||||
else
|
||||
port_pid=$(netstat -tulnp 2>/dev/null | grep ":${p} " | sed -n 's|.* \([0-9]*\)/.*|\1|p' | head -1)
|
||||
port_pid=$(netstat -tulnp 2>/dev/null | grep ":${p} " | awk '{print $7}' | cut -d'/' -f1 | grep -E '^[0-9]+$' | head -n 1)
|
||||
fi
|
||||
[ -n "$port_pid" ] && kill -9 "$port_pid" 2>/dev/null && usleep 300000 2>/dev/null
|
||||
return 0
|
||||
@ -392,17 +392,36 @@ done
|
||||
|
||||
# 4) 如果端口仍被占用,强制 SIGKILL
|
||||
if [ $wait_count -ge $max_wait ]; then
|
||||
local port_pid=""
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
port_pid=$(ss -tulnp 2>/dev/null | grep ":${port} " | sed -n 's/.*pid=\([0-9]*\).*/\1/p' | head -1)
|
||||
else
|
||||
port_pid=$(netstat -tulnp 2>/dev/null | grep ":${port} " | sed -n 's|.* \([0-9]*\)/.*|\1|p' | head -1)
|
||||
fi
|
||||
if [ -n "$port_pid" ]; then
|
||||
kill -9 "$port_pid" 2>/dev/null
|
||||
# 等待内核回收 (缩短到 0.5 秒)
|
||||
usleep 500000 2>/dev/null || sleep 0.5
|
||||
fi
|
||||
local port_pid=""
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
port_pid=$(ss -tulnp 2>/dev/null | grep ":${port} " | sed -n 's/.*pid=\([0-9]*\).*/\1/p' | head -1)
|
||||
else
|
||||
port_pid=$(netstat -tulnp 2>/dev/null | grep ":${port} " | awk '{print $7}' | cut -d'/' -f1 | grep -E '^[0-9]+$' | head -n 1)
|
||||
fi
|
||||
if [ -n "$port_pid" ]; then
|
||||
kill -9 "$port_pid" 2>/dev/null
|
||||
# 等待内核回收 (缩短到 0.5 秒)
|
||||
usleep 500000 2>/dev/null || sleep 0.5
|
||||
fi
|
||||
fi
|
||||
|
||||
# 5) 终极保险:使用暴力匹配端口杀死该名下任何相关占用进程
|
||||
local _pty_port=$(uci -q get openclaw.main.pty_port || echo "18793")
|
||||
for _p in "$port" "$_pty_port"; do
|
||||
local _spid=""
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
_spid=$(ss -tulnp 2>/dev/null | grep ":${_p} " | sed -n 's/.*pid=\([0-9]*\).*/\1/p' | head -1)
|
||||
else
|
||||
_spid=$(netstat -tulnp 2>/dev/null | grep ":${_p} " | awk '{print $7}' | cut -d'/' -f1 | grep -E '^[0-9]+$' | head -n 1)
|
||||
fi
|
||||
[ -n "$_spid" ] && kill -9 "$_spid" 2>/dev/null || true
|
||||
done
|
||||
|
||||
# 6) 清理该特定系统用户下任何悬挂或离群孤儿进程
|
||||
if getent passwd openclaw >/dev/null 2>&1 || grep -q '^openclaw:' /etc/passwd 2>/dev/null; then
|
||||
for _opcup in $(pgrep -u openclaw 2>/dev/null); do
|
||||
kill -9 "$_opcup" 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@ -999,13 +999,14 @@ add_firewall_rule() {
|
||||
$ipt_m -N PSW_RULE
|
||||
$ipt_m -A PSW_RULE -j CONNMARK --restore-mark
|
||||
$ipt_m -A PSW_RULE -m mark --mark ${FWMARK} -j RETURN
|
||||
$ipt_m -A PSW_RULE -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j MARK --set-xmark ${FWMARK}
|
||||
$ipt_m -A PSW_RULE -p udp -m conntrack --ctstate NEW -j MARK --set-xmark ${FWMARK}
|
||||
$ipt_m -A PSW_RULE -p tcp -m tcp --syn -j MARK --set-xmark ${FWMARK}
|
||||
$ipt_m -A PSW_RULE -p udp -m conntrack --ctstate NEW,RELATED -j MARK --set-xmark ${FWMARK}
|
||||
$ipt_m -A PSW_RULE -j CONNMARK --save-mark
|
||||
|
||||
$ipt_m -N PSW
|
||||
$ipt_m -A PSW $(dst $IPSET_LAN) -j RETURN
|
||||
$ipt_m -A PSW $(dst $IPSET_VPS) -j RETURN
|
||||
$ipt_m -A PSW -m conntrack --ctdir REPLY -j RETURN
|
||||
|
||||
[ ! -z "${WAN_IP}" ] && {
|
||||
ipset -F $IPSET_WAN
|
||||
@ -1024,7 +1025,6 @@ add_firewall_rule() {
|
||||
$ipt_m -N PSW_OUTPUT
|
||||
$ipt_m -A PSW_OUTPUT $(dst $IPSET_LAN) -j RETURN
|
||||
$ipt_m -A PSW_OUTPUT $(dst $IPSET_VPS) -j RETURN
|
||||
|
||||
[ -n "$IPT_APPEND_DNS" ] && {
|
||||
local local_dns dns_address dns_port
|
||||
for local_dns in $(echo $IPT_APPEND_DNS | tr ',' ' '); do
|
||||
@ -1044,6 +1044,7 @@ add_firewall_rule() {
|
||||
|
||||
[ "${USE_BLOCK_LIST}" = "1" ] && $ipt_m -A PSW_OUTPUT $(dst $IPSET_BLOCK) -j DROP
|
||||
[ "${USE_DIRECT_LIST}" = "1" ] && $ipt_m -A PSW_OUTPUT $(dst $IPSET_WHITE) -j RETURN
|
||||
$ipt_m -A PSW_OUTPUT -m conntrack --ctdir REPLY -j RETURN
|
||||
$ipt_m -A PSW_OUTPUT -m mark --mark 255 -j RETURN
|
||||
|
||||
ip rule add fwmark ${FWMARK} lookup 999 priority 999
|
||||
@ -1077,13 +1078,14 @@ add_firewall_rule() {
|
||||
$ip6t_m -N PSW_RULE
|
||||
$ip6t_m -A PSW_RULE -j CONNMARK --restore-mark
|
||||
$ip6t_m -A PSW_RULE -m mark --mark ${FWMARK} -j RETURN
|
||||
$ip6t_m -A PSW_RULE -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j MARK --set-xmark ${FWMARK}
|
||||
$ip6t_m -A PSW_RULE -p udp -m conntrack --ctstate NEW -j MARK --set-xmark ${FWMARK}
|
||||
$ip6t_m -A PSW_RULE -p tcp -m tcp --syn -j MARK --set-xmark ${FWMARK}
|
||||
$ip6t_m -A PSW_RULE -p udp -m conntrack --ctstate NEW,RELATED -j MARK --set-xmark ${FWMARK}
|
||||
$ip6t_m -A PSW_RULE -j CONNMARK --save-mark
|
||||
|
||||
$ip6t_m -N PSW
|
||||
$ip6t_m -A PSW $(dst $IPSET_LAN6) -j RETURN
|
||||
$ip6t_m -A PSW $(dst $IPSET_VPS6) -j RETURN
|
||||
$ip6t_m -A PSW -m conntrack --ctdir REPLY -j RETURN
|
||||
|
||||
WAN6_IP=$(get_wan_ips ip6)
|
||||
[ ! -z "${WAN6_IP}" ] && {
|
||||
@ -1106,6 +1108,7 @@ add_firewall_rule() {
|
||||
$ip6t_m -A PSW_OUTPUT $(dst $IPSET_VPS6) -j RETURN
|
||||
[ "${USE_BLOCK_LIST}" = "1" ] && $ip6t_m -A PSW_OUTPUT $(dst $IPSET_BLOCK6) -j DROP
|
||||
[ "${USE_DIRECT_LIST}" = "1" ] && $ip6t_m -A PSW_OUTPUT $(dst $IPSET_WHITE6) -j RETURN
|
||||
$ip6t_m -A PSW_OUTPUT -m conntrack --ctdir REPLY -j RETURN
|
||||
|
||||
ip -6 rule add fwmark ${FWMARK} table 999 priority 999
|
||||
ip -6 route add local ::/0 dev lo table 999
|
||||
|
||||
@ -1037,14 +1037,15 @@ add_firewall_rule() {
|
||||
nft "flush chain $NFTABLE_NAME PSW_MANGLE"
|
||||
nft "add rule $NFTABLE_NAME PSW_MANGLE ip daddr @$NFTSET_LAN counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW_MANGLE ip daddr @$NFTSET_VPS counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW_MANGLE ct direction reply counter return"
|
||||
|
||||
nft "add chain $NFTABLE_NAME PSW_OUTPUT_MANGLE"
|
||||
nft "flush chain $NFTABLE_NAME PSW_OUTPUT_MANGLE"
|
||||
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_LAN counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_VPS counter return"
|
||||
|
||||
[ "${USE_BLOCK_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_BLOCK counter drop"
|
||||
[ "${USE_DIRECT_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_WHITE counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ct direction reply counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE meta mark 255 counter return"
|
||||
|
||||
# jump chains
|
||||
@ -1105,6 +1106,7 @@ add_firewall_rule() {
|
||||
nft "flush chain $NFTABLE_NAME PSW_MANGLE_V6"
|
||||
nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ip6 daddr @$NFTSET_LAN6 counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ip6 daddr @$NFTSET_VPS6 counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ct direction reply counter return"
|
||||
|
||||
nft "add chain $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6"
|
||||
nft "flush chain $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6"
|
||||
@ -1112,6 +1114,7 @@ add_firewall_rule() {
|
||||
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_VPS6 counter return"
|
||||
[ "${USE_BLOCK_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_BLOCK6 counter drop"
|
||||
[ "${USE_DIRECT_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_WHITE6 counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ct direction reply counter return"
|
||||
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 meta mark 255 counter return"
|
||||
|
||||
[ -n "$IPT_APPEND_DNS" ] && {
|
||||
|
||||
@ -744,7 +744,7 @@ add_firewall_rule() {
|
||||
}
|
||||
$ipt_m -A PSW2_OUTPUT -m mark --mark 255 -j RETURN
|
||||
|
||||
ip rule add fwmark ${FWMARK} lookup 999 priority 999
|
||||
ip rule add fwmark ${FWMARK} table 999 priority 999
|
||||
ip route add local 0.0.0.0/0 dev lo table 999
|
||||
|
||||
[ "$accept_icmpv6" = "1" ] && {
|
||||
@ -953,10 +953,10 @@ del_firewall_rule() {
|
||||
done
|
||||
done
|
||||
|
||||
ip rule del fwmark ${FWMARK} lookup 999 priority 999 2>/dev/null
|
||||
ip rule del fwmark ${FWMARK} 2>/dev/null
|
||||
ip route del local 0.0.0.0/0 dev lo table 999 2>/dev/null
|
||||
|
||||
ip -6 rule del fwmark ${FWMARK} table 999 priority 999 2>/dev/null
|
||||
ip -6 rule del fwmark ${FWMARK} 2>/dev/null
|
||||
ip -6 route del local ::/0 dev lo table 999 2>/dev/null
|
||||
|
||||
log_i18n 0 "Delete %s rules is complete." "iptables"
|
||||
|
||||
@ -642,9 +642,35 @@ filter_direct_node_list() {
|
||||
done
|
||||
}
|
||||
|
||||
del_script_mwan3() {
|
||||
[ -s "/etc/init.d/mwan3" ] && sed -i "/${CONFIG}/d" /etc/init.d/mwan3 >/dev/null 2>&1
|
||||
}
|
||||
|
||||
add_script_mwan3() {
|
||||
del_script_mwan3
|
||||
[ -s "/etc/init.d/mwan3" ] && {
|
||||
sed -i '/start_service()/,/}/ s/^}/ \/usr\/share\/passwall2\/nftables.sh mwan3_start\n}/' /etc/init.d/mwan3
|
||||
sed -i '/stop_service().*{/a \ \/usr\/share\/passwall2\/nftables.sh mwan3_stop' /etc/init.d/mwan3
|
||||
}
|
||||
}
|
||||
|
||||
mwan3_stop() {
|
||||
local handles=$(nft -a list chain ip mangle mwan3_hook 2>/dev/null | grep "${FWMARK}" | awk -F '# handle ' '{print$2}')
|
||||
for handle in $handles; do
|
||||
nft delete rule ip mangle mwan3_hook handle ${handle} 2>/dev/null
|
||||
done
|
||||
}
|
||||
|
||||
mwan3_start() {
|
||||
mwan3_stop
|
||||
nft list chain ip mangle mwan3_hook >/dev/null 2>&1 && nft insert rule ip mangle mwan3_hook ct mark ${FWMARK} counter return >/dev/null 2>&1
|
||||
}
|
||||
|
||||
add_firewall_rule() {
|
||||
log_i18n 0 "Starting to load %s firewall rules..." "nftables"
|
||||
gen_nft_tables
|
||||
add_script_mwan3
|
||||
mwan3_start
|
||||
gen_nftset $NFTSET_WAN ipv4_addr 0 "-1"
|
||||
gen_nftset $NFTSET_LOCAL ipv4_addr 0 "-1"
|
||||
gen_nftset $NFTSET_LAN ipv4_addr 0 "-1" $(gen_lanlist)
|
||||
@ -798,7 +824,7 @@ add_firewall_rule() {
|
||||
}
|
||||
unset WAN_IP
|
||||
|
||||
ip rule add fwmark ${FWMARK} lookup 999 priority 999
|
||||
ip rule add fwmark ${FWMARK} table 999 priority 999
|
||||
ip route add local 0.0.0.0/0 dev lo table 999
|
||||
|
||||
#ipv6 tproxy mode and udp
|
||||
@ -974,10 +1000,10 @@ del_firewall_rule() {
|
||||
# Need to be removed at the end, otherwise it will show "Resource busy"
|
||||
nft delete chain $NFTABLE_NAME handle $(nft -a list chains | grep -E "PSW2_RULE" | awk -F '# handle ' '{print$2}') 2>/dev/null
|
||||
|
||||
ip rule del fwmark ${FWMARK} lookup 999 priority 999 2>/dev/null
|
||||
ip rule del fwmark ${FWMARK} 2>/dev/null
|
||||
ip route del local 0.0.0.0/0 dev lo table 999 2>/dev/null
|
||||
|
||||
ip -6 rule del fwmark ${FWMARK} table 999 priority 999 2>/dev/null
|
||||
ip -6 rule del fwmark ${FWMARK} 2>/dev/null
|
||||
ip -6 route del local ::/0 dev lo table 999 2>/dev/null
|
||||
|
||||
destroy_nftset $NFTSET_LOCAL
|
||||
@ -990,6 +1016,8 @@ del_firewall_rule() {
|
||||
destroy_nftset $NFTSET_LAN6
|
||||
destroy_nftset $NFTSET_VPS6
|
||||
|
||||
del_script_mwan3
|
||||
|
||||
log_i18n 0 "Delete %s rules is complete." "nftables"
|
||||
}
|
||||
|
||||
@ -1071,6 +1099,12 @@ insert_nftset)
|
||||
filter_direct_node_list)
|
||||
filter_direct_node_list
|
||||
;;
|
||||
mwan3_start)
|
||||
mwan3_start
|
||||
;;
|
||||
mwan3_stop)
|
||||
mwan3_stop
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
@ -1079,3 +1113,7 @@ start)
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
reload_service() {
|
||||
restart
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user