feat: 小程序超级个体/个人资料/CKB获客;VIP列表展示过滤;管理端与API联调

- 超级个体:去掉首位特例;列表仅展示有头像且非微信默认昵称(vip.go)
- 个人资料:居中头像、低调联系方式、点头像优先走存客宝 lead(ckbLeadToken)
- 阅读页分享朋友圈复制与 toast 去重
- soul-api: miniprogram users 带 ckbLeadToken;其它 handler 与路由调整
- 脚本:content_upload、miniprogram 上传辅助等

Made-with: Cursor
This commit is contained in:
卡若
2026-03-22 08:34:28 +08:00
parent 17ce20c8ee
commit 5724fba877
119 changed files with 8198 additions and 4369 deletions

View File

@@ -25,6 +25,8 @@ import subprocess
import shutil
import tarfile
import time
import threading
import shlex
try:
import paramiko
@@ -311,8 +313,20 @@ def upload_and_extract(cfg, tarball_path, no_restart=False, restart_method="auto
"mkdir -p %s && cd %s && tar -xzf %s && "
"chmod +x soul-api && rm -f %s && echo OK"
) % (project_path, project_path, remote_tar, remote_tar)
stdin, stdout, stderr = client.exec_command(cmd, timeout=60)
stdin, stdout, stderr = client.exec_command(cmd, timeout=120)
ex_err = []
def _drain_tar_stderr():
try:
ex_err.append(stderr.read().decode("utf-8", errors="replace"))
except Exception:
ex_err.append("")
t_tar = threading.Thread(target=_drain_tar_stderr)
t_tar.daemon = True
t_tar.start()
out = stdout.read().decode("utf-8", errors="replace").strip()
t_tar.join(timeout=10)
exit_status = stdout.channel.recv_exit_status()
if exit_status != 0 or "OK" not in out:
print(" [失败] 解压失败,退出码:", exit_status)
@@ -325,17 +339,32 @@ def upload_and_extract(cfg, tarball_path, no_restart=False, restart_method="auto
if restart_method in ("auto", "btapi") and (cfg.get("bt_panel_url") and cfg.get("bt_api_key")):
ok = restart_via_bt_api(cfg)
if not ok and restart_method in ("auto", "ssh"):
# SSH只杀「工作目录为本项目」的 soul-api避免误杀其他 Go 项目
restart_cmd = (
"cd %s && T=$(readlink -f .) && for p in $(pgrep -f soul-api 2>/dev/null); do "
"[ \"$(readlink -f /proc/$p/cwd 2>/dev/null)\" = \"$T\" ] && kill $p 2>/dev/null; done; "
"sleep 2; setsid nohup ./soul-api >> soul-api.log 2>&1 </dev/null & "
"sleep 3; T=$(readlink -f .) && for p in $(pgrep -f soul-api 2>/dev/null); do "
"[ \"$(readlink -f /proc/$p/cwd 2>/dev/null)\" = \"$T\" ] && echo RESTART_OK && exit 0; done; echo RESTART_FAIL"
) % project_path
stdin, stdout, stderr = client.exec_command(restart_cmd, timeout=20)
# SSH正式环境固定监听 DEPLOY_PORT默认 8080。用 fuser 释放端口,避免宝塔守护
# 启动的进程 cwd 与项目目录不一致导致 pgrep+cwd 校验永远失败。
# 用 timeout + bash -c 单引号包裹,避免远端偶发挂死导致 Paramiko stdout.read 永久阻塞。
restart_inner = (
"cd %s && (fuser -k %d/tcp 2>/dev/null || true) && sleep 2 && "
"setsid nohup ./soul-api >> soul-api.log 2>&1 </dev/null & "
"sleep 12 && curl -sf --connect-timeout 5 --max-time 15 "
"http://127.0.0.1:%d/health 2>/dev/null | grep -q '\"status\"' "
"&& echo RESTART_OK || echo RESTART_FAIL"
) % (project_path, DEPLOY_PORT, DEPLOY_PORT)
restart_cmd = "timeout 95 bash -c " + shlex.quote(restart_inner)
stdin, stdout, stderr = client.exec_command(restart_cmd, timeout=110)
err_holder = []
def _drain_stderr():
try:
err_holder.append(stderr.read().decode("utf-8", errors="replace"))
except Exception:
err_holder.append("")
t = threading.Thread(target=_drain_stderr)
t.daemon = True
t.start()
out = stdout.read().decode("utf-8", errors="replace").strip()
err = (stderr.read().decode("utf-8", errors="replace") or "").strip()
t.join(timeout=5)
err = (err_holder[0] if err_holder else "").strip()
if err:
print(" [stderr] %s" % err[:200])
ok = "RESTART_OK" in out