73 lines
3.4 KiB
Bash
73 lines
3.4 KiB
Bash
#!/usr/bin/env bash
|
||||
|
|
# =============================================================================
|
|||
|
|
# 构建期数据快照 —— 把「模板渲染时必须用、但只能从远端拿」的数据先 curl 成本地文件
|
|||
|
|
# =============================================================================
|
|||
|
|
# 为什么必须这么做(2026-10-04 实战教训):
|
|||
|
|
# footer.html 原先用 resources.GetRemote 拉 /api/links 与 /api/feeds。Hugo 的
|
|||
|
|
# GetRemote 是**在模板渲染过程中同步发请求**的,而 footer 每个页面都要走一遍。
|
|||
|
|
# 构建节点(国内)到 api.200181.xyz(Cloudflare)一旦抖动:
|
|||
|
|
# WARN Links API fetch failed: dial tcp 104.21.58.236:443: i/o timeout
|
|||
|
|
# WARN Links API fetch failed: ... connection reset by peer
|
|||
|
|
# Artalk 无关,但这两个拉取会一直重试 → 撞穿 Hugo 的 `partial` 30 秒超时 →
|
|||
|
|
# ERROR render of "home" failed: partial "footer.html" timed out after 30s
|
|||
|
|
# Error: error building site → exit code: 1
|
|||
|
|
# 整站构建失败、站点不更新(实测白等 14.5 分钟)。
|
|||
|
|
#
|
|||
|
|
# 改成「stage 里 curl 一次 + 模板只读本地文件」后:
|
|||
|
|
# 网络问题最多让某个快照变旧/为空(模板 with 判空 → 渲染空值),
|
|||
|
|
# **永远不会再让构建挂掉**。命中失败时一律删文件,绝不留半截内容。
|
|||
|
|
#
|
|||
|
|
# 在流水线里由 .cnb.yml 的「Hugo 构建」stage 调用;本地预览想拿到同款数据
|
|||
|
|
# 也可以直接跑:bash scripts/fetch_snapshots.sh
|
|||
|
|
#
|
|||
|
|
# 产物(均在 .gitignore 里,不入库):
|
|||
|
|
# data/artalk_conf.json 评论 /conf(首屏省一跳跨境往返,见 partials/artalk.html)
|
|||
|
|
# data/friend_links.json 友链 → window.friendLinks(评论区「友链」徽章)
|
|||
|
|
# data/friend_feeds.json 友圈 → window.friendFeeds(评论区「友圈」徽章)
|
|||
|
|
# =============================================================================
|
|||
|
|
|
|||
|
|
set -u
|
|||
|
|
|
|||
|
|
BASE="${RSSAPI_BASE:-https://api.200181.xyz}"
|
|||
|
|
BASE="${BASE%/}"
|
|||
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|||
|
|
DATA_DIR="$ROOT/data"
|
|||
|
|
mkdir -p "$DATA_DIR"
|
|||
|
|
|
|||
|
|
# JSON 合法性校验:python3 不一定有(本机 Windows 可能没有),没有就跳过校验
|
|||
|
|
validate_json() {
|
|||
|
|
command -v python3 >/dev/null 2>&1 || return 0
|
|||
|
|
python3 -c 'import json,sys;json.load(open(sys.argv[1],encoding="utf-8"))' "$1" 2>/dev/null
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# snap <输出文件名> <URL>
|
|||
|
|
# 成功:原子替换(先写 .tmp 再 mv),并打印字节数
|
|||
|
|
# 失败:删除目标文件(含 .tmp),返回非 0 —— 但本脚本最后统一 exit 0,
|
|||
|
|
# 因为「快照拿不到」是可接受的降级,不该阻断构建。
|
|||
|
|
snap() {
|
|||
|
|
local name="$1" url="$2" out tmp ok=1
|
|||
|
|
out="$DATA_DIR/$name"
|
|||
|
|
tmp="$out.tmp"
|
|||
|
|
|
|||
|
|
if curl -fsS --max-time 30 --retry 2 --retry-delay 2 --retry-connrefused \
|
|||
|
|
-H 'User-Agent: hugo-build-snapshot' "$url" -o "$tmp" 2>/dev/null; then
|
|||
|
|
if [ -s "$tmp" ] && validate_json "$tmp"; then
|
|||
|
|
mv -f "$tmp" "$out"
|
|||
|
|
echo "✅ $name 就绪 $(wc -c < "$out" | tr -d ' ') 字节"
|
|||
|
|
return 0
|
|||
|
|
fi
|
|||
|
|
echo "⚠️ $name 内容校验失败(空文件或非法 JSON)"
|
|||
|
|
else
|
|||
|
|
echo "⚠️ $name 拉取失败:$url"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
rm -f "$tmp" "$out"
|
|||
|
|
return 1
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
echo "── 构建期快照(源:$BASE)──"
|
|||
|
|
snap artalk_conf.json "$BASE/api/v2/conf" || true
|
|||
|
|
snap friend_links.json "$BASE/api/links?all=1" || true
|
|||
|
|
snap friend_feeds.json "$BASE/api/feeds" || true
|
|||
|
|
|
|||
|
|
exit 0
|