feat: 全面快取資料設計 & heartbeat 機制除錯完成

This commit is contained in:
swpa 2026-05-08 18:31:46 +08:00
parent 9365fef8c5
commit 98e78789e5
2 changed files with 37859 additions and 6123 deletions

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,13 @@ let currentEditElementId = null;
let currentEditIsSuccess = false;
let currentEditType = null; // 💡 新增:用來記錄是 'folder' 還是 'leaf'
window.onload = initTerminal;
// 💤 全域閒置偵測
let idleTimer;
const IDLE_TIMEOUT = 300000; // 5 分鐘 (毫秒)
window.onload = () => {
initTerminal();
resetIdleTimer(); // 頁面載入時啟動閒置計時器
};
window.onresize = () => { if (fitAddon) fitAddon.fit(); };
// ==========================================
@ -22,16 +28,67 @@ window.onresize = () => { if (fitAddon) fitAddon.fit(); };
const SESSION_USER_ID = crypto.randomUUID ? crypto.randomUUID() : 'user-' + Math.random().toString(36).substr(2, 9);
const ACTIVE_HEARTBEATS = {};
// 💤 閒置超時,自動釋放所有鎖
async function releaseAllLocks() {
const pathsToRelease = Object.keys(ACTIVE_HEARTBEATS);
if (pathsToRelease.length === 0) return; // 如果沒有鎖,就不用執行
// 建立一個 Promise 陣列,來平行處理所有釋放請求
const releasePromises = pathsToRelease.map(path => {
// 1. 清除心跳計時器
clearInterval(ACTIVE_HEARTBEATS[path]);
delete ACTIVE_HEARTBEATS[path];
// 2. 發送釋放請求
return fetch('/api/v1/locks/release', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ path: path, user_id: SESSION_USER_ID })
}).catch(err => console.error(`釋放鎖定 ${path} 失敗:`, err));
});
// 3. 等待所有釋放請求完成
await Promise.all(releasePromises);
// 4. 提示並重整頁面
alert("您已閒置超過 5 分鐘,系統已自動釋放編輯鎖定並重新整理頁面。");
location.reload();
}
// 💓 發送心跳,告訴後端「我還在編輯」,請延長鎖定時間
async function sendHeartbeat(path) {
try {
await fetch('/api/v1/locks/heartbeat', {
const response = await fetch('/api/v1/locks/heartbeat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ path: path, user_id: SESSION_USER_ID })
});
} catch (error) {}
if (!response.ok) {
console.warn(`心跳發送失敗 (${path}): 伺服器回傳 ${response.status}`);
// 如果回傳 404代表後端的鎖已經被清掉了停止發送心跳
if (response.status === 404) {
clearInterval(ACTIVE_HEARTBEATS[path]);
delete ACTIVE_HEARTBEATS[path];
}
} else {
console.log(`💓 心跳已送出,鎖定已延長 (${path})`); // 測試用,確認沒問題後可刪除這行
}
} catch (error) {
console.error(`心跳請求發生錯誤 (${path}):`, error);
}
}
// 實作閒置計時器重置邏輯
function resetIdleTimer() {
clearTimeout(idleTimer);
idleTimer = setTimeout(releaseAllLocks, IDLE_TIMEOUT); // IDLE_TIMEOUT 是 300000
}
// 監聽使用者的互動事件,只要有動作就重置計時器
window.addEventListener('mousemove', resetIdleTimer);
window.addEventListener('keydown', resetIdleTimer);
window.addEventListener('click', resetIdleTimer);
// 🎨 輔助函數:解析終端機輸出,僅將錯誤/警告行標紅
function highlightTerminalOutput(text) {
if (!text) return '';