1.修改了系统监控页面,现在打卡页面即可开始监控。
2.修复了关闭DDS监控时的锁死问题。
This commit is contained in:
parent
069ea0ea37
commit
8c8f3a09f9
Binary file not shown.
@ -145,6 +145,15 @@ public:
|
|||||||
void unregisterPublisher(const std::string &topicName)
|
void unregisterPublisher(const std::string &topicName)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> locker(m_Mutex);
|
std::lock_guard<std::mutex> locker(m_Mutex);
|
||||||
|
unregisterPublisherWithoutLock(topicName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 注销发布者, 不带锁
|
||||||
|
* @param topicName: 主题名称
|
||||||
|
*/
|
||||||
|
void unregisterPublisherWithoutLock(const std::string &topicName)
|
||||||
|
{
|
||||||
auto it = topics_.find(topicName);
|
auto it = topics_.find(topicName);
|
||||||
if (it != topics_.end()) {
|
if (it != topics_.end()) {
|
||||||
MonitorTopicInfo &topicInfo = it->second; // 获取主题信息
|
MonitorTopicInfo &topicInfo = it->second; // 获取主题信息
|
||||||
@ -221,12 +230,21 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 注销订阅者
|
* @brief 注销订阅者, 带锁
|
||||||
* @param topicName: 主题名称
|
* @param topicName: 主题名称
|
||||||
*/
|
*/
|
||||||
void unregisterSubscriber(const std::string &topicName)
|
void unregisterSubscriber(const std::string &topicName)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> locker(m_Mutex);
|
std::lock_guard<std::mutex> locker(m_Mutex);
|
||||||
|
unregisterSubscriberWithoutLock(topicName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 注销订阅者, 不带锁
|
||||||
|
* @param topicName: 主题名称
|
||||||
|
*/
|
||||||
|
void unregisterSubscriberWithoutLock(const std::string &topicName)
|
||||||
|
{
|
||||||
auto it = topics_.find(topicName);
|
auto it = topics_.find(topicName);
|
||||||
if (it != topics_.end()) {
|
if (it != topics_.end()) {
|
||||||
MonitorTopicInfo &topicInfo = it->second; // 获取主题信息
|
MonitorTopicInfo &topicInfo = it->second; // 获取主题信息
|
||||||
@ -260,8 +278,8 @@ private:
|
|||||||
std::lock_guard<std::mutex> locker(m_Mutex);
|
std::lock_guard<std::mutex> locker(m_Mutex);
|
||||||
if (m_Participant != nullptr) {
|
if (m_Participant != nullptr) {
|
||||||
while (!topics_.empty()) {
|
while (!topics_.empty()) {
|
||||||
unregisterPublisher(topics_.begin()->first); // 注销发布者
|
unregisterPublisherWithoutLock(topics_.begin()->first); // 注销发布者
|
||||||
unregisterSubscriber(topics_.begin()->first); // 注销订阅者
|
unregisterSubscriberWithoutLock(topics_.begin()->first); // 注销订阅者
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,6 +315,45 @@ class RunSim extends HTMLElement {
|
|||||||
|
|
||||||
// 使用进程ID作为仿真ID
|
// 使用进程ID作为仿真ID
|
||||||
this.currentSimulationId = data.pid.toString();
|
this.currentSimulationId = data.pid.toString();
|
||||||
|
|
||||||
|
// 获取构型ID
|
||||||
|
const savedSelection = localStorage.getItem('xnsim-selection');
|
||||||
|
const selection = savedSelection ? JSON.parse(savedSelection) : {};
|
||||||
|
const confID = selection.configurationId;
|
||||||
|
|
||||||
|
// 获取构型参数
|
||||||
|
const configResponse = await fetch(`/api/configurations/${confID}`);
|
||||||
|
if (!configResponse.ok) {
|
||||||
|
throw new Error('获取构型参数失败');
|
||||||
|
}
|
||||||
|
const configData = await configResponse.json();
|
||||||
|
|
||||||
|
// 从构型参数中提取域ID
|
||||||
|
const domainId = configData.DomainID;
|
||||||
|
if (!domainId) {
|
||||||
|
throw new Error('构型参数中未找到有效的域ID');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化DDS监控
|
||||||
|
const ddsInitResponse = await fetch('/api/dds-monitor/initialize', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
domainId: domainId,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!ddsInitResponse.ok) {
|
||||||
|
console.warn('初始化DDS监控失败,但继续连接仿真');
|
||||||
|
} else {
|
||||||
|
const ddsInitResult = await ddsInitResponse.json();
|
||||||
|
if (ddsInitResult.error) {
|
||||||
|
console.warn('初始化DDS监控出错:', ddsInitResult.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 清空并初始化输出框
|
// 清空并初始化输出框
|
||||||
const outputContent = this.shadowRoot.querySelector('#output-content');
|
const outputContent = this.shadowRoot.querySelector('#output-content');
|
||||||
@ -524,16 +563,13 @@ class RunSim extends HTMLElement {
|
|||||||
throw new Error('构型参数中未找到有效的域ID');
|
throw new Error('构型参数中未找到有效的域ID');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成唯一的监控器ID
|
|
||||||
const monitorId = `sim_${Date.now()}`;
|
|
||||||
|
|
||||||
// 初始化DDS监控
|
// 初始化DDS监控
|
||||||
const ddsInitResponse = await fetch('/api/dds-monitor/initialize', {
|
const ddsInitResponse = await fetch('/api/dds-monitor/initialize', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ domainId, monitorId })
|
body: JSON.stringify({ domainId })
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!ddsInitResponse.ok) {
|
if (!ddsInitResponse.ok) {
|
||||||
@ -624,16 +660,42 @@ class RunSim extends HTMLElement {
|
|||||||
|
|
||||||
// 在组件销毁时清理资源
|
// 在组件销毁时清理资源
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
|
// 清理日志文件轮询
|
||||||
if (this.logFilePollingInterval) {
|
if (this.logFilePollingInterval) {
|
||||||
clearInterval(this.logFilePollingInterval);
|
clearInterval(this.logFilePollingInterval);
|
||||||
this.logFilePollingInterval = null;
|
this.logFilePollingInterval = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清理 SSE 连接
|
||||||
if (this.eventSource) {
|
if (this.eventSource) {
|
||||||
this.eventSource.close();
|
this.eventSource.close();
|
||||||
this.eventSource = null;
|
this.eventSource = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清理其他资源
|
||||||
this.currentSimulationId = null;
|
this.currentSimulationId = null;
|
||||||
this.reconnectAttempts = 0;
|
this.reconnectAttempts = 0;
|
||||||
|
this.isPaused = false;
|
||||||
|
this.modelGroups = [];
|
||||||
|
this.services = [];
|
||||||
|
|
||||||
|
// 清理 DOM 事件监听器
|
||||||
|
const runButton = this.shadowRoot.querySelector('#run-button');
|
||||||
|
const runSimulationButton = this.shadowRoot.querySelector('#run-simulation-button');
|
||||||
|
const pauseSimulationButton = this.shadowRoot.querySelector('#pause-simulation-button');
|
||||||
|
const stopSimulationButton = this.shadowRoot.querySelector('#stop-simulation-button');
|
||||||
|
|
||||||
|
if (runButton) runButton.removeEventListener('click', () => this.runTest());
|
||||||
|
if (runSimulationButton) runSimulationButton.removeEventListener('click', () => this.runSimulation());
|
||||||
|
if (pauseSimulationButton) pauseSimulationButton.removeEventListener('click', () => this.pauseSimulation());
|
||||||
|
if (stopSimulationButton) stopSimulationButton.removeEventListener('click', () => this.stopSimulation());
|
||||||
|
|
||||||
|
// 清理 Shadow DOM
|
||||||
|
if (this.shadowRoot) {
|
||||||
|
this.shadowRoot.innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注意:不在这里关闭 DDS 监控,因为其他组件可能正在使用它
|
||||||
}
|
}
|
||||||
|
|
||||||
showError(message) {
|
showError(message) {
|
||||||
@ -1136,23 +1198,8 @@ class RunSim extends HTMLElement {
|
|||||||
throw new Error(result.message || '停止引擎失败');
|
throw new Error(result.message || '停止引擎失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 等待5秒
|
// 等待1秒确保引擎完全停止
|
||||||
await new Promise(resolve => setTimeout(resolve, 5000));
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
|
||||||
// 调用老接口确保完全停止
|
|
||||||
const fallbackResponse = await fetch('/api/stop-simulation', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
id: simulationId
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!fallbackResponse.ok) {
|
|
||||||
console.warn('调用老接口停止仿真失败,但引擎已停止');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭SSE连接
|
// 关闭SSE连接
|
||||||
if (this.eventSource) {
|
if (this.eventSource) {
|
||||||
@ -1160,13 +1207,53 @@ class RunSim extends HTMLElement {
|
|||||||
this.eventSource = null;
|
this.eventSource = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 调用停止仿真接口清理数据库记录和发送终止事件
|
||||||
|
const stopResponse = await fetch('/api/stop-simulation', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ id: simulationId })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!stopResponse.ok) {
|
||||||
|
console.warn('调用停止仿真接口失败,但引擎已停止');
|
||||||
|
}
|
||||||
|
|
||||||
// 重置按钮状态
|
// 重置按钮状态
|
||||||
this.resetSimulationButtons();
|
this.resetSimulationButtons();
|
||||||
this.currentSimulationId = null;
|
this.currentSimulationId = null;
|
||||||
this.showSuccess('仿真已停止');
|
this.showSuccess('仿真已停止');
|
||||||
|
|
||||||
|
// 关闭系统监控
|
||||||
|
try {
|
||||||
|
await fetch('/api/system-monitor/stop', {
|
||||||
|
method: 'POST'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭DDS监控
|
||||||
|
try {
|
||||||
|
await fetch('/api/dds-monitor/unregister', {
|
||||||
|
method: 'POST'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('关闭DDS监控失败,但这不影响仿真停止');
|
||||||
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('停止仿真失败:', error);
|
console.error('停止仿真失败:', error);
|
||||||
this.showError('停止仿真失败: ' + error.message);
|
this.showError('停止仿真失败: ' + error.message);
|
||||||
|
|
||||||
|
// 即使出错也尝试清理资源
|
||||||
|
if (this.eventSource) {
|
||||||
|
this.eventSource.close();
|
||||||
|
this.eventSource = null;
|
||||||
|
}
|
||||||
|
this.resetSimulationButtons();
|
||||||
|
this.currentSimulationId = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,9 +20,14 @@ class SimulationMonitor extends HTMLElement {
|
|||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
this.render();
|
this.render();
|
||||||
this.isActive = true; // 设置初始状态为激活
|
this.isActive = true; // 设置初始状态为激活
|
||||||
// 等待组件完全加载
|
|
||||||
|
// 等待组件完全加载后初始化
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.initializeComponent();
|
this.initializeComponent();
|
||||||
|
// 初始化完成后再启动定时器,给服务器一些准备时间
|
||||||
|
setTimeout(() => {
|
||||||
|
this.startStatusCheck();
|
||||||
|
}, 1000); // 延迟1秒启动定时器
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,10 +50,10 @@ class SimulationMonitor extends HTMLElement {
|
|||||||
|
|
||||||
// 设置定时器,每秒执行一次
|
// 设置定时器,每秒执行一次
|
||||||
this.statusCheckInterval = setInterval(() => {
|
this.statusCheckInterval = setInterval(() => {
|
||||||
if (this.isActive && this.monitorStatus.isMonitoring) {
|
if (this.isActive) {
|
||||||
this.checkMonitorStatus();
|
this.checkMonitorStatus();
|
||||||
} else {
|
} else {
|
||||||
// 如果监控已停止,清除定时器
|
// 如果组件不再激活,清除定时器
|
||||||
this.stopStatusCheck();
|
this.stopStatusCheck();
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
@ -56,8 +61,6 @@ class SimulationMonitor extends HTMLElement {
|
|||||||
|
|
||||||
// 修改 checkMonitorStatus 方法
|
// 修改 checkMonitorStatus 方法
|
||||||
async checkMonitorStatus() {
|
async checkMonitorStatus() {
|
||||||
if (!this.monitorStatus.isMonitoring) return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 获取监控状态
|
// 获取监控状态
|
||||||
const statusResponse = await fetch('/api/system-monitor/status');
|
const statusResponse = await fetch('/api/system-monitor/status');
|
||||||
@ -89,20 +92,13 @@ class SimulationMonitor extends HTMLElement {
|
|||||||
// 只在成功获取数据后更新UI
|
// 只在成功获取数据后更新UI
|
||||||
this.updateUI();
|
this.updateUI();
|
||||||
} else {
|
} else {
|
||||||
// 如果监控已停止,清空数据
|
// 如果监控已停止,尝试启动监控
|
||||||
this.systemInfo = null;
|
this.startMonitoring();
|
||||||
this.threadInfo = null;
|
|
||||||
// 停止状态检查
|
|
||||||
this.stopStatusCheck();
|
|
||||||
// 更新UI显示停止状态
|
|
||||||
this.updateUI();
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取监控状态失败:', error);
|
console.error('获取监控状态失败:', error);
|
||||||
this.monitorStatus.lastError = error.message;
|
this.monitorStatus.lastError = error.message;
|
||||||
this.updateUI();
|
this.updateUI();
|
||||||
// 发生错误时也停止状态检查
|
|
||||||
this.stopStatusCheck();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,24 +141,10 @@ class SimulationMonitor extends HTMLElement {
|
|||||||
const ddsStatusResponse = await fetch('/api/dds-monitor/status');
|
const ddsStatusResponse = await fetch('/api/dds-monitor/status');
|
||||||
const ddsStatusData = await ddsStatusResponse.json();
|
const ddsStatusData = await ddsStatusResponse.json();
|
||||||
|
|
||||||
// 如果DDS监控未初始化,先初始化DDS监控
|
// 如果DDS监控未初始化,直接返回,等待下次定时器运行时再检查
|
||||||
if (!ddsStatusData.isInitialized) {
|
if (!ddsStatusData.isInitialized) {
|
||||||
const ddsInitResponse = await fetch('/api/dds-monitor/initialize', {
|
console.log('DDS监控未初始化,等待下次检查');
|
||||||
method: 'POST',
|
return;
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
domainId,
|
|
||||||
monitorId: this.monitorId
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!ddsInitResponse.ok) {
|
|
||||||
const errorData = await ddsInitResponse.json();
|
|
||||||
console.error('DDS监控初始化失败:', errorData.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 启动系统监控
|
// 启动系统监控
|
||||||
@ -192,17 +174,9 @@ class SimulationMonitor extends HTMLElement {
|
|||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
this.isActive = false;
|
this.isActive = false;
|
||||||
this.stopStatusCheck();
|
this.stopStatusCheck();
|
||||||
// 注销监控器
|
// 自动停止监控
|
||||||
fetch('/api/dds-monitor/unregister', {
|
this.stopMonitoring();
|
||||||
method: 'POST',
|
// 注意:不再在这里注销 DDS 监控,因为其他组件可能正在使用它
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ monitorId: this.monitorId })
|
|
||||||
}).catch(error => {
|
|
||||||
console.error('注销监控器失败:', error);
|
|
||||||
});
|
|
||||||
// 不要在这里销毁图表实例,让它在重新激活时重新创建
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async initializeComponent() {
|
async initializeComponent() {
|
||||||
@ -224,9 +198,9 @@ class SimulationMonitor extends HTMLElement {
|
|||||||
const statusData = await statusResponse.json();
|
const statusData = await statusResponse.json();
|
||||||
this.monitorStatus = statusData;
|
this.monitorStatus = statusData;
|
||||||
|
|
||||||
// 如果已经在监控中,开始状态检查
|
// 如果监控未运行,尝试启动监控
|
||||||
if (this.monitorStatus.isMonitoring && !this.statusCheckInterval) {
|
if (!this.monitorStatus.isMonitoring) {
|
||||||
this.startStatusCheck();
|
this.startMonitoring();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.chartInitialized = true;
|
this.chartInitialized = true;
|
||||||
@ -285,21 +259,11 @@ class SimulationMonitor extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateUI() {
|
updateUI() {
|
||||||
const startButton = this.shadowRoot.querySelector('.start-button');
|
|
||||||
const stopButton = this.shadowRoot.querySelector('.stop-button');
|
|
||||||
const statusDisplay = this.shadowRoot.querySelector('.status-display');
|
const statusDisplay = this.shadowRoot.querySelector('.status-display');
|
||||||
const engineInfo = this.shadowRoot.querySelector('#engine-info');
|
const engineInfo = this.shadowRoot.querySelector('#engine-info');
|
||||||
const coreStatus = this.shadowRoot.querySelector('#core-status');
|
const coreStatus = this.shadowRoot.querySelector('#core-status');
|
||||||
const threadTableBody = this.shadowRoot.querySelector('#thread-table-body');
|
const threadTableBody = this.shadowRoot.querySelector('#thread-table-body');
|
||||||
|
|
||||||
if (this.monitorStatus.isMonitoring) {
|
|
||||||
startButton.disabled = true;
|
|
||||||
stopButton.disabled = false;
|
|
||||||
} else {
|
|
||||||
startButton.disabled = false;
|
|
||||||
stopButton.disabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新状态显示
|
// 更新状态显示
|
||||||
statusDisplay.textContent = `监控状态: ${this.monitorStatus.isMonitoring ? '运行中' : '已停止'}`;
|
statusDisplay.textContent = `监控状态: ${this.monitorStatus.isMonitoring ? '运行中' : '已停止'}`;
|
||||||
if (this.monitorStatus.lastError) {
|
if (this.monitorStatus.lastError) {
|
||||||
@ -404,6 +368,17 @@ class SimulationMonitor extends HTMLElement {
|
|||||||
|
|
||||||
async stopMonitoring() {
|
async stopMonitoring() {
|
||||||
try {
|
try {
|
||||||
|
// 首先检查监控状态
|
||||||
|
const statusResponse = await fetch('/api/system-monitor/status');
|
||||||
|
const statusData = await statusResponse.json();
|
||||||
|
|
||||||
|
// 如果监控未运行,直接返回
|
||||||
|
if (!statusData.isMonitoring) {
|
||||||
|
console.log('监控未运行,无需关闭');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行关闭操作
|
||||||
const response = await fetch('/api/system-monitor/stop', {
|
const response = await fetch('/api/system-monitor/stop', {
|
||||||
method: 'POST'
|
method: 'POST'
|
||||||
});
|
});
|
||||||
@ -495,63 +470,6 @@ class SimulationMonitor extends HTMLElement {
|
|||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar {
|
|
||||||
display: flex;
|
|
||||||
gap: 12px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar-left {
|
|
||||||
display: flex;
|
|
||||||
gap: 12px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-label {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #333;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.control-button {
|
|
||||||
padding: 8px 16px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 14px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.control-button:disabled {
|
|
||||||
opacity: 0.6;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.start-button {
|
|
||||||
background-color: #4CAF50;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.start-button:hover:not(:disabled) {
|
|
||||||
background-color: #45a049;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stop-button {
|
|
||||||
background-color: #f44336;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stop-button:hover:not(:disabled) {
|
|
||||||
background-color: #da190b;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-display {
|
.status-display {
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
@ -712,13 +630,7 @@ class SimulationMonitor extends HTMLElement {
|
|||||||
</style>
|
</style>
|
||||||
<div class="monitor-container">
|
<div class="monitor-container">
|
||||||
<div class="toolbar-section">
|
<div class="toolbar-section">
|
||||||
<div class="toolbar">
|
<div class="status-display">监控状态: 未启动</div>
|
||||||
<div class="toolbar-left">
|
|
||||||
<button class="control-button start-button" onclick="this.getRootNode().host.startMonitoring()">开始监控</button>
|
|
||||||
<button class="control-button stop-button" onclick="this.getRootNode().host.stopMonitoring()">停止监控</button>
|
|
||||||
</div>
|
|
||||||
<div class="status-display">监控状态: 未启动</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
<div class="left-panel">
|
<div class="left-panel">
|
||||||
@ -824,7 +736,7 @@ class SimulationMonitor extends HTMLElement {
|
|||||||
<input type="checkbox" id="display-type-switch">
|
<input type="checkbox" id="display-type-switch">
|
||||||
<span class="slider"></span>
|
<span class="slider"></span>
|
||||||
</label>
|
</label>
|
||||||
<span id="display-type-label">频率</span>
|
<span id="display-type-label">周期</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,27 +6,25 @@ const { initializeMonitor, cleanupMonitor } = require('../utils/systemMonitor');
|
|||||||
let monitorStatus = {
|
let monitorStatus = {
|
||||||
isInitialized: false,
|
isInitialized: false,
|
||||||
domainId: null,
|
domainId: null,
|
||||||
lastError: null,
|
lastError: null
|
||||||
activeMonitors: new Set() // 添加活跃监控器集合
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化监控服务
|
// 初始化监控服务
|
||||||
router.post('/initialize', async (req, res) => {
|
router.post('/initialize', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { domainId, monitorId } = req.body;
|
const { domainId } = req.body;
|
||||||
|
|
||||||
if (!domainId || !monitorId) {
|
if (!domainId) {
|
||||||
return res.status(400).json({ error: '缺少必要的参数' });
|
return res.status(400).json({ error: '缺少必要的参数' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果已经初始化,检查是否是新的监控器
|
// 如果已经初始化,检查域ID是否匹配
|
||||||
if (monitorStatus.isInitialized) {
|
if (monitorStatus.isInitialized) {
|
||||||
if (monitorStatus.domainId !== domainId) {
|
if (monitorStatus.domainId !== domainId) {
|
||||||
return res.status(400).json({ error: 'DDS域ID不匹配' });
|
return res.status(400).json({ error: 'DDS域ID不匹配' });
|
||||||
}
|
}
|
||||||
monitorStatus.activeMonitors.add(monitorId);
|
|
||||||
return res.json({
|
return res.json({
|
||||||
message: '监控器已注册',
|
message: '监控服务已初始化',
|
||||||
status: monitorStatus
|
status: monitorStatus
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -41,7 +39,6 @@ router.post('/initialize', async (req, res) => {
|
|||||||
monitorStatus.isInitialized = true;
|
monitorStatus.isInitialized = true;
|
||||||
monitorStatus.domainId = domainId;
|
monitorStatus.domainId = domainId;
|
||||||
monitorStatus.lastError = null;
|
monitorStatus.lastError = null;
|
||||||
monitorStatus.activeMonitors.add(monitorId);
|
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
message: '监控服务初始化成功',
|
message: '监控服务初始化成功',
|
||||||
@ -57,32 +54,21 @@ router.post('/initialize', async (req, res) => {
|
|||||||
// 注销监控器
|
// 注销监控器
|
||||||
router.post('/unregister', async (req, res) => {
|
router.post('/unregister', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { monitorId } = req.body;
|
// 清理资源
|
||||||
|
await cleanupMonitor();
|
||||||
if (!monitorId) {
|
monitorStatus = {
|
||||||
return res.status(400).json({ error: '缺少必要的monitorId参数' });
|
isInitialized: false,
|
||||||
}
|
domainId: null,
|
||||||
|
lastError: null
|
||||||
monitorStatus.activeMonitors.delete(monitorId);
|
};
|
||||||
|
|
||||||
// 如果没有活跃的监控器了,清理资源
|
|
||||||
if (monitorStatus.activeMonitors.size === 0) {
|
|
||||||
cleanupMonitor();
|
|
||||||
monitorStatus = {
|
|
||||||
isInitialized: false,
|
|
||||||
domainId: null,
|
|
||||||
lastError: null,
|
|
||||||
activeMonitors: new Set()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
message: '监控器注销成功',
|
message: '监控服务注销成功',
|
||||||
status: monitorStatus
|
status: monitorStatus
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('注销监控器失败:', error);
|
console.error('注销监控服务失败:', error);
|
||||||
res.status(500).json({ error: '注销监控器失败', message: error.message });
|
res.status(500).json({ error: '注销监控服务失败', message: error.message });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ router.post('/resume', async (req, res) => {
|
|||||||
*/
|
*/
|
||||||
router.post('/stop', async (req, res) => {
|
router.post('/stop', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const result = stopEngine();
|
const result = await stopEngine();
|
||||||
res.json({
|
res.json({
|
||||||
success: !result.includes('失败'),
|
success: !result.includes('失败'),
|
||||||
message: result
|
message: result
|
||||||
|
@ -385,16 +385,36 @@ router.post('/stop-simulation', async (req, res) => {
|
|||||||
if (isRunning && isXNEngine) {
|
if (isRunning && isXNEngine) {
|
||||||
// 终止进程
|
// 终止进程
|
||||||
try {
|
try {
|
||||||
|
// 使用 SIGTERM 信号终止进程
|
||||||
process.kill(processInfo.pid, 'SIGTERM');
|
process.kill(processInfo.pid, 'SIGTERM');
|
||||||
// 等待进程终止
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
||||||
|
|
||||||
// 检查进程是否真的终止了
|
// 使用 Promise.race 添加超时机制
|
||||||
const stillRunning = await isProcessRunning(processInfo.pid);
|
const killPromise = new Promise(async (resolve) => {
|
||||||
if (stillRunning) {
|
let attempts = 0;
|
||||||
// 如果还在运行,强制终止
|
const maxAttempts = 5;
|
||||||
process.kill(processInfo.pid, 'SIGKILL');
|
|
||||||
}
|
while (attempts < maxAttempts) {
|
||||||
|
const stillRunning = await isProcessRunning(processInfo.pid);
|
||||||
|
if (!stillRunning) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await new Promise(r => setTimeout(r, 200));
|
||||||
|
attempts++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果进程还在运行,使用 SIGKILL 强制终止
|
||||||
|
if (await isProcessRunning(processInfo.pid)) {
|
||||||
|
process.kill(processInfo.pid, 'SIGKILL');
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
const timeoutPromise = new Promise((_, reject) =>
|
||||||
|
setTimeout(() => reject(new Error('终止进程超时')), 3000)
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.race([killPromise, timeoutPromise]);
|
||||||
|
|
||||||
// 删除数据库中的进程记录
|
// 删除数据库中的进程记录
|
||||||
await deleteXNEngineProcess(id);
|
await deleteXNEngineProcess(id);
|
||||||
|
@ -112,14 +112,16 @@ function initializeMonitor(domainId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 清理监控服务器资源
|
// 清理监控服务器资源
|
||||||
function cleanupMonitor() {
|
async function cleanupMonitor() {
|
||||||
if (!monitorLib) {
|
if (!monitorLib) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
monitorLib.XN_Cleanup();
|
monitorLib.XN_Cleanup();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return;
|
console.error('清理监控服务器资源失败:', error);
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,7 +285,7 @@ function resumeEngine() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 停止引擎
|
// 停止引擎
|
||||||
function stopEngine() {
|
async function stopEngine() {
|
||||||
if (!monitorLib) {
|
if (!monitorLib) {
|
||||||
return '监控服务器库未加载';
|
return '监控服务器库未加载';
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user