Compare commits

8 Commits

Author SHA1 Message Date
e70cfdd857 Merge pull request 'merge' (#37) from fix into main
All checks were successful
Test CI / test speed (push) Successful in 44s
Reviewed-on: #37
2024-12-27 10:44:39 +08:00
5397a2bb90 Merge branch 'fix-update' into fix
All checks were successful
Test CI / test speed (push) Successful in 15s
2024-10-25 09:58:16 +08:00
edab4a3950 Update frontend dependencies and add react-router-dom 2024-10-25 09:53:46 +08:00
043da6cb70 fix: fix missing "make" command 2024-10-25 09:37:26 +08:00
c64ccd57e3 Merge pull request 'merge into main' (#36) from fix-update into main
All checks were successful
Test CI / test speed (push) Successful in 18s
Reviewed-on: #36
2024-10-24 23:35:42 +08:00
835c908ca7 Merge remote-tracking branch 'refs/remotes/origin/fix-update' 2024-10-15 20:19:46 +08:00
fffa6728bc fix: remove duplicate import 2024-10-15 20:19:26 +08:00
7fa5bb460c Add css style 2024-10-15 19:59:20 +08:00
15 changed files with 425 additions and 282 deletions

View File

@@ -14,6 +14,7 @@
"axios": "^1.7.7", "axios": "^1.7.7",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-router-dom": "^6.27.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
} }
@@ -3484,6 +3485,15 @@
} }
} }
}, },
"node_modules/@remix-run/router": {
"version": "1.20.0",
"resolved": "https://registry.npmmirror.com/@remix-run/router/-/router-1.20.0.tgz",
"integrity": "sha512-mUnk8rPJBI9loFDZ+YzPGdeniYK+FTmRD1TMCz7ev2SNIozyKKpnGgsxO34u6Z4z/t0ITuu7voi/AshfsGsgFg==",
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@rollup/plugin-babel": { "node_modules/@rollup/plugin-babel": {
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmmirror.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", "resolved": "https://registry.npmmirror.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -16207,6 +16217,38 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/react-router": {
"version": "6.27.0",
"resolved": "https://registry.npmmirror.com/react-router/-/react-router-6.27.0.tgz",
"integrity": "sha512-YA+HGZXz4jaAkVoYBE98VQl+nVzI+cVI2Oj/06F5ZM+0u3TgedN9Y9kmMRo2mnkSK2nCpNQn0DVob4HCsY/WLw==",
"license": "MIT",
"dependencies": {
"@remix-run/router": "1.20.0"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/react-router-dom": {
"version": "6.27.0",
"resolved": "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-6.27.0.tgz",
"integrity": "sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==",
"license": "MIT",
"dependencies": {
"@remix-run/router": "1.20.0",
"react-router": "6.27.0"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"react": ">=16.8",
"react-dom": ">=16.8"
}
},
"node_modules/react-scripts": { "node_modules/react-scripts": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmmirror.com/react-scripts/-/react-scripts-5.0.1.tgz", "resolved": "https://registry.npmmirror.com/react-scripts/-/react-scripts-5.0.1.tgz",

View File

@@ -9,6 +9,7 @@
"axios": "^1.7.7", "axios": "^1.7.7",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-router-dom": "^6.27.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },

View File

@@ -1,29 +1,135 @@
.App-header { /* App.css */
background-color: #282c34; body {
padding: 20px; background-color: #f0f8ff; /* AliceBlue */
color: white; color: #2f6c99; /* Navy */
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
min-height: 100vh; /* Minimum height set to 100% of the viewport height */
} }
.App { .App {
display: flex;
flex-direction: column;
min-height: 100vh; /* Ensure the App component takes the full height */
}
.App-header {
background-color: #4abbe1; /*背景颜色*/
padding: 20px;
text-align: center; text-align: center;
margin: 20px;
} }
table { .App-content {
margin: 20px auto; flex: 1; /* This makes the main content take up the remaining space */
border-collapse: collapse; display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 40px 20px;
background: linear-gradient(135deg, #e0f7fa, #80deea); /* 渐变背景颜色 */
border-radius: 0px; /* 圆角边框 */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 阴影效果 */
} }
table, th, td { .App-footer {
border: 1px solid #ccc; background-color: #4abbe1; /*背景颜色*/
padding: 10px; padding: 10px;
text-align: center;
} }
th { .glow {
background-color: #f0f0f0; color: #ffffff; /* White */
text-shadow: 0 0 10px #00bfff, 0 0 20px #00bfff, 0 0 30px #00bfff, 0 0 40px #00bfff, 0 0 50px #00bfff, 0 0 60px #00bfff, 0 0 70px #00bfff;
font-size: 2.5em; /* 调整字体大小 */
}
input, button {
margin: 20px 10px;
padding: 10px;
border: 1px solid #000080; /* Navy */
border-radius: 5px;
cursor: pointer;
font-size: 1.2em; /* 调整字体大小 */
}
button:hover {
background-color: #104e8b; /* DodgerBlue Darker */
}
nav ul {
list-style-type: none;
padding: 0;
margin: 20px 0; /* 增加上下间距 */
}
nav li {
display: inline;
margin: 0 10px;
}
nav a {
color: #ffffff; /* White */
text-decoration: none;
font-size: 1.5em; /* 调整字体大小 */
padding: 5px 19px;
border-radius: 5px;
background-color: #2db5c391; /* DodgerBlue */
transition: background-color 0.3s, transform 0.3s;
}
nav a:hover {
text-decoration: underline;
background-color: #104e8b; /* DodgerBlue Darker */
transform: scale(1.05);
} }
.log-info { .log-info {
width: 80%; height: 200px;
margin: 20px auto; overflow-y: scroll;
background-color: #ffffff; /* White */
padding: 10px;
border: 1px solid #b3d9ff; /* Light Blue Border */
border-radius: 5px;
margin-top: 20px;
} }
.log-entry {
margin: 5px 0;
padding: 5px;
border-bottom: 1px solid #b3d9ff; /* Light Blue Border */
}
.log-entry:last-child {
border-bottom: none;
}
.log-timestamp {
color: #007acc; /* Blue */
font-weight: bold;
}
.log-message {
color: #333333; /* Dark Gray */
}
.node-info, .heartbeat-info, .nodes-list {
margin-top: 20px;
background-color: #e6f7ff; /* Light Blue */
padding: 10px;
border: 1px solid #b3d9ff; /* Light Blue Border */
border-radius: 5px;
width: 100%;
max-width: 600px;
}
.info-item {
margin-bottom: 10px;
}
pre {
white-space: pre-wrap; /* Wrap long lines */
word-wrap: break-word; /* Break long words */
}

View File

@@ -1,118 +1,38 @@
import React, { useEffect, useState } from 'react'; import React from 'react';
import axios from 'axios'; import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import HomePage from './HomePage';
import NodePage from './NodePage';
import HeartbeatPage from './HeartbeatPage';
import NodesListPage from './NodesListPage';
import WebSocketComponent from './WebSocketComponent'; import WebSocketComponent from './WebSocketComponent';
import './App.css';
function App() { function App() {
const [nodes, setNodes] = useState([]);
const [node, setNode] = useState(null);
const [heartbeat, setHeartbeat] = useState(null);
const [nodesList, setNodesList] = useState([]);
const [ip, setIp] = useState('');
const [count, setCount] = useState('');
const fetchNodes = async () => {
try {
const response = await axios.get('/server/show_nodes');
setNodes(response.data);
} catch (error) {
console.error('Error fetching nodes:', error);
}
};
const fetchNode = async (ip) => {
try {
const response = await axios.get('/server/get_node', { params: { ip } });
setNode(response.data);
} catch (error) {
console.error('Error fetching node:', error);
}
};
const fetchHeartbeat = async (ip) => {
try {
const response = await axios.get('/server/heartbeat', { params: { ip } });
setHeartbeat(response.data);
} catch (error) {
console.error('Error fetching heartbeat:', error);
}
};
const fetchNodesList = async (count) => {
try {
const response = await axios.get('/server/send_nodes_list', { params: { count } });
setNodesList(response.data);
} catch (error) {
console.error('Error fetching nodes list:', error);
}
};
useEffect(() => {
fetchNodes(); // 获取所有节点
}, []);
const handleFetchNode = () => {
fetchNode(ip); // 根据输入的 IP 获取单个节点
};
const handleFetchHeartbeat = () => {
fetchHeartbeat(ip); // 根据输入的 IP 获取心跳信息
};
const handleFetchNodesList = () => {
fetchNodesList(count); // 根据输入的数量获取节点列表
};
return ( return (
<div className="App"> <Router>
<header className="App-header"> <div className="App">
<h1>中央服务器路由</h1> {/* Header 部分仅放置导航或标题 */}
<header className="App-header">
</header>
<h2>所有节点</h2> {/* Main 部分用来渲染路由的内容 */}
{nodes.length > 0 ? ( <main className="App-content">
<ul> <Routes>
{nodes.map((node, index) => ( <Route path="/" element={<HomePage />} />
<li key={index}>{JSON.stringify(node)}</li> <Route path="/node" element={<NodePage />} />
))} <Route path="/heartbeat" element={<HeartbeatPage />} />
</ul> <Route path="/nodes-list" element={<NodesListPage />} />
) : ( <Route path="/logs" element={<WebSocketComponent />} />
<p>没有节点数据</p> </Routes>
)} </main>
<h2>单个节点</h2> {/* Footer 部分 */}
<input <footer className="App-footer">
type="text" <p>&copy; 2024 Server Application</p>
value={ip} </footer>
onChange={(e) => setIp(e.target.value)} </div>
placeholder="输入节点 IP" </Router>
/>
<button onClick={handleFetchNode}>获取节点</button>
{node ? <p>{JSON.stringify(node)}</p> : <p></p>}
<h2>心跳信息</h2>
<button onClick={handleFetchHeartbeat}>获取心跳信息</button>
{heartbeat ? <p>{JSON.stringify(heartbeat)}</p> : <p></p>}
<h2>节点列表</h2>
<input
type="number"
value={count}
onChange={(e) => setCount(e.target.value)}
placeholder="输入节点数量"
/>
<button onClick={handleFetchNodesList}>获取节点列表</button>
{nodesList.length > 0 ? (
<ul>
{nodesList.map((node, index) => (
<li key={index}>{JSON.stringify(node)}</li>
))}
</ul>
) : (
<p>没有节点列表数据</p>
)}
</header>
<WebSocketComponent/>
</div>
); );
} }
export default App; export default App;

View File

@@ -0,0 +1,55 @@
import React, { useState } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
import './App.css';
const HeartbeatPage = () => {
const [ip, setIp] = useState('');
const [heartbeat, setHeartbeat] = useState(null);
const fetchHeartbeat = async (ip) => {
try {
const response = await axios.get('/server/heartbeat', { params: { ip } });
setHeartbeat(response.data);
} catch (error) {
console.error('Error fetching heartbeat:', error);
}
};
const handleFetchHeartbeat = () => {
fetchHeartbeat(ip);
};
return (
<section>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/node">Get Node</Link></li>
<li><Link to="/heartbeat">Heartbeat</Link></li>
<li><Link to="/nodes-list">Nodes List</Link></li>
<li><Link to="/logs">Logs</Link></li>
</ul>
</nav>
<h2 className="glow">Heartbeat</h2>
<p>请输入节点 IP 地址以获取心跳状态信息</p>
<input
type="text"
value={ip}
onChange={(e) => setIp(e.target.value)}
placeholder="Enter node IP"
/>
<button onClick={handleFetchHeartbeat}>Get Heartbeat</button>
{heartbeat ? (
<div className="heartbeat-info">
<h3>Heartbeat Information:</h3>
<div className="info-item"><strong>Status:</strong> {heartbeat.status}</div>
</div>
) : (
<p>这里没有任何信息</p>
)}
</section>
);
};
export default HeartbeatPage;

21
frontend/src/HomePage.js Normal file
View File

@@ -0,0 +1,21 @@
import React from 'react';
import { Link } from 'react-router-dom';
import './App.css';
const HomePage = () => {
return (
<div>
<h1 className="glow">The server</h1>
<p>欢迎来到服务器管理页面请选择一个操作</p>
<nav>
<ul>
<li><Link to="/node">Get Node</Link></li>
<li><Link to="/heartbeat">Heartbeat</Link></li>
<li><Link to="/nodes-list">Nodes List</Link></li>
<li><Link to="/logs">Logs</Link></li>
</ul>
</nav>
</div>
);
};
export default HomePage;

59
frontend/src/NodePage.js Normal file
View File

@@ -0,0 +1,59 @@
import React, { useState } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
import './App.css';
const NodePage = () => {
const [ip, setIp] = useState('');
const [node, setNode] = useState(null);
const fetchNode = async (ip) => {
try {
const response = await axios.get('/server/get_node', { params: { ip } });
const nodeData = response.data;
const date = new Date(nodeData.current_time * 1000);
nodeData.current_time = date.toLocaleString();
setNode(nodeData);
} catch (error) {
console.error('Error fetching node:', error);
}
};
const handleFetchNode = () => {
fetchNode(ip);
};
return (
<section>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/node">Get Node</Link></li>
<li><Link to="/heartbeat">Heartbeat</Link></li>
<li><Link to="/nodes-list">Nodes List</Link></li>
<li><Link to="/logs">Logs</Link></li>
</ul>
</nav>
<h2 className="glow">Get Node</h2>
<p>请输入节点 IP 地址以获取节点信息</p>
<input
type="text"
value={ip}
onChange={(e) => setIp(e.target.value)}
placeholder="Enter node IP"
/>
<button onClick={handleFetchNode}>Send</button>
{node ? (
<div className="node-info">
<h3>Node Information:</h3>
<div className="info-item"><strong>ID:</strong> {node.id}</div>
<div className="info-item"><strong>Current Time:</strong> {node.current_time}</div>
</div>
) : (
<p>这里没有任何信息</p>
)}
</section>
);
};
export default NodePage;

View File

@@ -0,0 +1,61 @@
import React, { useState } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
import './App.css';
const NodesListPage = () => {
const [count, setCount] = useState('');
const [nodesList, setNodesList] = useState([]);
const fetchNodesList = async (count) => {
try {
const response = await axios.get('/server/send_nodes_list', { params: { count } });
setNodesList(response.data);
} catch (error) {
console.error('Error fetching nodes list:', error);
}
};
const handleFetchNodesList = () => {
fetchNodesList(count);
};
return (
<section>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/node">Get Node</Link></li>
<li><Link to="/heartbeat">Heartbeat</Link></li>
<li><Link to="/nodes-list">Nodes List</Link></li>
<li><Link to="/logs">Logs</Link></li>
</ul>
</nav>
<h2 className="glow">Nodes List</h2>
<p>请输入要获取的节点数量</p>
<input
type="number"
value={count}
onChange={(e) => setCount(e.target.value)}
placeholder="Enter the number of nodes"
/>
<button onClick={handleFetchNodesList}>Get Node List</button>
{nodesList.length > 0 ? (
<div className="nodes-list">
<h3>Nodes Information:</h3>
<ul>
{nodesList.map((node, index) => (
<li key={index} className="info-item">
{node}
</li>
))}
</ul>
</div>
) : (
<p>这里没有任何信息</p>
)}
</section>
);
};
export default NodesListPage;

View File

@@ -1,10 +1,9 @@
import React, { useEffect, useState, useRef, useCallback } from 'react'; import React, { useEffect, useState, useRef, useCallback } from 'react';
import './App.css'; // 确保引入了样式文件
const WebSocketComponent = () => { const WebSocketComponent = () => {
const [logs, setLogs] = useState([]); const [logs, setLogs] = useState([]);
const [nodes, setNodes] = useState([]);
const wsRef = useRef(null); const wsRef = useRef(null);
const heartbeatIntervalRef = useRef(null);
const connectWebSocket = useCallback(() => { const connectWebSocket = useCallback(() => {
if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) { if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
@@ -15,17 +14,11 @@ const WebSocketComponent = () => {
wsRef.current.onopen = () => { wsRef.current.onopen = () => {
console.log('WebSocket 连接成功'); console.log('WebSocket 连接成功');
heartbeatIntervalRef.current = setInterval(() => {
if (wsRef.current.readyState === WebSocket.OPEN) {
wsRef.current.send(JSON.stringify({ type: 'heartbeat' }));
}
}, 10000); // 心跳包间隔调整为 10 秒
}; };
wsRef.current.onmessage = (event) => { wsRef.current.onmessage = (event) => {
setLogs((prevLogs) => [...prevLogs, event.data]); // 直接加入收到的消息 setLogs((prevLogs) => [...prevLogs, JSON.parse(event.data)]); // 解析 JSON 数据
}; };
wsRef.current.onerror = (error) => { wsRef.current.onerror = (error) => {
console.error('WebSocket 错误: ', error); console.error('WebSocket 错误: ', error);
@@ -33,7 +26,6 @@ const WebSocketComponent = () => {
wsRef.current.onclose = () => { wsRef.current.onclose = () => {
console.log('WebSocket 连接关闭,尝试重新连接...'); console.log('WebSocket 连接关闭,尝试重新连接...');
clearInterval(heartbeatIntervalRef.current);
// 确保 WebSocket 连接在关闭后再进行重连 // 确保 WebSocket 连接在关闭后再进行重连
setTimeout(() => { setTimeout(() => {
connectWebSocket(); connectWebSocket();
@@ -47,30 +39,9 @@ const WebSocketComponent = () => {
if (wsRef.current) { if (wsRef.current) {
wsRef.current.close(); wsRef.current.close();
} }
clearInterval(heartbeatIntervalRef.current);
}; };
}, [connectWebSocket]); }, [connectWebSocket]);
// 获取节点信息
const fetchNodes = useCallback(async () => {
try {
const response = await fetch('/server/show_nodes');
const data = await response.json();
setNodes(data);
} catch (error) {
console.error('Error fetching nodes:', error);
}
}, []);
useEffect(() => {
connectWebSocket();
fetchNodes(); // 组件加载时获取节点信息
return () => {
if (wsRef.current) {
wsRef.current.close();
}
clearInterval(heartbeatIntervalRef.current);
};
}, [connectWebSocket, fetchNodes]);
useEffect(() => { useEffect(() => {
const logContainer = document.querySelector('.log-info'); const logContainer = document.querySelector('.log-info');
if (logContainer) { if (logContainer) {
@@ -80,36 +51,21 @@ const WebSocketComponent = () => {
return ( return (
<div> <div>
<h1>节点记录信息</h1> <h2 className="glow">The logs</h2>
<table> <p>这里显示服务器的日志信息</p>
<thead> <div className="log-info">
<tr> {logs.map((log, index) => {
<th>ID</th> const [timestamp, message] = log.message.split(' - ', 2);
<th>IP</th> return (
<th>Last Heartbeat</th> <div key={index} className="log-entry">
</tr> <span className="log-timestamp">{timestamp}</span>
</thead> <span className="log-message"> - {message}</span>
<tbody> </div>
{nodes.map((node) => ( );
<tr key={node[0]}> })}
<td>{node[0]}</td>
<td>{node[1]}</td>
<td>{new Date(node[2] * 1000).toLocaleString()}</td>
</tr>
))}
</tbody>
</table>
<h2>日志信息</h2>
<div
className="log-info"
style={{ height: '300px', overflowY: 'scroll', background: '#fff', padding: '10px' }}
>
{logs.map((log, index) => (
<p key={index} style={{ margin: '5px 0' }}>{log}</p>
))}
</div> </div>
</div> </div>
); );
}; };
export default WebSocketComponent; export default WebSocketComponent;

View File

@@ -1,11 +1,18 @@
/* src/index.css */ html, body {
body {
margin: 0; margin: 0;
padding: 0;
height: 100%; /* Ensures the body takes the full height */
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
#root {
height: 100%; /* Makes sure the root element takes the full height of the viewport */
display: flex;
flex-direction: column;
}
code { code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
} }

View File

@@ -1,13 +1,11 @@
import React from 'react'; import React from 'react';
import { createRoot } from 'react-dom/client'; import ReactDOM from 'react-dom';
import App from './App';
import './index.css'; import './index.css';
import App from './App';
const container = document.getElementById('root'); ReactDOM.render(
const root = createRoot(container);
root.render(
<React.StrictMode> <React.StrictMode>
<App /> <App />
</React.StrictMode> </React.StrictMode>,
document.getElementById('root')
); );

View File

@@ -8,6 +8,7 @@ cp -r gmssl/include include
mkdir gmssl/build mkdir gmssl/build
cd gmssl/build || exit cd gmssl/build || exit
cmake .. cmake ..
make
cd bin || exit cd bin || exit
cp libgmssl.so libgmssl.so.3 libgmssl.so.3.1 ../../../lib cp libgmssl.so libgmssl.so.3 libgmssl.so.3.1 ../../../lib
cp libsdf_dummy.so libsdf_dummy.so.3 libsdf_dummy.so.3.1 ../../../lib cp libsdf_dummy.so libsdf_dummy.so.3 libsdf_dummy.so.3.1 ../../../lib

View File

@@ -1,84 +0,0 @@
2024-10-14 22:50:49,964 - server - INFO - 节点信息已成功获取
2024-10-14 22:50:58,662 - server - INFO - 节点信息已成功获取
2024-10-14 22:51:03,979 - server - INFO - 节点信息已成功获取
2024-10-14 22:51:05,667 - server - INFO - 节点信息已成功获取
2024-10-14 22:51:13,103 - server - INFO - 节点信息已成功获取
2024-10-14 22:51:13,117 - server - INFO - 节点信息已成功获取
2024-10-14 22:51:13,119 - server - INFO - 节点信息已成功获取
2024-10-14 22:53:44,044 - server - INFO - 数据库已清空
2024-10-14 22:55:08,488 - server - INFO - 节点信息已成功获取
2024-10-14 22:55:08,494 - server - INFO - 节点信息已成功获取
2024-10-14 22:55:08,497 - server - INFO - 节点信息已成功获取
2024-10-14 22:56:22,602 - server - INFO - 数据库已清空
2024-10-14 22:56:44,348 - server - INFO - 节点信息已成功获取
2024-10-14 22:56:44,353 - server - INFO - 节点信息已成功获取
2024-10-14 22:56:44,356 - server - INFO - 节点信息已成功获取
2024-10-14 22:57:25,960 - server - INFO - 节点信息已成功获取
2024-10-14 22:57:25,964 - server - INFO - 节点信息已成功获取
2024-10-14 22:57:25,966 - server - INFO - 节点信息已成功获取
2024-10-14 22:57:27,676 - server - INFO - 节点信息已成功获取
2024-10-14 22:57:30,534 - server - INFO - 节点信息已成功获取
2024-10-14 22:57:30,537 - server - INFO - 节点信息已成功获取
2024-10-14 22:57:30,540 - server - INFO - 节点信息已成功获取
2024-10-14 23:05:37,396 - server - INFO - 节点信息已成功获取
2024-10-14 23:05:37,405 - server - INFO - 节点信息已成功获取
2024-10-14 23:05:45,897 - server - INFO - 节点信息已成功获取
2024-10-14 23:05:45,906 - server - INFO - 节点信息已成功获取
2024-10-14 23:05:50,598 - server - INFO - 已成功发送 2 个节点信息
2024-10-14 23:05:55,495 - server - INFO - 已成功发送 2 个节点信息
2024-10-14 23:06:34,923 - server - INFO - 已成功发送 2 个节点信息
2024-10-14 23:06:58,479 - server - WARNING - 收到无效 IP 格式的心跳包:
2024-10-14 23:11:47,671 - server - INFO - 节点信息已成功获取
2024-10-14 23:13:06,672 - server - INFO - 节点信息已成功获取
2024-10-14 23:13:19,665 - server - INFO - 节点信息已成功获取
2024-10-14 23:13:19,976 - server - INFO - 节点信息已成功获取
2024-10-14 23:13:20,286 - server - INFO - 节点信息已成功获取
2024-10-14 23:15:27,409 - server - INFO - 节点信息已成功获取
2024-10-14 23:15:27,558 - server - INFO - 节点信息已成功获取
2024-10-14 23:15:27,621 - server - INFO - 节点信息已成功获取
2024-10-14 23:15:27,631 - server - INFO - 节点信息已成功获取
2024-10-14 23:16:40,476 - server - INFO - 节点信息已成功获取
2024-10-14 23:16:40,487 - server - INFO - 节点信息已成功获取
2024-10-14 23:16:40,540 - server - INFO - 节点信息已成功获取
2024-10-14 23:16:40,798 - server - INFO - 节点信息已成功获取
2024-10-14 23:17:25,417 - server - INFO - 节点信息已成功获取
2024-10-14 23:18:35,867 - server - INFO - IP 119.3.125.234 对应的ID为 1996717546
2024-10-14 23:18:35,867 - server - INFO - 当前时间: 1728919115
2024-10-14 23:18:35,874 - server - INFO - 节点 119.3.125.234 已成功添加到数据库
2024-10-14 23:18:56,376 - server - WARNING - 节点 127.0.0.1 未找到
2024-10-14 23:19:22,373 - server - INFO - 已成功发送 1 个节点信息
2024-10-14 23:19:22,630 - server - INFO - 已成功发送 1 个节点信息
2024-10-14 23:19:27,170 - server - WARNING - 收到无效 IP 格式的心跳包:
2024-10-14 23:19:49,887 - server - INFO - 收到来自 119.3.125.234 的心跳包
2024-10-14 23:19:49,895 - server - INFO - 成功更新节点 119.3.125.234 的心跳时间
2024-10-14 23:19:54,186 - server - WARNING - 收到无效 IP 格式的心跳包:
2024-10-15 13:05:13,546 - server - INFO - 节点信息已成功获取
2024-10-15 13:05:13,556 - server - INFO - 节点信息已成功获取
2024-10-15 13:05:13,569 - server - INFO - 节点信息已成功获取
2024-10-15 13:05:13,584 - server - INFO - 节点信息已成功获取
2024-10-15 13:06:27,487 - server - INFO - 节点信息已成功获取
2024-10-15 13:08:25,875 - server - WARNING - 节点 127.0.0.1 未找到
2024-10-15 13:08:41,176 - server - INFO - IP 127.0.0.0 对应的ID为 2130706432
2024-10-15 13:08:41,176 - server - INFO - 当前时间: 1728968921
2024-10-15 13:08:41,183 - server - INFO - 节点 127.0.0.0 已成功添加到数据库
2024-10-15 13:08:42,347 - server - INFO - IP 127.0.0.0 对应的ID为 2130706432
2024-10-15 13:08:42,347 - server - INFO - 当前时间: 1728968922
2024-10-15 13:09:42,114 - asyncio - ERROR - Task exception was never retrieved
future: <Task finished name='Task-3' coro=<receive_heartbeat_internal() done, defined at /home/muzhi/tpre-python/src/server.py:232> exception=OperationalError('no such table: nodes')>
Traceback (most recent call last):
File "/home/muzhi/tpre-python/src/server.py", line 237, in receive_heartbeat_internal
db.execute(
sqlite3.OperationalError: no such table: nodes
2024-10-15 13:11:26,824 - server - INFO - IP 192.168.8.57 对应的ID为 3232237625
2024-10-15 13:11:26,824 - server - INFO - 当前时间: 1728969086
2024-10-15 13:11:26,831 - server - INFO - 节点 192.168.8.57 已成功添加到数据库
2024-10-15 13:11:28,244 - server - INFO - IP 192.168.8.57 对应的ID为 3232237625
2024-10-15 13:11:28,244 - server - INFO - 当前时间: 1728969088
2024-10-15 13:11:46,205 - server - INFO - IP 192.168.8.57 对应的ID为 3232237625
2024-10-15 13:11:46,205 - server - INFO - 当前时间: 1728969106
2024-10-15 13:12:28,014 - server - INFO - IP 192.168.8.58 对应的ID为 3232237626
2024-10-15 13:12:28,014 - server - INFO - 当前时间: 1728969148
2024-10-15 13:12:28,020 - server - INFO - 节点 192.168.8.58 已成功添加到数据库
2024-10-15 13:12:34,416 - server - INFO - 收到来自 192.168.8.58 的心跳包
2024-10-15 13:12:34,422 - server - INFO - 成功更新节点 192.168.8.58 的心跳时间
2024-10-15 13:12:42,439 - server - INFO - 已成功发送 1 个节点信息

View File

@@ -28,9 +28,10 @@ app.add_middleware(
) )
# 配置日志文件路径 # 配置日志文件路径
log_dir = "logs"
if not os.path.exists(log_dir): log_dir = os.path.expanduser("~/tpre-python-logs")
os.makedirs(log_dir) os.makedirs(log_dir, exist_ok=True)
log_file = os.path.join(log_dir, "server_logs.log") log_file = os.path.join(log_dir, "server_logs.log")
# 全局日志配置 # 全局日志配置
@@ -58,10 +59,10 @@ async def lifespan(_: FastAPI):
current_dir = os.path.dirname(os.path.abspath(__file__)) current_dir = os.path.dirname(os.path.abspath(__file__))
# 定义 frontend 的绝对路径 # 定义 frontend 的绝对路径
frontend_dir = os.path.join(current_dir, "..", "frontend") frontend_dir = os.path.join(current_dir, "..", "frontend","build")
app = FastAPI(lifespan=lifespan) app = FastAPI(lifespan=lifespan)
app.mount("/frontend", StaticFiles(directory="frontend/build"), name="frontend") app.mount("/frontend", StaticFiles(directory=frontend_dir), name="frontend")
def init(): def init():

View File

@@ -9,7 +9,6 @@ import httpx
import respx import respx
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
import sys import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../src"))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../src")))
from node import ( from node import (