#include #include "crow.h" #include #include "json/json.h" #include #include #include #include #include #include #include #include #include "../pPowerManger/SQLiteDB.h" #include "../pPowerManger/pmSysvariable.h" #include #include "DBImage.h" using namespace std; // 定义全局变量 ccuState ccustate; StateData stateData; mutex wsMutex; vector wsConnections; shared_ptr db; shared_ptr moosClient; shared_ptr dbImage; bool bContinue = true; // WebSocket消息处理 void sendStateUpdate() { crow::json::wvalue msg; string time; { lock_guard lock(wsMutex); db->getStateData(stateData, time); } // 基本状态信息 msg["state"] = { {"time", time}, {"state_id", stateData.state_id}, {"state_name", stateData.state_name}, {"event", stateData.event}, {"event_id", stateData.event_id}, {"fault_code", stateData.fault_code}, {"note", stateData.note} }; // 数据库状态信息 msg["db_status"] = { {"connected", db->isDatabaseConnected("/home/zjk/project/H100/H100PowerManger/data", "power_data.db")}, {"database", db->getDBPatch()}, {"size", db->getDatabaseSize()} }; // MOOS数据库状态信息 msg["moos_db_status"] = { {"connected", moosClient->IsConnected()}, {"host", "localhost"}, {"port", 9000} }; // 进程详细信息 { lock_guard lock(wsMutex); STRING_LIST processes; dbImage->GetProcesses(processes); crow::json::wvalue::list processList; for(const auto& proc : processes) { STRING_LIST subs, pubs; if(dbImage->GetProcInfo(proc, subs, pubs)) { crow::json::wvalue processInfo; processInfo["name"] = proc; std::vector subs_vec(subs.begin(), subs.end()); std::vector pubs_vec(pubs.begin(), pubs.end()); processInfo["subscribed"] = subs_vec; processInfo["published"] = pubs_vec; processList.push_back(std::move(processInfo)); } } msg["processes"] = { {"count", processes.size()}, {"list", std::move(processList)} }; } // 数据库变量信息 { lock_guard lock(wsMutex); int varCount = dbImage->GetNumVariables(); crow::json::wvalue::list varList; // 遍历所有变量 for(int i = 0; i < varCount; i++) { CDBImage::CVar var; if(dbImage->Get(var, i)) { varList.push_back({ {"name", var.GetName()}, {"value", var.GetValue()}, {"time", var.GetTime()}, {"type", var.GetType()}, {"source", var.GetSource()} }); } } msg["variables"] = { {"count", varCount}, {"data", std::move(varList)} // 包含所有变量的数组 }; } // 发送WebSocket消息 { lock_guard lock(wsMutex); for(auto conn : wsConnections) { conn->send_text(msg.dump()); } } } // 订阅MOOS变量 bool FetchLoop(MOOS::MOOSAsyncCommClient* comms, CDBImage* m_DBImage) { int nCounts = 0; while(true) // 外部需要控制循环退出条件 { if(comms->IsConnected()) { // 每5次循环获取一次进程摘要 if(nCounts++ % 5 == 0) { MOOSMSG_LIST procMail; if(comms->ServerRequest("PROC_SUMMARY", procMail)) { m_DBImage->SetProcInfo(procMail); // 打印进程信息 // STRING_LIST processes; // m_DBImage->GetProcesses(processes); // std::cout << "Active processes: " << processes.size() << std::endl; } } // 每次循环都获取数据库摘要 MOOSMSG_LIST dbMail; if(comms->ServerRequest("ALL", dbMail)) { m_DBImage->Set(dbMail); // 打印数据库变量信息 int varCount = m_DBImage->GetNumVariables(); // std::cout << "Database variables: " << varCount << std::endl; // 打印最近更新的变量 if(varCount > 0) { CDBImage::CVar lastVar; if(m_DBImage->Get(lastVar, varCount-1)) { // std::cout << "Last updated variable: " // << lastVar.GetName() << " = " // << lastVar.GetValue() << std::endl; } } } } // 保持大约4Hz的频率 MOOSPause(250); } return true; } int main() { crow::SimpleApp app; db = make_shared("/home/zjk/project/H100/H100PowerManger/data/power_data.db"); moosClient = make_shared(); dbImage = make_shared(); moosClient->Run("localhost", 9000, "appPowerMangerWebUI"); // WebSocket路由 CROW_WEBSOCKET_ROUTE(app, "/ws/state") .onopen([&](crow::websocket::connection& conn){ lock_guard lock(wsMutex); wsConnections.push_back(&conn); cout << "New WebSocket connection" << endl; }) .onclose([&](crow::websocket::connection& conn, const string& /*reason*/, uint16_t /*code*/){ lock_guard lock(wsMutex); wsConnections.erase( remove(wsConnections.begin(), wsConnections.end(), &conn), wsConnections.end()); cout << "WebSocket connection closed" << endl; }) .onmessage([&](crow::websocket::connection& conn, const string& data, bool is_binary){ cout << "Received WebSocket message: " << data << endl; }); // 状态更新定时器 thread([](){ while(true) { sendStateUpdate(); this_thread::sleep_for(chrono::seconds(1)); } }).detach(); //MOOS数据库更新定时器 std::thread fetchThread([&](){ while(bContinue) { FetchLoop(moosClient.get(), dbImage.get()); } }); // 绑定主页路由 CROW_ROUTE(app, "/")([]() { auto page = crow::mustache::load_text("index.html"); return page; }); // MOOS通知API CROW_ROUTE(app, "/api/moos-notify") .methods("POST"_method) ([](const crow::request& req) { auto json = crow::json::load(req.body); if (!json) { return crow::response(400, "Invalid JSON"); } string var = json["var"].s(); string key = json["key"].s(); if (var.empty() || key.empty()) { return crow::response(400, "Var and Key are required"); } try { moosClient->Notify(var, key); return crow::response(200, "{\"success\":true}"); } catch (const exception& e) { return crow::response(500, crow::json::wvalue{{"success", false}, {"message", e.what()}}.dump()); } }); // 下载数据库API CROW_ROUTE(app, "/api/download-db") ([]() { const std::string dbPath = "/home/zjk/project/H100/H100PowerManger/data/power_data.db"; const size_t chunkSize = 4096; // 4KB chunks std::ifstream file(dbPath, std::ios::binary | std::ios::ate); if (!file) { return crow::response(404, "Database file not found"); } // 获取文件大小 std::streamsize fileSize = file.tellg(); file.seekg(0, std::ios::beg); if (fileSize == 0) { return crow::response(500, "Database file is empty"); } // 创建响应 crow::response res; res.code = 200; res.set_header("Content-Type", "application/octet-stream"); res.set_header("Content-Disposition", "attachment; filename=power_data.db"); res.set_header("Content-Length", std::to_string(fileSize)); try { // 分块读取和写入文件 auto buffer = std::make_unique(chunkSize); size_t totalSent = 0; while (totalSent < fileSize) { size_t remaining = fileSize - totalSent; size_t readSize = std::min(remaining, chunkSize); file.read(buffer.get(), readSize); if (file.gcount() <= 0) break; res.write(std::string(buffer.get(), file.gcount())); totalSent += file.gcount(); } file.close(); return res; } catch (const std::exception& e) { file.close(); return crow::response(500, std::string("Download failed: ") + e.what()); } }); // 启动服务器 app.port(18080) .multithreaded() .concurrency(16) .run(); return 0; }