web服务器文件开发
This commit is contained in:
parent
1cd0d68115
commit
cb6d594e49
|
|
@ -3,9 +3,12 @@
|
|||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
"${workspaceFolder}/**",
|
||||
"/usr/include"
|
||||
],
|
||||
"defines": [
|
||||
"CROW_USE_BOOST"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "gnu++17",
|
||||
|
|
|
|||
|
|
@ -9,7 +9,11 @@ find_package(spdlog REQUIRED)
|
|||
find_package(Boost REQUIRED COMPONENTS system thread)
|
||||
message(STATUS "Found Boost version: ${Boost_VERSION}")
|
||||
find_package(PahoMqttCpp REQUIRED)
|
||||
find_package(SQLite3 REQUIRED)
|
||||
|
||||
# 在包含 Crow 子目录之前,设置一个 CMake 选项
|
||||
# 这会告诉 Crow 的构建脚本去使用 Boost 库中包含的 Asio
|
||||
add_subdirectory(src/vendor/crow)
|
||||
|
||||
add_library(nlohmann_json INTERFACE)
|
||||
target_include_directories(nlohmann_json INTERFACE
|
||||
|
|
@ -54,6 +58,9 @@ add_library(edge_proxy_lib STATIC
|
|||
# 数据缓存/断点续传
|
||||
src/dataCache/data_cache.cc
|
||||
src/dataCache/cache_uploader.cc
|
||||
|
||||
#web
|
||||
src/web/web_server.cc
|
||||
)
|
||||
|
||||
target_include_directories(edge_proxy_lib PUBLIC
|
||||
|
|
@ -65,11 +72,14 @@ target_link_libraries(edge_proxy_lib PRIVATE
|
|||
Boost::system
|
||||
Boost::thread
|
||||
PahoMqttCpp::paho-mqttpp3
|
||||
sqlite3
|
||||
SQLite::SQLite3
|
||||
pthread
|
||||
nlohmann_json
|
||||
)
|
||||
|
||||
target_link_libraries(edge_proxy_lib PUBLIC
|
||||
Crow
|
||||
)
|
||||
# =================================================================
|
||||
# Main Application Target (UNCOMMENTED AND ACTIVATED)
|
||||
# =================================================================
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ services:
|
|||
- "8888:8888"
|
||||
- "9999:9999"
|
||||
- "502:502"
|
||||
- "8080:8080"
|
||||
command: sleep infinity
|
||||
|
||||
mqtt-broker:
|
||||
|
|
|
|||
|
|
@ -21,6 +21,11 @@ RUN apt-get update && \
|
|||
git \
|
||||
gdb \
|
||||
vim \
|
||||
# Piper TTS 所需的系统库
|
||||
espeak-ng-data \
|
||||
libespeak1 \
|
||||
python3 \
|
||||
python3-pip \
|
||||
# 开发库
|
||||
libssl-dev \
|
||||
libspdlog-dev \
|
||||
|
|
@ -68,8 +73,16 @@ RUN cd /tmp/build-context/external/paho.mqtt.c && \
|
|||
rm -rf /tmp/build-context && \
|
||||
# 在所有 apt 操作完成后,最后进行清理
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
COPY piper_models/ /app/piper_models/
|
||||
|
||||
RUN pip install --no-cache-dir --user piper-tts
|
||||
# 将 ~/.local/bin (包含 piper 二进制文件) 添加到 PATH
|
||||
RUN echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bash_profile
|
||||
# 现在,dev 用户可以使用 `piper` 命令了,只要 shell 环境被正确加载。
|
||||
# 我们可以将最终的 CMD 设置为加载环境然后执行一个命令,或者留空让用户交互。
|
||||
|
||||
# 5. 设置默认用户
|
||||
# =================================
|
||||
# 容器的默认用户将是 'dev'
|
||||
USER dev
|
||||
USER dev
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -0,0 +1,487 @@
|
|||
{
|
||||
"audio": {
|
||||
"sample_rate": 22050,
|
||||
"quality": "medium"
|
||||
},
|
||||
"espeak": {
|
||||
"voice": "cmn"
|
||||
},
|
||||
"inference": {
|
||||
"noise_scale": 0.667,
|
||||
"length_scale": 1,
|
||||
"noise_w": 0.8
|
||||
},
|
||||
"phoneme_type": "espeak",
|
||||
"phoneme_map": {},
|
||||
"phoneme_id_map": {
|
||||
"_": [
|
||||
0
|
||||
],
|
||||
"^": [
|
||||
1
|
||||
],
|
||||
"$": [
|
||||
2
|
||||
],
|
||||
" ": [
|
||||
3
|
||||
],
|
||||
"!": [
|
||||
4
|
||||
],
|
||||
"'": [
|
||||
5
|
||||
],
|
||||
"(": [
|
||||
6
|
||||
],
|
||||
")": [
|
||||
7
|
||||
],
|
||||
",": [
|
||||
8
|
||||
],
|
||||
"-": [
|
||||
9
|
||||
],
|
||||
".": [
|
||||
10
|
||||
],
|
||||
":": [
|
||||
11
|
||||
],
|
||||
";": [
|
||||
12
|
||||
],
|
||||
"?": [
|
||||
13
|
||||
],
|
||||
"a": [
|
||||
14
|
||||
],
|
||||
"b": [
|
||||
15
|
||||
],
|
||||
"c": [
|
||||
16
|
||||
],
|
||||
"d": [
|
||||
17
|
||||
],
|
||||
"e": [
|
||||
18
|
||||
],
|
||||
"f": [
|
||||
19
|
||||
],
|
||||
"h": [
|
||||
20
|
||||
],
|
||||
"i": [
|
||||
21
|
||||
],
|
||||
"j": [
|
||||
22
|
||||
],
|
||||
"k": [
|
||||
23
|
||||
],
|
||||
"l": [
|
||||
24
|
||||
],
|
||||
"m": [
|
||||
25
|
||||
],
|
||||
"n": [
|
||||
26
|
||||
],
|
||||
"o": [
|
||||
27
|
||||
],
|
||||
"p": [
|
||||
28
|
||||
],
|
||||
"q": [
|
||||
29
|
||||
],
|
||||
"r": [
|
||||
30
|
||||
],
|
||||
"s": [
|
||||
31
|
||||
],
|
||||
"t": [
|
||||
32
|
||||
],
|
||||
"u": [
|
||||
33
|
||||
],
|
||||
"v": [
|
||||
34
|
||||
],
|
||||
"w": [
|
||||
35
|
||||
],
|
||||
"x": [
|
||||
36
|
||||
],
|
||||
"y": [
|
||||
37
|
||||
],
|
||||
"z": [
|
||||
38
|
||||
],
|
||||
"æ": [
|
||||
39
|
||||
],
|
||||
"ç": [
|
||||
40
|
||||
],
|
||||
"ð": [
|
||||
41
|
||||
],
|
||||
"ø": [
|
||||
42
|
||||
],
|
||||
"ħ": [
|
||||
43
|
||||
],
|
||||
"ŋ": [
|
||||
44
|
||||
],
|
||||
"œ": [
|
||||
45
|
||||
],
|
||||
"ǀ": [
|
||||
46
|
||||
],
|
||||
"ǁ": [
|
||||
47
|
||||
],
|
||||
"ǂ": [
|
||||
48
|
||||
],
|
||||
"ǃ": [
|
||||
49
|
||||
],
|
||||
"ɐ": [
|
||||
50
|
||||
],
|
||||
"ɑ": [
|
||||
51
|
||||
],
|
||||
"ɒ": [
|
||||
52
|
||||
],
|
||||
"ɓ": [
|
||||
53
|
||||
],
|
||||
"ɔ": [
|
||||
54
|
||||
],
|
||||
"ɕ": [
|
||||
55
|
||||
],
|
||||
"ɖ": [
|
||||
56
|
||||
],
|
||||
"ɗ": [
|
||||
57
|
||||
],
|
||||
"ɘ": [
|
||||
58
|
||||
],
|
||||
"ə": [
|
||||
59
|
||||
],
|
||||
"ɚ": [
|
||||
60
|
||||
],
|
||||
"ɛ": [
|
||||
61
|
||||
],
|
||||
"ɜ": [
|
||||
62
|
||||
],
|
||||
"ɞ": [
|
||||
63
|
||||
],
|
||||
"ɟ": [
|
||||
64
|
||||
],
|
||||
"ɠ": [
|
||||
65
|
||||
],
|
||||
"ɡ": [
|
||||
66
|
||||
],
|
||||
"ɢ": [
|
||||
67
|
||||
],
|
||||
"ɣ": [
|
||||
68
|
||||
],
|
||||
"ɤ": [
|
||||
69
|
||||
],
|
||||
"ɥ": [
|
||||
70
|
||||
],
|
||||
"ɦ": [
|
||||
71
|
||||
],
|
||||
"ɧ": [
|
||||
72
|
||||
],
|
||||
"ɨ": [
|
||||
73
|
||||
],
|
||||
"ɪ": [
|
||||
74
|
||||
],
|
||||
"ɫ": [
|
||||
75
|
||||
],
|
||||
"ɬ": [
|
||||
76
|
||||
],
|
||||
"ɭ": [
|
||||
77
|
||||
],
|
||||
"ɮ": [
|
||||
78
|
||||
],
|
||||
"ɯ": [
|
||||
79
|
||||
],
|
||||
"ɰ": [
|
||||
80
|
||||
],
|
||||
"ɱ": [
|
||||
81
|
||||
],
|
||||
"ɲ": [
|
||||
82
|
||||
],
|
||||
"ɳ": [
|
||||
83
|
||||
],
|
||||
"ɴ": [
|
||||
84
|
||||
],
|
||||
"ɵ": [
|
||||
85
|
||||
],
|
||||
"ɶ": [
|
||||
86
|
||||
],
|
||||
"ɸ": [
|
||||
87
|
||||
],
|
||||
"ɹ": [
|
||||
88
|
||||
],
|
||||
"ɺ": [
|
||||
89
|
||||
],
|
||||
"ɻ": [
|
||||
90
|
||||
],
|
||||
"ɽ": [
|
||||
91
|
||||
],
|
||||
"ɾ": [
|
||||
92
|
||||
],
|
||||
"ʀ": [
|
||||
93
|
||||
],
|
||||
"ʁ": [
|
||||
94
|
||||
],
|
||||
"ʂ": [
|
||||
95
|
||||
],
|
||||
"ʃ": [
|
||||
96
|
||||
],
|
||||
"ʄ": [
|
||||
97
|
||||
],
|
||||
"ʈ": [
|
||||
98
|
||||
],
|
||||
"ʉ": [
|
||||
99
|
||||
],
|
||||
"ʊ": [
|
||||
100
|
||||
],
|
||||
"ʋ": [
|
||||
101
|
||||
],
|
||||
"ʌ": [
|
||||
102
|
||||
],
|
||||
"ʍ": [
|
||||
103
|
||||
],
|
||||
"ʎ": [
|
||||
104
|
||||
],
|
||||
"ʏ": [
|
||||
105
|
||||
],
|
||||
"ʐ": [
|
||||
106
|
||||
],
|
||||
"ʑ": [
|
||||
107
|
||||
],
|
||||
"ʒ": [
|
||||
108
|
||||
],
|
||||
"ʔ": [
|
||||
109
|
||||
],
|
||||
"ʕ": [
|
||||
110
|
||||
],
|
||||
"ʘ": [
|
||||
111
|
||||
],
|
||||
"ʙ": [
|
||||
112
|
||||
],
|
||||
"ʛ": [
|
||||
113
|
||||
],
|
||||
"ʜ": [
|
||||
114
|
||||
],
|
||||
"ʝ": [
|
||||
115
|
||||
],
|
||||
"ʟ": [
|
||||
116
|
||||
],
|
||||
"ʡ": [
|
||||
117
|
||||
],
|
||||
"ʢ": [
|
||||
118
|
||||
],
|
||||
"ʲ": [
|
||||
119
|
||||
],
|
||||
"ˈ": [
|
||||
120
|
||||
],
|
||||
"ˌ": [
|
||||
121
|
||||
],
|
||||
"ː": [
|
||||
122
|
||||
],
|
||||
"ˑ": [
|
||||
123
|
||||
],
|
||||
"˞": [
|
||||
124
|
||||
],
|
||||
"β": [
|
||||
125
|
||||
],
|
||||
"θ": [
|
||||
126
|
||||
],
|
||||
"χ": [
|
||||
127
|
||||
],
|
||||
"ᵻ": [
|
||||
128
|
||||
],
|
||||
"ⱱ": [
|
||||
129
|
||||
],
|
||||
"0": [
|
||||
130
|
||||
],
|
||||
"1": [
|
||||
131
|
||||
],
|
||||
"2": [
|
||||
132
|
||||
],
|
||||
"3": [
|
||||
133
|
||||
],
|
||||
"4": [
|
||||
134
|
||||
],
|
||||
"5": [
|
||||
135
|
||||
],
|
||||
"6": [
|
||||
136
|
||||
],
|
||||
"7": [
|
||||
137
|
||||
],
|
||||
"8": [
|
||||
138
|
||||
],
|
||||
"9": [
|
||||
139
|
||||
],
|
||||
"̧": [
|
||||
140
|
||||
],
|
||||
"̃": [
|
||||
141
|
||||
],
|
||||
"̪": [
|
||||
142
|
||||
],
|
||||
"̯": [
|
||||
143
|
||||
],
|
||||
"̩": [
|
||||
144
|
||||
],
|
||||
"ʰ": [
|
||||
145
|
||||
],
|
||||
"ˤ": [
|
||||
146
|
||||
],
|
||||
"ε": [
|
||||
147
|
||||
],
|
||||
"↓": [
|
||||
148
|
||||
],
|
||||
"#": [
|
||||
149
|
||||
],
|
||||
"\"": [
|
||||
150
|
||||
],
|
||||
"↑": [
|
||||
151
|
||||
]
|
||||
},
|
||||
"num_symbols": 256,
|
||||
"num_speakers": 1,
|
||||
"speaker_id_map": {},
|
||||
"piper_version": "1.0.0",
|
||||
"language": {
|
||||
"code": "zh_CN",
|
||||
"family": "zh",
|
||||
"region": "CN",
|
||||
"name_native": "简体中文",
|
||||
"name_english": "Chinese",
|
||||
"country_english": "China"
|
||||
},
|
||||
"dataset": "huayan"
|
||||
}
|
||||
32
src/main.cpp
32
src/main.cpp
|
|
@ -8,6 +8,7 @@
|
|||
#include "deviceManager/device_manager.h"
|
||||
#include "dataCache/data_cache.h"
|
||||
#include "dataCache/cache_uploader.h"
|
||||
#include "web/web_server.h"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
|
|
@ -34,7 +35,7 @@ void poll_system_metrics(
|
|||
SystemMonitor::SystemMonitor& monitor,
|
||||
MqttClient& mqtt_client
|
||||
) {
|
||||
// ... 此函数内部逻辑保持不变 ...
|
||||
if (g_io_context.stopped()) return;
|
||||
auto cpu_util = monitor.getCpuUtilization();
|
||||
auto mem_info = monitor.getMemoryInfo();
|
||||
double mem_total_gb = mem_info.total_kb / 1024.0 / 1024.0;
|
||||
|
|
@ -63,38 +64,33 @@ int main(int argc, char* argv[]) {
|
|||
signal(SIGTERM, signalHandler);
|
||||
|
||||
try {
|
||||
// --- 1. 初始化核心服务 ---
|
||||
MqttClient mqtt_client("tcp://mqtt-broker:1883", "edge-proxy-main-client");
|
||||
MqttRouter mqtt_router(mqtt_client);
|
||||
std::vector<uint16_t> listen_ports = { 8888 };
|
||||
TCPServer tcp_server(g_io_context, listen_ports, mqtt_client);
|
||||
SystemMonitor::SystemMonitor monitor;
|
||||
|
||||
// <<< MODIFIED: 初始化数据缓存和上传器 >>>
|
||||
DataCache data_cache;
|
||||
if (!data_cache.open("edge_data_cache.db")) { // 数据库文件将创建在程序运行目录
|
||||
if (!data_cache.open("edge_data_cache.db")) {
|
||||
spdlog::critical("Failed to initialize data cache. Exiting.");
|
||||
return 1;
|
||||
}
|
||||
CacheUploader cache_uploader(g_io_context, mqtt_client, data_cache);
|
||||
|
||||
// <<< MODIFIED: 设置MQTT连接成功的回调,用于触发断点续传 >>>
|
||||
mqtt_client.set_connected_handler([&](const std::string& cause){
|
||||
spdlog::info("MQTT client connected: {}", cause);
|
||||
// 当连接成功时,启动缓存上传
|
||||
cache_uploader.start_upload();
|
||||
});
|
||||
|
||||
// 现在再连接MQTT
|
||||
mqtt_client.connect();
|
||||
mqtt_router.start();
|
||||
|
||||
// --- 2. 启动系统状态监控定时器 ---
|
||||
monitor.getCpuUtilization(); // 首次调用以初始化
|
||||
|
||||
monitor.getCpuUtilization();
|
||||
boost::asio::steady_timer system_monitor_timer(g_io_context, std::chrono::seconds(15));
|
||||
system_monitor_timer.async_wait(std::bind(poll_system_metrics, std::ref(system_monitor_timer), std::ref(monitor), std::ref(mqtt_client)));
|
||||
|
||||
// --- 3. <<< MODIFIED: 创建包含缓存逻辑的统一数据上报回调函数 >>>
|
||||
// --- 创建包含缓存逻辑的统一数据上报回调函数 >>>
|
||||
auto report_to_mqtt = [&](const UnifiedData& data) {
|
||||
if (mqtt_client.is_connected()) {
|
||||
// 网络正常,直接上报
|
||||
|
|
@ -109,19 +105,29 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
};
|
||||
|
||||
// --- 4. 实例化设备管理器并从文件加载所有设备 (使用新的回调) ---
|
||||
// 实例化设备管理器并从文件加载所有设备 (使用新的回调)
|
||||
DeviceManager device_manager(g_io_context, report_to_mqtt);
|
||||
// 默认从程序运行目录下的 "devices.json" 文件加载
|
||||
device_manager.load_and_start("../config/devices.json");
|
||||
|
||||
// --- 5. 启动主事件循环 (程序将阻塞在这里直到被信号中断) ---
|
||||
WebServer web_server(monitor, 8080);
|
||||
web_server.start();
|
||||
|
||||
spdlog::info("All services are running. Press Ctrl+C to exit.");
|
||||
g_io_context.run();
|
||||
|
||||
// --- 清理工作 ---
|
||||
spdlog::info("Shutting down MQTT client...");
|
||||
|
||||
spdlog::info("Stopping device manager services...");
|
||||
device_manager.stop_all();
|
||||
spdlog::info("Stopping web server...");
|
||||
web_server.stop();
|
||||
spdlog::info("Disconnecting from MQTT broker...");
|
||||
mqtt_client.disconnect();
|
||||
|
||||
// mqtt_client.disconnect();
|
||||
// web_server.stop();
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
spdlog::critical("An unhandled exception occurred: {}", e.what());
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#define MODBUS_MASTER_POLLER_H
|
||||
|
||||
#include "protocol/iprotocol_adapter.h" // For UnifiedData and ReportDataCallback
|
||||
#include "modbus_common.h" // <<< MODIFIED: 包含通用配置定义
|
||||
#include "modbus_common.h"
|
||||
#include <boost/asio.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
|
|
|||
|
|
@ -64,12 +64,21 @@ MemoryInfo SystemMonitor::getMemoryInfo() const {
|
|||
std::string meminfo_content = readFile("/proc/meminfo");
|
||||
std::istringstream stream(meminfo_content);
|
||||
std::string line;
|
||||
|
||||
// 遍历/proc/meminfo的每一行
|
||||
while (std::getline(stream, line)) {
|
||||
// 查找并解析总内存
|
||||
if (line.rfind("MemTotal:", 0) == 0) {
|
||||
std::sscanf(line.c_str(), "MemTotal: %lu kB", &info.total_kb);
|
||||
break;
|
||||
}
|
||||
// 查找并解析可用内存 (MemAvailable通常比MemFree更准确)
|
||||
else if (line.rfind("MemAvailable:", 0) == 0) {
|
||||
std::sscanf(line.c_str(), "MemAvailable: %lu kB", &info.available_kb);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果系统中没有 MemAvailable 字段 (非常老的内核), 则将 available_kb 设为0
|
||||
// 我们的 web_server 代码会处理这种情况
|
||||
return info;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ struct StorageDevice {
|
|||
|
||||
struct MemoryInfo {
|
||||
uint64_t total_kb = 0;
|
||||
uint64_t available_kb = 0;
|
||||
// 未来可以添加 free, available, cached 等
|
||||
};
|
||||
|
||||
|
|
@ -55,7 +56,6 @@ public:
|
|||
std::string getKernelLogs(int last_n_lines = 20) const;
|
||||
|
||||
private:
|
||||
// --- 核心工具函数(现在作为私有成员)---
|
||||
std::string readFile(const std::string& filePath) const;
|
||||
std::string execCommand(const char* cmd) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
// 文件名: src/web/web_server.cc
|
||||
#include "web_server.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
WebServer::WebServer(SystemMonitor::SystemMonitor& monitor, uint16_t port)
|
||||
: m_monitor(monitor), m_port(port)
|
||||
{
|
||||
// Crow默认会输出很多调试信息,我们可以将其日志级别调高,
|
||||
// 以便只显示警告和错误,让我们的终端更干净。
|
||||
m_app.loglevel(crow::LogLevel::Warning);
|
||||
|
||||
// 调用函数来设置所有的API路由
|
||||
setup_routes();
|
||||
}
|
||||
|
||||
WebServer::~WebServer() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void WebServer::start() {
|
||||
if (m_thread.joinable()) {
|
||||
spdlog::warn("Web server is already running.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Crow的 run() 方法是一个阻塞操作,它会一直运行直到被停止。
|
||||
// 因此,我们必须在一个独立的线程中启动它,否则它会卡住我们的主程序。
|
||||
m_thread = std::thread([this]() {
|
||||
spdlog::info("Starting Web server on port {}", m_port);
|
||||
m_app.port(m_port).run();
|
||||
spdlog::info("Web server has stopped.");
|
||||
});
|
||||
}
|
||||
|
||||
void WebServer::stop() {
|
||||
// a. 停止Crow应用
|
||||
m_app.stop();
|
||||
|
||||
// b. 等待线程执行完毕
|
||||
if (m_thread.joinable()) {
|
||||
m_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void WebServer::setup_routes() {
|
||||
// ----------------------------------------------------------------
|
||||
// 定义第一个API路由: GET /api/system/status
|
||||
// ----------------------------------------------------------------
|
||||
CROW_ROUTE(m_app, "/api/system/status")
|
||||
([this] {
|
||||
auto cpu_util = m_monitor.getCpuUtilization();
|
||||
auto mem_info = m_monitor.getMemoryInfo();
|
||||
|
||||
crow::json::wvalue response;
|
||||
response["cpu_usage_percentage"] = cpu_util.totalUsagePercentage;
|
||||
response["memory_total_kb"] = mem_info.total_kb;
|
||||
response["memory_free_kb"] = mem_info.available_kb;
|
||||
response["memory_usage_percentage"] = (mem_info.total_kb > 0)
|
||||
? (1.0 - static_cast<double>(mem_info.available_kb) / mem_info.total_kb) * 100.0
|
||||
: 0.0;
|
||||
|
||||
|
||||
return response;
|
||||
});
|
||||
|
||||
// 未来在这里添加更多的路由,例如:
|
||||
// CROW_ROUTE(m_app, "/api/devices")([this]{ ... });
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
// 文件名: src/web/web_server.h
|
||||
#ifndef WEB_SERVER_H
|
||||
#define WEB_SERVER_H
|
||||
|
||||
#include "crow.h" // 引入 Crow 库的头文件
|
||||
#include "systemMonitor/system_monitor.h"
|
||||
#include <thread>
|
||||
|
||||
/**
|
||||
* @brief Web服务器模块
|
||||
* * 负责启动一个后台HTTP服务器,为前端提供RESTful API接口。
|
||||
* 它在自己的线程中运行,以避免阻塞主程序的io_context事件循环。
|
||||
*/
|
||||
class WebServer {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
* @param monitor SystemMonitor的引用,用于获取系统状态数据
|
||||
* @param port Web服务器监听的端口号,默认为8080
|
||||
*/
|
||||
WebServer(SystemMonitor::SystemMonitor& monitor, uint16_t port = 8080);
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
* * 确保在程序退出时,Web服务线程能够被安全地停止和清理。
|
||||
*/
|
||||
~WebServer();
|
||||
|
||||
// 禁止拷贝和赋值,因为该类管理着一个线程资源
|
||||
WebServer(const WebServer&) = delete;
|
||||
WebServer& operator=(const WebServer&) = delete;
|
||||
|
||||
/**
|
||||
* @brief 在后台线程中启动Web服务
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* @brief 停止Web服务并等待线程退出
|
||||
*/
|
||||
void stop();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 设置所有的API路由(URL路径)
|
||||
*/
|
||||
void setup_routes();
|
||||
|
||||
crow::SimpleApp m_app; // Crow 应用实例
|
||||
SystemMonitor::SystemMonitor& m_monitor;
|
||||
uint16_t m_port;
|
||||
|
||||
std::thread m_thread; // 运行Web服务的后台线程
|
||||
};
|
||||
|
||||
#endif // WEB_SERVER_H
|
||||
Loading…
Reference in New Issue