Files
arcrun-collector/cloud_version.go
T
Leo 1e139a2e7e t177 更正:取回 08-02 的原版修法,撤掉我重寫的次級版本
【leo 08-04 質問】「這不是先前改過為什麼又出現?你去查看 wiki,是不是你沒看 wiki 就改?」
——**是。查證屬實,而且比沒查更糟。**

【事實】08-02 commit `dde7a5b` 已完整修過這個 bug(t170 daemon 側),
但它**只在 `fix/cis-round3-landing-favicon` 分支**,`feat/daemon` 不含它。
我在 feat/daemon 上看到沒修過的舊 code,就當新 bug 從頭修了一遍。

【而且我修得比原版差】
  08-02 原版:isSemverLike 辨格式 → compareSemver **逐段整數比較**
              (能擋 "1.10.0" < "1.9.0" 這個經典坑)+ minCloudRelease 最低版本常數
  我今天版:  只判「是不是 semver」,是就放行 ⇒ 無法表達「semver 世代的最低相容版本」
⇒ 本 commit **取回 08-02 原版**(git checkout dde7a5b -- ...),
   刪掉我另建的重複測試檔 cloudversion_test.go,改用原版在 main_test.go 的 8 則。

【測試】兩模組全綠;8 則逐項通過,含「semver 1.10.0 比 1.9.0 新(防字串比較)」
——那則正是我的版本表達不出來的。

【病根】hook 給的是 wiki grep 命中行,而那幾行**不含「已修過」的線索**
(關鍵字 compareSemver/isSemverLike 不在搜尋詞裡)。我把「hook 沒提」當成「沒人修過」,
且跳過了 `git log --all -S` 這個五秒就能做的機械檢查。
⇒ 已在頂層 InkStoneCo 補 hook:改檔時一併列出**該檔在所有分支的近期 commit**。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 09:51:48 +08:00

116 lines
3.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// cloud_version.go — t103 daemon 雲端版本偵測。
// 每輪 GET {cypher_url}/health 取 bundle_version,比對最低相容日期,
// 過舊時 status.json 記錄,托盤顯示更新入口。
package main
import (
"encoding/json"
"io"
"net/http"
"strconv"
"strings"
"time"
)
// minCloudBuilt 是**舊格式**YYYY-MM-DD+sha)的雲端最低相容建置日期。
// 2026-08-02 起雲端版本號改為 semver1.4.2),改由 minCloudRelease 判斷;
// 本常數只用於尚未更新到 semver 世代的老實例。
const minCloudBuilt = "2026-07-28"
// minCloudRelease 是 semver 世代的雲端最低相容版本。
// 雲端契約變更時升此常數;daemon 下一輪自動偵測並提示更新。
const minCloudRelease = "1.4.0"
// isSemverLike 判斷版本字串是不是 semver 形態(開頭是數字且含 '.',且不是 YYYY-MM-DD)。
// 舊格式 "2026-07-31+8e83589" 開頭也是數字,但用 '-' 不用 '.',故以第一個分隔符區分。
func isSemverLike(v string) bool {
if v == "" {
return false
}
if v[0] < '0' || v[0] > '9' {
return false
}
dot := strings.Index(v, ".")
dash := strings.Index(v, "-")
if dot < 0 {
return false
}
return dash < 0 || dot < dash
}
// compareSemver 比較 a、b 兩個 semver(如 "1.4.2")。回 -101。
// 逐段以「整數」比較——**不可用字串比較**,否則 "1.10.0" < "1.9.0"。
func compareSemver(a, b string) int {
as := strings.Split(a, ".")
bs := strings.Split(b, ".")
n := len(as)
if len(bs) > n {
n = len(bs)
}
for i := 0; i < n; i++ {
var ai, bi int
if i < len(as) {
ai, _ = strconv.Atoi(strings.TrimSpace(as[i]))
}
if i < len(bs) {
bi, _ = strconv.Atoi(strings.TrimSpace(bs[i]))
}
if ai != bi {
if ai < bi {
return -1
}
return 1
}
}
return 0
}
// fetchCloudVersion 可在測試中替換為 stub,避免真實網路呼叫拖慢測試。
var fetchCloudVersion = fetchBundleVersion
// fetchBundleVersion GET {cypherURL}/health 取 bundle_version。
// 5s timeout;失敗(逾時、連不上、非 JSON)靜默回 ("", false)——呼叫端不判定過舊。
func fetchBundleVersion(cypherURL string) (version string, ok bool) {
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Get(strings.TrimSuffix(cypherURL, "/") + "/health")
if err != nil {
return "", false
}
defer resp.Body.Close()
var payload struct {
BundleVersion string `json:"bundle_version"`
}
if err := json.NewDecoder(io.LimitReader(resp.Body, 4096)).Decode(&payload); err != nil {
return "", false
}
return payload.BundleVersion, true
}
// cloudVersionStale 判斷雲端是否需要更新。
// checkOK=false/health 不可達)回 false(靜默不判定)——**呼叫端要自己顯示「查不到」**,
// 別把「連不上」呈現成「一切正常」(2026-08-02 記:這個預設會讓壞掉的機器安靜無聲)。
//
// 🔴 2026-08-02 修(leo 實撞:兩個帳號都更新到最新,卻**都**顯示「知識庫需要更新」且消不掉):
//
// 原本一律 `version.split("+")[0] < minCloudBuilt`,看似日期比較,**實為字串比較**。
// 08-02 雲端版本號改為 semver1.4.1)後:
// "1.4.1" < "2026-07-28" → true(字元 '1' 排在 '2' 前)⇒ **恆為真**
// ⇒ 更新到最新版反而被判過舊,更新幾次都消不掉。
// 兩種格式並存期間(老實例仍是 YYYY-MM-DD+sha),**必須兩種都認**
// 否則老實例會被誤判成最新而收不到更新提示。
func cloudVersionStale(version string, checkOK bool) bool {
if !checkOK {
return false
}
if version == "" {
return true
}
head := strings.SplitN(version, "+", 2)[0]
if isSemverLike(head) {
// semver 世代:逐段整數比較(不可字串比較,否則 1.10.0 < 1.9.0
return compareSemver(head, minCloudRelease) < 0
}
// 舊格式 YYYY-MM-DD+sha:日期字串等長、可安全字串比較
return head < minCloudBuilt
}