feat: 全面快取資料設計 & heartbeat 機制除錯完成
This commit is contained in:
parent
9365fef8c5
commit
98e78789e5
File diff suppressed because it is too large
Load Diff
|
|
@ -13,7 +13,13 @@ let currentEditElementId = null;
|
||||||
let currentEditIsSuccess = false;
|
let currentEditIsSuccess = false;
|
||||||
let currentEditType = null; // 💡 新增:用來記錄是 'folder' 還是 'leaf'
|
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(); };
|
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 SESSION_USER_ID = crypto.randomUUID ? crypto.randomUUID() : 'user-' + Math.random().toString(36).substr(2, 9);
|
||||||
const ACTIVE_HEARTBEATS = {};
|
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) {
|
async function sendHeartbeat(path) {
|
||||||
try {
|
try {
|
||||||
await fetch('/api/v1/locks/heartbeat', {
|
const response = await fetch('/api/v1/locks/heartbeat', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ path: path, user_id: SESSION_USER_ID })
|
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) {
|
function highlightTerminalOutput(text) {
|
||||||
if (!text) return '';
|
if (!text) return '';
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue