diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 53765de..89f699f 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -5,7 +5,7 @@ "includePath": [ "${workspaceFolder}/**", "${workspaceFolder}/build/_deps/kylin-src/Universal", - "/opt/Libraries/boost_1_84_0/include" + "/opt/Libraries/boost_1_85_0/include" ], "defines": [], "compilerPath": "/usr/bin/gcc", diff --git a/Server/Application.cpp b/Server/Application.cpp index 8525ca9..22aacc1 100644 --- a/Server/Application.cpp +++ b/Server/Application.cpp @@ -5,6 +5,7 @@ #include "IoContext.h" #include "ServiceLogic.h" #include "ServiceManager.h" +#include "SystemUsage.h" #include "WeChatContext/CorporationContext.h" Application::Application(const std::string &path) @@ -122,6 +123,9 @@ Application::Application(const std::string &path) m_ioContext = Amass::Singleton::instance(getThreads()); m_timer = std::make_shared(*m_ioContext->ioContext()); + m_systemUsage = std::make_shared(*m_ioContext->ioContext(), getHomeAssistantAccessToken()); + m_systemUsage->start(); + alarmTask(); } diff --git a/Server/Application.h b/Server/Application.h index 69d05bd..3d5aca3 100644 --- a/Server/Application.h +++ b/Server/Application.h @@ -10,6 +10,7 @@ class HttpSession; class ChatRoom; +class SystemUsage; class IoContext; class Application : public ApplicationSettings, public std::enable_shared_from_this { @@ -22,6 +23,7 @@ public: BUILD_SETTING(uint16_t, Port, 8081); BUILD_SETTING(uint32_t, Threads, std::thread::hardware_concurrency()); BUILD_SETTING(std::string, DocumentRoot, "."); + BUILD_SETTING(std::string, HomeAssistantAccessToken, ""); INITIALIZE_FIELDS(Server, Port, Threads, DocumentRoot); Application(const std::string &path); @@ -40,6 +42,7 @@ private: std::shared_ptr> m_router; std::shared_ptr m_timer; std::shared_ptr m_charRoom; + std::shared_ptr m_systemUsage; }; #endif // __SETTINGS_H__ \ No newline at end of file diff --git a/Server/CMakeLists.txt b/Server/CMakeLists.txt index 1560e18..4c68099 100644 --- a/Server/CMakeLists.txt +++ b/Server/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable(Server main.cpp ResponseUtility.h ResponseUtility.cpp ServiceLogic.h ServiceLogic.inl ServiceLogic.cpp ServiceManager.h + SystemUsage.h SystemUsage.cpp UdpServer.h UdpServer.cpp WeChatContext/CorporationContext.h WeChatContext/CorporationContext.cpp WeChatContext/WeChatContext.h WeChatContext/WeChatContext.cpp diff --git a/Server/SystemUsage.cpp b/Server/SystemUsage.cpp new file mode 100644 index 0000000..dc40249 --- /dev/null +++ b/Server/SystemUsage.cpp @@ -0,0 +1,96 @@ +#include "SystemUsage.h" +#include "BoostLog.h" +#include "NetworkUtility.h" +#include +#include +#include +#include +#include +#include + +SystemUsage::SystemUsage(boost::asio::io_context &ioContext, const std::string &accessToken) + : m_ioContext(ioContext), m_accessToken(accessToken) { + m_timer = std::make_shared(m_ioContext); + // LOG(info) << "access token: " << m_accessToken; +} + +void SystemUsage::start() { + m_timer->expires_after(std::chrono::seconds(10)); + m_timer->async_wait([this](const boost::system::error_code &error) { + if (error) { + LOG(error) << error.message(); + return; + } + auto currentCpuStats = readCpuData(); + int usage = 100.0f * cpuUsage(m_lastCpuStats, currentCpuStats); + publish("yuyun_cpu_usage", usage, "%", "CPU占用率"); + + publish("yuyun_disk_usage", static_cast(100.0f * diskUsage("/")), "%", "磁盘占用率"); + m_lastCpuStats = currentCpuStats; + start(); + }); +} + +void SystemUsage::publish(const std::string_view &deviceName, float value, const std::string_view &unit, + const std::string_view &friendlyName) { + // LOG(info) << "cpu usage: " << usage << "%"; + Http::Client http(m_ioContext, Http::Transparent); + std::ostringstream oss; + oss << "Bearer " << m_accessToken; + http.addRequestField(boost::beast::http::field::authorization, oss.str()); + http.addRequestField(boost::beast::http::field::content_type, "application/json"); + + boost::json::object request; + request["state"] = value; + boost::json::object attributes; + attributes["unit_of_measurement"] = unit; + attributes["friendly_name"] = friendlyName; + request["attributes"] = std::move(attributes); + + oss.str(""); + oss << "/api/states/sensor." << deviceName; + boost::system::error_code error; + auto reply = http.post("iot.amass.fun", "80", oss.str(), boost::json::serialize(request), error); + if (error) { + LOG(error) << error.message(); + } +} + +SystemUsage::CpuStats SystemUsage::readCpuData() { + CpuStats result; + std::ifstream proc_stat("/proc/stat"); + if (proc_stat.good()) { + std::string line; + getline(proc_stat, line); + + unsigned int *stats_p = (unsigned int *)&result; + std::stringstream iss(line); + std::string cpu; + iss >> cpu; + while (iss >> *stats_p) { + stats_p++; + }; + } + proc_stat.close(); + return result; +} + +float SystemUsage::cpuUsage(const CpuStats &first, const CpuStats &second) { + const float active_time = static_cast(second.totalActive() - first.totalActive()); + const float idle_time = static_cast(second.totalIdle() - first.totalIdle()); + const float total_time = active_time + idle_time; + return active_time / total_time; +} + +float SystemUsage::diskUsage(const std::string &disk) { + struct statvfs diskData; + statvfs(disk.c_str(), &diskData); + + auto total = diskData.f_blocks; + auto free = diskData.f_bfree; + auto diff = total - free; + + float result = static_cast(diff) / total; + + return result; +} diff --git a/Server/SystemUsage.h b/Server/SystemUsage.h new file mode 100644 index 0000000..e28f3ed --- /dev/null +++ b/Server/SystemUsage.h @@ -0,0 +1,48 @@ +#ifndef __SYSTEMUSAGE_H__ +#define __SYSTEMUSAGE_H__ + +#include + +/** + * @brief 参考 https://github.com/improvess/cpp-linux-system-stats + * + */ +class SystemUsage { +public: + struct CpuStats { // see http://www.linuxhowtos.org/manpages/5/proc.htm + int user; + int nice; + int system; + int idle; + int iowait; + int irq; + int softirq; + int steal; + int guest; + int guestNice; + + int totalIdle() const { + return idle + iowait; + } + + int totalActive() const { + return user + nice + system + irq + softirq + steal + guest + guestNice; + } + }; + SystemUsage(boost::asio::io_context &ioContext, const std::string &accessToken); + void start(); + +protected: + void publish(const std::string_view &deviceName, float value, const std::string_view &unit, + const std::string_view &friendlyName); + CpuStats readCpuData(); + float cpuUsage(const CpuStats &first, const CpuStats &second); + float diskUsage(const std::string &disk); + +private: + boost::asio::io_context &m_ioContext; + std::shared_ptr m_timer; + std::string m_accessToken; + CpuStats m_lastCpuStats; +}; +#endif // __SYSTEMUSAGE_H__ \ No newline at end of file diff --git a/Server/conf/nginx.conf b/Server/conf/nginx.conf index 4b63a70..029cf09 100644 --- a/Server/conf/nginx.conf +++ b/Server/conf/nginx.conf @@ -89,13 +89,13 @@ http { server { listen 443 ssl; - server_name chatgpt.amass.fun; + server_name iot.amass.fun; client_header_timeout 120s; client_body_timeout 120s; - ssl_certificate cert/chatgpt.amass.fun.pem; - ssl_certificate_key cert/chatgpt.amass.fun.key; + ssl_certificate cert/iot.amass.fun.pem; + ssl_certificate_key cert/iot.amass.fun.key; ssl_session_timeout 5m; #缓存有效期 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #加密算法 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #安全链接可选的加密协议 @@ -115,20 +115,8 @@ http { } server { - listen 443 ssl; - server_name pve.amass.fun; - - client_header_timeout 120s; - client_body_timeout 120s; - client_max_body_size 512m; - - ssl_certificate cert/pve.amass.fun.pem; - ssl_certificate_key cert/pve.amass.fun.key; - ssl_session_timeout 5m; #缓存有效期 - ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #加密算法 - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #安全链接可选的加密协议 - ssl_prefer_server_ciphers on; #使用服务器端的首选算法 - + listen 80; + server_name iot.amass.fun; location / { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; @@ -299,12 +287,6 @@ http { } } - server { - listen 80; - server_name pve.amass.fun; - rewrite ^(.*)$ https://pve.amass.fun$1 permanent; - } - server { listen 80; server_name gitea.amass.fun; diff --git a/resource/build.sh b/resource/build.sh index 36900c2..6c0c35c 100755 --- a/resource/build.sh +++ b/resource/build.sh @@ -14,7 +14,7 @@ function cmake_scan() { -S ${base_path} \ -B ${build_path} \ -DCMAKE_BUILD_TYPE=Debug \ - -DBOOST_ROOT=${libraries_root}/boost_1_84_0 + -DBOOST_ROOT=${libraries_root}/boost_1_85_0 } function build() { @@ -46,6 +46,10 @@ function deploy() { nohup ./HttpServer >logs/HttpServer.log 2>&1 &" } +function init(){ + scp -r /opt/Libraries/boost_1_85_0 root@amass.fun:/opt/Libraries/ +} + function main() { local cmd=$1 shift 1