XNSim/XNSimHtml/components/network-monitor.js

289 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @class NetworkMonitor
* @description 网络监控组件用于监控系统网络状态和UDP数据抓包
*/
class NetworkMonitor extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.state = {
ip: '127.0.0.1',
port: 54321,
isMonitoring: false,
data: [],
timer: null,
statusMsg: '',
};
}
connectedCallback() {
this.render();
this.initialize();
}
disconnectedCallback() {
if (this.state.timer) {
clearInterval(this.state.timer);
}
}
render() {
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
font-family: 'Segoe UI', 'PingFang SC', Arial, sans-serif;
background: #f4f6fa;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0,0,0,0.07);
padding: 24px 20px 20px 20px;
max-width: 600px;
}
.form-row {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 18px;
}
label {
font-size: 15px;
color: #333;
}
input[type="text"], input[type="number"] {
border: 1px solid #d0d7de;
border-radius: 6px;
padding: 6px 12px;
font-size: 15px;
outline: none;
transition: border 0.2s;
background: #fff;
margin-left: 4px;
}
input[type="text"]:focus, input[type="number"]:focus {
border: 1.5px solid #409eff;
}
.status {
display: flex;
align-items: center;
background: #eaf6ff;
color: #1976d2;
border-radius: 8px;
padding: 8px 14px;
margin-bottom: 16px;
font-size: 15px;
font-weight: 500;
box-shadow: 0 1px 4px rgba(64,158,255,0.07);
}
.status::before {
content: '\u26A1';
margin-right: 8px;
font-size: 18px;
}
button {
border: none;
border-radius: 6px;
padding: 7px 20px;
font-size: 15px;
cursor: pointer;
transition: background 0.2s, box-shadow 0.2s;
box-shadow: 0 1px 4px rgba(64,158,255,0.07);
}
#startBtn {
background: linear-gradient(90deg, #409eff 60%, #66b1ff 100%);
color: #fff;
font-weight: 600;
}
#startBtn:hover {
background: linear-gradient(90deg, #1976d2 60%, #409eff 100%);
}
#stopBtn {
background: #fff0f0;
color: #e53935;
font-weight: 600;
border: 1px solid #ffcdd2;
}
#stopBtn:hover {
background: #ffcdd2;
}
.monitor-status {
margin-bottom: 14px;
font-size: 15px;
color: #666;
}
.monitor-status span {
font-weight: bold;
color: #43a047;
}
.monitor-status span.stopped {
color: #e53935;
}
.data-list {
max-height: 340px;
overflow-y: auto;
background: #fff;
border-radius: 10px;
border: 1px solid #e0e3e7;
padding: 10px 0 10px 0;
box-shadow: 0 1px 6px rgba(0,0,0,0.04);
}
.data-item {
background: #f8fafc;
border-radius: 8px;
margin: 10px 16px;
padding: 10px 14px 8px 14px;
box-shadow: 0 1px 3px rgba(64,158,255,0.04);
border-left: 4px solid #409eff;
font-size: 14px;
transition: box-shadow 0.2s;
}
.data-item:hover {
box-shadow: 0 2px 8px rgba(64,158,255,0.13);
}
.data-item b {
color: #1976d2;
}
.data-item pre {
background: #f3f7fa;
border-radius: 4px;
padding: 4px 6px;
margin: 2px 0 0 0;
font-size: 13px;
color: #333;
}
.nodata {
color: #bbb;
text-align: center;
padding: 30px 0;
}
</style>
<div class="status">${this.state.statusMsg}</div>
<div class="form-row">
<label>IP: <input type="text" id="ip" value="${this.state.ip}" /></label>
<label>端口: <input type="number" id="port" value="${this.state.port}" min="1024" max="65535" /></label>
<button id="startBtn">开始抓包</button>
<button id="stopBtn">停止抓包</button>
</div>
<div class="monitor-status">抓包状态:<span id="monitorStatus" class="${this.state.isMonitoring ? '' : 'stopped'}">${this.state.isMonitoring ? '运行中' : '已停止'}</span></div>
<div class="data-list" id="dataList"></div>
`;
this.shadowRoot.getElementById('startBtn').onclick = () => this.startMonitor();
this.shadowRoot.getElementById('stopBtn').onclick = () => this.stopMonitor();
this.shadowRoot.getElementById('ip').onchange = (e) => {
this.state.ip = e.target.value;
};
this.shadowRoot.getElementById('port').onchange = (e) => {
this.state.port = parseInt(e.target.value, 10);
};
this.renderDataList();
}
renderDataList() {
const dataList = this.shadowRoot.getElementById('dataList');
if (!dataList) return;
if (!this.state.data.length) {
dataList.innerHTML = '<div class="nodata">暂无数据</div>';
return;
}
dataList.innerHTML = this.state.data.map(item => `
<div class="data-item">
<div><b>时间:</b> ${new Date(item.timestamp).toLocaleString()}</div>
<div><b>来源:</b> ${item.source}</div>
<div><b>内容:</b> <pre>${typeof item.data === 'object' ? JSON.stringify(item.data, null, 2) : item.data}</pre></div>
</div>
`).join('');
}
setStatus(msg) {
this.state.statusMsg = msg;
this.render();
}
async startMonitor() {
this.setStatus('正在启动UDP抓包...');
try {
const res = await fetch('/api/udp-monitor/start', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ip: this.state.ip, port: this.state.port })
});
const data = await res.json();
if (data.success) {
this.state.isMonitoring = true;
this.setStatus(data.message || 'UDP抓包已启动');
this.startPolling();
} else {
this.state.isMonitoring = false;
this.setStatus(data.error || '启动失败');
}
} catch (e) {
this.state.isMonitoring = false;
this.setStatus('启动UDP抓包失败: ' + e.message);
}
this.render();
}
async stopMonitor() {
this.setStatus('正在停止UDP抓包...');
try {
const res = await fetch('/api/udp-monitor/stop', { method: 'POST' });
const data = await res.json();
this.state.isMonitoring = false;
this.setStatus(data.message || 'UDP抓包已停止');
if (this.state.timer) {
clearInterval(this.state.timer);
this.state.timer = null;
}
} catch (e) {
this.setStatus('停止UDP抓包失败: ' + e.message);
}
this.render();
}
startPolling() {
if (this.state.timer) clearInterval(this.state.timer);
this.state.timer = setInterval(() => this.fetchData(), 1000);
}
async fetchData() {
if (!this.state.isMonitoring) return;
try {
const res = await fetch('/api/udp-monitor/data');
const data = await res.json();
if (data.success) {
if (Array.isArray(data.data) && data.data.length > 0) {
this.state.data = this.state.data.concat(data.data);
// 最多只保留1000条
if (this.state.data.length > 1000) {
this.state.data = this.state.data.slice(-1000);
}
this.renderDataList();
}
this.state.isMonitoring = data.isMonitoring;
this.shadowRoot.getElementById('monitorStatus').textContent = data.isMonitoring ? '运行中' : '已停止';
}
} catch (e) {
this.setStatus('获取UDP数据失败: ' + e.message);
}
}
initialize() {
this.setStatus('请设置IP和端口后点击开始抓包');
// 检查当前监控状态
fetch('/api/udp-monitor/status').then(res => res.json()).then(data => {
if (data.success && data.isMonitoring) {
this.state.isMonitoring = true;
this.state.ip = data.ip || this.state.ip;
this.state.port = data.port || this.state.port;
this.setStatus('UDP抓包已在运行');
this.startPolling();
this.render();
}
});
}
reactivate() {
this.initialize();
}
}
customElements.define('network-monitor', NetworkMonitor);