From da603652143f62c11982cafe4faf7906a4954eb4 Mon Sep 17 00:00:00 2001 From: ericwyuan Date: Sun, 13 Sep 2026 08:35:36 +0800 Subject: [PATCH] =?UTF-8?q?feat(fam-notifier):=20=E8=A1=A5=E5=BC=80?= =?UTF-8?q?=E6=9C=BA=E8=87=AA=E5=90=AF=E8=84=9A=E6=9C=AC=EF=BC=8CNAS=20?= =?UTF-8?q?=E9=87=8D=E5=90=AF=E5=90=8E=E6=8E=A8=E9=80=81=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E9=9D=99=E9=BB=98=E6=96=AD=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NAS 上没有 systemd,rc.d 是唯一的守护手段。旁边 frpc / nas-monitor / comic-api 都有 S99 脚本,唯独这个推送进程没有——它一旦随重启消失,运动事件就悄无声息地 断流,而且不打开网站根本发现不了。2026-09-04 到 09-12 断档整整十天就是这个剧本 (当时它还在 fam-core 里,fam-core 挂了没人重启)。 - 照抄 S99nas-monitor.sh 的写法:等 volume1 挂载就绪(最多 90s)、pidfile 判重 - 以 ericwyuan 而非 root 运行,保持 logs/ 与 data/cursor.json 属主跟手动启动一致 - DSM 上没有 pgrep,用 grep 字符类找 pid - su 自身的 stdio 也断开:否则通过 SSH 执行时命令跑完了会话却不退出(实测踩到) 已装到 NAS 的 /usr/local/etc/rc.d/ 并验证 start/stop/restart/status; restart 后游标从本地文件正确读回(33081),没有被重置成 SS 当前最大 id。 Co-Authored-By: Claude Opus 5 --- fam-notifier/scripts/S99fam-notifier.sh | 72 +++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100755 fam-notifier/scripts/S99fam-notifier.sh diff --git a/fam-notifier/scripts/S99fam-notifier.sh b/fam-notifier/scripts/S99fam-notifier.sh new file mode 100755 index 0000000..41f7a44 --- /dev/null +++ b/fam-notifier/scripts/S99fam-notifier.sh @@ -0,0 +1,72 @@ +#!/bin/sh +# fam-notifier 开机自启(DSM 没有 systemd,/usr/local/etc/rc.d/ 是唯一的守护手段) +# +# 部署:sudo cp 到 /usr/local/etc/rc.d/S99fam-notifier.sh && sudo chmod 755 同路径 +# +# 为什么非有不可:这个进程是摄像头系统在 NAS 上唯一保留的东西(轮询 +# Surveillance Station,把运动事件单向推给甲骨文)。它没起来的话事件就悄无声息 +# 地断流——2026-09-04 到 09-12 断档整整十天,就是因为当时它还在 fam-core 里、 +# fam-core 挂了没人重启,而且不打开网站根本发现不了。 +# +# 以 ericwyuan 而不是 root 运行:保持 logs/ 和 data/cursor.json 的属主跟手动启动 +# 时一致,免得 root 建出来的文件之后普通用户改不动。 +RUN_USER=ericwyuan +APP_DIR=/volume1/web/sentinel-home-ai/fam-notifier +START="$APP_DIR/scripts/start_notifier.sh" +LOG="$APP_DIR/logs/start.log" +PIDFILE="$APP_DIR/fam-notifier.pid" + +# DSM 上没有 pgrep,用 grep 字符类找 pid([f] 写法避免匹配到 grep 自己) +find_pid() { + ps aux | grep "[f]am_notifier" | awk '{print $2}' | head -1 +} + +start() { + RUNNING=$(find_pid) + if [ -n "$RUNNING" ]; then + echo "fam-notifier 已在运行 (PID $RUNNING)"; echo "$RUNNING" > "$PIDFILE"; return 0 + fi + # 等待数据卷 volume1 挂载就绪(最多 90 秒),避免开机时脚本早于卷挂载而静默失败 + n=0 + while [ ! -f "$START" ] && [ $n -lt 90 ]; do + sleep 1; n=$((n+1)) + done + if [ ! -f "$START" ]; then + echo "等待 $START 超时(数据卷可能未挂载),启动放弃"; return 1 + fi + # su 自身的 stdio 也要断开:否则通过 SSH 执行本脚本时,子进程继承了连接的管道, + # 命令跑完了 SSH 会话却迟迟不退出(开机时无所谓,手动敲的时候很烦) + su "$RUN_USER" -c "cd '$APP_DIR' && setsid nohup sh scripts/start_notifier.sh >> '$LOG' 2>&1 < /dev/null &" > /dev/null 2>&1 < /dev/null + sleep 4 + PID=$(find_pid) + if [ -n "$PID" ]; then + echo "$PID" > "$PIDFILE" + echo "fam-notifier 已启动 (PID $PID)" + else + echo "启动失败,请查看 $LOG 与 $APP_DIR/logs/fam-notifier.log"; return 1 + fi +} + +stop() { + if [ -f "$PIDFILE" ]; then kill "$(cat "$PIDFILE")" 2>/dev/null; rm -f "$PIDFILE"; fi + for p in $(ps aux | grep "[f]am_notifier" | awk '{print $2}'); do kill "$p" 2>/dev/null; done + echo "fam-notifier 已停止" +} + +status() { + PID=$(find_pid) + if [ -n "$PID" ]; then + echo "运行中 (PID $PID)" + tail -3 "$APP_DIR/logs/fam-notifier.log" 2>/dev/null + else + echo "未运行"; return 1 + fi +} + +case "$1" in + start) start ;; + stop) stop ;; + restart) stop; sleep 2; start ;; + status) status ;; + *) echo "用法: $0 {start|stop|restart|status}"; exit 1 ;; +esac