From d8aa0b1f5d5dea269773f8795c7fb8f325e1b439 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Wed, 2 Sep 2026 17:21:23 +0800 Subject: [PATCH] =?UTF-8?q?feat(patrol):=20=E5=B7=A1=E6=AA=A2=E6=94=B9?= =?UTF-8?q?=E7=B5=84=E7=9B=AE=E9=8C=84=E9=A0=81=E5=8D=80=E5=A1=8A=E6=AA=94?= =?UTF-8?q?=EF=BC=8C=E8=BC=B8=E5=87=BA=E6=AA=94=E6=94=B9=E5=90=8D=20conten?= =?UTF-8?q?ts-entry.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 一輪巡檢組給目錄頁的輸出,從一列 markdown 表格改成一整個大標題區塊: `## {監控頁頁名}` 那一行、空行,然後每個欄位一條 `- {欄位名}:{值}`。輸出 檔跟著從 `contents.tsv` 改名 `contents-entry.md`,`contents_file=` 指向 新檔名。 目錄頁已經不放表格,再組出那一列就沒有地方放。舊檔名說的是逐欄對照的資料 檔,內容其實是一段 markdown,名不對實會讓呼叫端以為還能逐欄解析。改名讓 呼叫端契約的變動在檔名上就看得見,而不是同名檔悄悄換了格式——同名換格式 的話,還沒跟上的呼叫端會拿到讀得開卻意義全錯的內容。 新增 `oneline` 處理條列一條的值:換行一律壓成空白,因為一條條列裡的換行會 被讀成另一條,或者讓整個區塊提早結束;`|` 反而不跳脫,條列裡沒有切欄的 意思,跳脫過的符號會原樣顯示在頁面上。監控頁那一條的網址仍然留佔位,由 呼叫端換成真網址、驗過連得到才寫,這支腳本一頁都不寫。裸雜湊照樣留一條, 讓人不必從標題切字串就抄得到。 範圍是一輪巡檢給目錄頁的輸出檔。 --- tools/patrol.sh | 74 ++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/tools/patrol.sh b/tools/patrol.sh index 3bd1e33..5f4d851 100755 --- a/tools/patrol.sh +++ b/tools/patrol.sh @@ -84,24 +84,25 @@ # gitea.sh wiki-url 印的那一個,不自己組路徑;wiki 自己那種雙中括號寫法只在同一個 wiki 裡 # 解得開,寫錯不會報錯,畫面上看起來像正常文字或死連結,巡不到也修不了。 # 絕對網址要等內容頁真的寫進去才查得到(gitea.sh wiki-url 讀的是 API 回的 html_url), -# 而 collect 跑在寫入之前,這裡查不到。所以這支只把列組好、網址留佔位,換字交給呼叫端。 +# 而 collect 跑在寫入之前,這裡查不到。所以這支只把區塊組好、網址留佔位,換字交給呼叫端。 # # --- 連結先驗證連得到,才可以寫進頁面 --- # # 這支腳本一頁都不寫:它只組出檔案,兩次 wiki 寫入都在呼叫端。所以驗證的時機也在呼叫端—— # 換掉佔位、拿到真網址之後,寫入之前,把要放進頁面的每一個連結交給 jsc-gitea 的 -# tools/link-check.sh,結束碼 0 才寫。有 DEAD 就不寫那一頁或那一列,把連不到的清單回報出去。 +# tools/link-check.sh,結束碼 0 才寫。有 DEAD 就不寫那一頁或那一個區塊,把連不到的清單回報出去。 # 驗證一律走 API,不看網頁狀態碼:私有存取庫的網頁網址對未登入請求一律回 404,拿狀態碼判會 # 把好連結判成壞的。金鑰失效(結束碼 7)要與「連不到」(結束碼 1)分開看,兩者混用,一次金鑰 # 過期就會把整批還在的頁判成死連結。 # -# --- 目錄頁的比對鍵是裸 HASH,不是那個連結 --- +# --- 目錄頁的比對鍵是 H2 標題,不是那個連結 --- # -# 目錄頁那一列另外留一欄裸 HASH(純文字、不帶連結),upsert 就拿那一欄當鍵。wiki-contents.sh -# 比對的是整格文字,拿含網址的連結當鍵太脆:GITEA_HOST 換掉、JSC_WIKI_REPO_MONITOR 換過存取 -# 庫、Gitea 對頁名的網址編碼有差,整格文字就變了,鍵對不上就走附加那一支,同一台機器多出第二 -# 列,舊列從此不再更新。這一頁每 15 分鐘寫一次,重複列累積得很快。裸 HASH 只由 -# {主機名}/{登入帳號} 決定,上面三件事都動不到它。 +# 目錄頁一台機器一個 H2 區塊,標題寫成內容頁頁名 MONITOR_{HASH},upsert 就拿那個標題當鍵。 +# wiki-contents.sh 比對的是標題文字,拿含網址的連結當鍵太脆:GITEA_HOST 換掉、 +# JSC_WIKI_REPO_MONITOR 換過存取庫、Gitea 對頁名的網址編碼有差,那一條文字就變了,鍵對不上就走 +# 附加那一支,同一台機器多出第二個區塊,舊區塊從此不再更新。這一頁每 15 分鐘寫一次,重複區塊 +# 累積得很快。頁名只由 {主機名}/{登入帳號} 決定,上面三件事都動不到它。 +# 裸 HASH 照樣在區塊裡留一條:標題是 MONITOR_ 加上它,那一條讓人不必從標題切字串就抄得到。 # # --- 執行狀態事件為什麼由這支排空 --- # @@ -142,7 +143,7 @@ # failed_sources= 讀不到的來源路徑,以「、」分隔;全部讀得到就是「無」 # warn_sources= 本輪的警示來源,以「、」分隔;沒有警示就是「無」。各項全過卻判成警示 # 時,原因只寫在這裡 -# tasks_total= tasks_failing= 待辦簿筆數與連續失敗筆數,只供目錄頁那一列用 +# tasks_total= tasks_failing= 待辦簿筆數與連續失敗筆數,只供目錄頁那一個區塊用 # pending= 本輪待人處理的筆數 # events_total= 本輪排空到的事件筆數 # events_bad= 其中 status 不是 ok 的筆數 @@ -155,10 +156,10 @@ # summary_file= 「近 24 輪摘要」那一塊,表格裡先放本輪這一列,舊頁的資料列接在下面 # summary_row_file= 只有本輪那一列,方便直接插到既有表格最上面 # newpage_file= MONITOR_{HASH} 不存在時要建的整頁內容,三塊都已經排好 -# contents_file= MONITOR_CONTENTS 那一列的欄位值。row= 就是整列 markdown,第一欄是 -# [{頁名}]({絕對網址}) 這種連結,網址的位置留 {監控頁絕對網址} 佔位,由呼叫端 -# 換掉、驗過再寫,理由見下一段;第二欄是裸 HASH,upsert 拿那一欄當鍵,理由見 -# 再下一段 +# contents_file= 目錄頁上本機那一個 H2 區塊,整塊 markdown:`## {頁名}` 那一行、 +# 空行,然後各條 `- {欄位名}:{值}`。「監控頁」那一條是 [{頁名}]({絕對網址}) +# 這種連結,網址的位置留 {監控頁絕對網址} 佔位,由呼叫端換掉、驗過再寫,理由見 +# 下一段。upsert 拿 H2 標題當鍵,理由見再下一段 # # 環境變數: # JSC_HOME 助理狀態檔的根目錄,預設 ~/.jsc @@ -270,6 +271,10 @@ mtime_of() { # $1=檔案;印出修改時間,取不到印「-」 # markdown 表格欄位裡的 `|` 會把欄切開,一律跳脫;換行壓成空白。 cell() { printf '%s' "$1" | tr '\n' ' ' | sed 's/|/\\|/g'; } +# 條列一條的值。換行一律壓成空白:一條 bullet 裡的換行會被讀成另一條,或者讓區塊提早結束。 +# `|` 在條列裡沒有特殊意義,所以不跳脫——跳脫過的 `\|` 反而會原樣顯示在頁面上。 +oneline() { printf '%s' "$1" | tr '\n' ' '; } + # 記一個讀不到的來源。同一輪多項失敗就串起來,供監控頁「讀不到的來源」那一列用。 add_failed_source() { # $1=路徑或來源名稱 if [ -z "$FAILED_SOURCES" ]; then FAILED_SOURCES="$1"; else FAILED_SOURCES="$FAILED_SOURCES、$1"; fi @@ -851,7 +856,7 @@ d11() { return 0 } -# --- 待辦簿筆數(只供目錄頁那一列用)--- +# --- 待辦簿筆數(只供目錄頁那一個區塊用)--- count_tasks() { TASKS_TOTAL=0; TASKS_FAILING=0 @@ -946,14 +951,14 @@ compose() { printf '> 最新一輪每輪整塊換掉;摘要表一輪一列往上疊,只留 24 列;基本資料建頁時寫一次就不動。\n' printf '> 完整內容只留最新一輪,頁面才讀得完;軌跡留在摘要表,看得出是從哪一輪開始壞的。\n' printf '> 目錄頁 `MONITOR_CONTENTS` 在 `JSC_WIKI_REPO_CONTENTS` 解出的專用存取庫,和這頁不同庫。\n' - printf '> 那一頁只更新自己那一列,別台機器的列一個字都不動,寫入交給 `jsc-gitea/tools/wiki-contents.sh upsert`。\n\n' + printf '> 那一頁一台機器一個 H2 區塊,只更新自己那一個區塊,別台機器的區塊一個字都不動,寫入交給 `jsc-gitea/tools/wiki-contents.sh upsert`。\n\n' printf '```mermaid\nflowchart LR\n' printf ' A[巡檢一輪] --> B[收攏各項結果]\n' printf ' B --> C[讀回舊頁]\n' printf ' C --> D[換掉最新一輪那一塊]\n' printf ' D --> E[本輪摘要列插到表格最上面,截到 24 列]\n' printf ' E --> F[整頁寫回]\n' - printf ' F --> G[wiki-contents.sh upsert 更新目錄頁自己那一列]\n' + printf ' F --> G[wiki-contents.sh upsert 更新目錄頁自己那一個區塊]\n' printf ' G --> H[最後才寫心跳]\n' printf '```\n\n' printf '## 本頁基本資料\n\n' @@ -968,25 +973,24 @@ compose() { cat "$RD/summary.md" } >"$RD/newpage.md" + # 目錄頁那一個 H2 區塊。標題就是內容頁頁名,欄位一行一條,順序照範本從上到下。 + # 「監控頁」那一條是 [{頁名}]({絕對網址}) 這種連結,網址留佔位由呼叫端換掉、過完 link-check.sh + # 才寫,理由見檔頭「目錄頁與內容頁分屬兩個存取庫」與「連結先驗證連得到」。 + # 連結文字先寫死成頁名:頁名這裡就知道,只有網址要等內容頁寫成才查得到。 + # upsert 拿 H2 標題當鍵,不拿那條連結:連結含 GITEA_HOST 與頁名的網址編碼,主機位址、存取庫或 + # 編碼一變,那一條文字就變了,鍵對不上就每輪多附一個區塊。頁名只跟 {主機名}/{登入帳號} 有關, + # 那三件事都動不到它。裸 HASH 照樣留一條,讓人不必從標題切字串就抄得到。 { - printf 'page=%s\n' "$PAGE" - printf 'host=%s\n' "$HOST" - printf 'user=%s\n' "$USER_NAME" - printf 'heartbeat=%s\n' "$HEARTBEAT_STATE" - printf 'last_patrol=%s\n' "$AT" - printf 'tasks_total=%s\n' "$TASKS_TOTAL" - printf 'tasks_failing=%s\n' "$TASKS_FAILING" - printf 'hash=%s\n' "$HASH" - # 第一欄是 [{頁名}]({絕對網址}) 這種連結,網址留佔位由呼叫端換掉、過完 link-check.sh 才寫, - # 理由見檔頭「目錄頁與內容頁分屬兩個存取庫」與「連結先驗證連得到」。 - # 連結文字先寫死成頁名:頁名這裡就知道,只有網址要等內容頁寫成才查得到。 - # 第二欄是裸 HASH,upsert 拿它當鍵。鍵不能用第一欄那個連結:那一格含 GITEA_HOST 與頁名的 - # 網址編碼,主機位址、存取庫或編碼一變,整格文字就變了,鍵對不上就每輪多附一列。裸 HASH - # 只跟 {主機名}/{登入帳號} 有關,那三件事都動不到它。 - printf 'row=| [%s](%s) | %s | %s | %s | %s | %s | %s | %s |\n' \ - "$PAGE" '{監控頁絕對網址}' "$HASH" "$HOST" "$USER_NAME" "$HEARTBEAT_STATE" "$AT" \ - "$TASKS_TOTAL" "$TASKS_FAILING" - } >"$RD/contents.tsv" + printf '## %s\n\n' "$PAGE" + printf -- '- 監控頁:[%s](%s)\n' "$PAGE" '{監控頁絕對網址}' + printf -- '- HASH:%s\n' "$HASH" + printf -- '- 主機:%s\n' "$(oneline "$HOST")" + printf -- '- 帳號:%s\n' "$(oneline "$USER_NAME")" + printf -- '- 心跳:%s\n' "$(oneline "$HEARTBEAT_STATE")" + printf -- '- 最後巡檢:%s\n' "$(oneline "$AT")" + printf -- '- 待辦筆數:%s\n' "$TASKS_TOTAL" + printf -- '- 連續失敗項:%s\n' "$TASKS_FAILING" + } >"$RD/contents-entry.md" return 0 } @@ -1076,7 +1080,7 @@ case "$CMD" in printf 'summary_file=%s\n' "$RD/summary.md" printf 'summary_row_file=%s\n' "$RD/summary-row.md" printf 'newpage_file=%s\n' "$RD/newpage.md" - printf 'contents_file=%s\n' "$RD/contents.tsv" + printf 'contents_file=%s\n' "$RD/contents-entry.md" [ "$OK_COUNT" -eq 0 ] && exit 3 [ "$FAIL_COUNT" -gt 0 ] && exit 1