UNPKG

oimp

Version:

A CLI tool for generating OI problem and packages

136 lines (133 loc) 6.98 kB
"use strict" import { getNodePaths,findNodeIdByPath} from "./ide-utility.js"; import { fetchStatus } from "./ide-status.js"; import { loadFile } from './ide-jstree.js'; // 与webscoket相关 let ws = null; let reconnectTimer = null; let reconnectCount = 0; export async function initWebSocket() { // ===== WebSocket 自动刷新文件树和状态面板 ===== ws = new window.WebSocket('ws://' + window.location.host); ws.onopen = function () { reconnectCount = 0; }; ws.onmessage = async function (event) { try { const data = JSON.parse(event.data); if (data.type === 'tree_changed') { // console.log('WS tree_changed arrived', data); // 拉取最新树数据 const doRefreshTree = async (treeData) => { const $tree = $('#file-tree'); const tree = $tree.jstree(true); // 记录当前展开和选中节点 path function getOpenedNodePaths(tree) { const all = tree.get_json('#', { flat: true }); return all.filter(n => n.state && n.state.opened).map(n => n.data && n.data.path).filter(Boolean); } function getSelectedNodePaths(tree) { if (typeof tree.get_selected === 'function') { return getNodePaths(tree, tree.get_selected()); } const all = tree.get_json('#', { flat: true }); return all.filter(n => n.state && n.state.selected).map(n => n.data && n.data.path).filter(Boolean); } const openedPaths = getOpenedNodePaths(tree); const selectedPaths = getSelectedNodePaths(tree); tree.settings.core.data = treeData; window.isRefreshingTree = true; $tree.one('refresh.jstree', function () { const tree2 = $tree.jstree(true); window.isRestoringTreeSelection = true; // 恢复展开 openedPaths.forEach(path => { const id = findNodeIdByPath(tree2, path); // console.log('恢复展开', path, '->', id); if (id) tree2.open_node(id, null, false); }); // 恢复选中 let found = false; for (const path of selectedPaths) { const id = findNodeIdByPath(tree2, path); // console.log('恢复选中', path, '->', id); if (id) { tree2.deselect_all(); tree2.select_node(id, false, false); found = true; break; } } if (!found) { // 尝试保持原来的cpp文件选中状态 const currentCppFile = window.currentFile; if (currentCppFile && currentCppFile.endsWith('.cpp')) { // 查找当前cpp文件在新树中的节点 const all = tree2.get_json('#', { flat: true }); const currentCppNode = all.find(n => n.data && n.data.type === 'file' && n.data.path === currentCppFile); if (currentCppNode) { tree2.deselect_all(); tree2.select_node(currentCppNode.id, false, false); loadFile(currentCppNode.data.path); found = true; } } // 如果仍然没有找到,则选择第一个md文件 if (!found) { const all = tree2.get_json('#', { flat: true }); const firstMd = all.find(n => n.data && n.data.type === 'file' && n.text.toLowerCase().endsWith('.md')); if (firstMd) { tree2.deselect_all(); tree2.select_node(firstMd.id, false, false); loadFile(firstMd.data.path); // console.log('未能恢复选中,自动选中第一个md文件', firstMd.data.path); } else { // console.log('未能恢复选中,也未找到md文件'); } } } window.isRestoringTreeSelection = false; window.isRefreshingTree = false; // 如果有新的 pendingTreeData,立即再次刷新 if (window.pendingTreeData) { const nextData = window.pendingTreeData; window.pendingTreeData = null; setTimeout(() => doRefreshTree(nextData), 0); } }); tree.refresh(true, true); }; // 防抖处理 if (window.isRefreshingTree) { // 正在刷新,存下最新数据 clearTimeout(window.debounceTreeChangedTimer); window.debounceTreeChangedTimer = setTimeout(async () => { const res = await fetch('/api/tree'); const treeData = await res.json(); window.pendingTreeData = treeData; }, 1000); } else { clearTimeout(window.debounceTreeChangedTimer); window.debounceTreeChangedTimer = setTimeout(async () => { const res = await fetch('/api/tree'); const treeData = await res.json(); window.pendingTreeData = null; doRefreshTree(treeData); }, 1000); } return; } else if (data.type === 'status_changed') { fetchStatus && fetchStatus(); } } catch (e) { console.error("error:", e.message, e); } }; ws.onclose = function () { if (reconnectTimer) clearTimeout(reconnectTimer); reconnectTimer = setTimeout(initWebSocket, Math.min(5000, 1000 + 1000 * reconnectCount++)); }; ws.onerror = function () { ws.close(); }; }