feat(t98): 托盤「立刻同步」——訊號檔法零 IPC,跨平台

leo:「無法知道到底同步了沒,可以在 daemon 上加一個立刻同步?」
tray 點擊寫 ~/.arcrun-rag/sync-now+短暫顯示「同步中…」;collector 主迴圈 1 秒輪詢
訊號檔、有就立刻跑一輪刪檔,無則照 PollSec 排程;完成後 status.json 更新自然刷新托盤。
測試:collector+supervisor+tray 三模組全綠(總管親跑)。
(實作=子 CC;驗證+commit=總管)
This commit is contained in:
2026-07-28 15:06:08 +08:00
parent 903ca60154
commit 77aa4c5195
6 changed files with 202 additions and 6 deletions
+30 -6
View File
@@ -656,15 +656,39 @@ func runDirect(args []string) int {
persistClaudeBinIfChanged()
return code
}
// 常駐輪詢:純 stdlib ticker,跨平台。首輪立即跑。
// 常駐輪詢:純 stdlib,跨平台。首輪立即跑。
// t98:每 1 秒檢查一次訊號檔(SyncNowSignalPath),命中即立刻跑一輪並刪檔;
// 否則依 PollSec 間隔照舊定時跑。這讓 tray「立刻同步」按鈕能即時觸發,
// 不需引入 IPC/socket 等平台依賴。
fmt.Fprintf(os.Stderr, "collector direct daemon 啟動:監看 %s → %s(每 %ds 掃一輪)\n",
strings.Join(cfg.Folders(), "、"), cfg.triggerURL(cfg.IngestWF), cfg.PollSec)
runOne()
persistClaudeBinIfChanged() // 第一輪後立即回寫(下次重啟直達)
ticker := time.NewTicker(time.Duration(cfg.PollSec) * time.Second)
defer ticker.Stop()
for range ticker.C {
runOne()
signalPath := SyncNowSignalPath(cfg.Manifest)
pollInterval := time.Duration(cfg.PollSec) * time.Second
lastRun := time.Now()
const checkInterval = time.Second
for {
time.Sleep(checkInterval)
if consumeSyncNowSignal(signalPath) {
runOne()
lastRun = time.Now()
continue
}
if time.Since(lastRun) >= pollInterval {
runOne()
lastRun = time.Now()
}
}
return 0
}
// consumeSyncNowSignal 檢查訊號檔是否存在:存在則刪除並回 true(呼叫端立刻跑一輪同步);
// 不存在回 false。刪除失敗也回 true——確保本輪至少跑一次,下次若殘留再刪。
func consumeSyncNowSignal(path string) bool {
if _, err := os.Stat(path); err != nil {
return false
}
_ = os.Remove(path)
return true
}