|
@@ -33,6 +33,8 @@ bool HttpServer::start() {
|
|
|
std::cout << " GET /api/videos - 列出所有视频" << std::endl;
|
|
|
std::cout << " GET /api/timestamps - 列出所有时间戳目录" << std::endl;
|
|
|
std::cout << " GET /api/videos/{timestamp} - 列出指定时间戳目录的视频" << std::endl;
|
|
|
+ std::cout << " GET /api/reports - 列出所有轮询报告" << std::endl;
|
|
|
+ std::cout << " GET /api/report/{timestamp} - 获取指定时间戳的轮询报告" << std::endl;
|
|
|
std::cout << " DELETE /api/video?path={path} - 删除指定视频文件" << std::endl;
|
|
|
std::cout << " DELETE /api/timestamp/{timestamp} - 删除指定时间戳目录及其所有文件" << std::endl;
|
|
|
std::cout << "Web界面:" << std::endl;
|
|
@@ -214,6 +216,10 @@ HttpResponse HttpServer::route_request(const HttpRequest& request) {
|
|
|
return handle_list_videos(request);
|
|
|
} else if (request.path == "/api/timestamps") {
|
|
|
return handle_list_timestamps(request);
|
|
|
+ } else if (request.path == "/api/reports") {
|
|
|
+ return handle_list_reports(request);
|
|
|
+ } else if (request.path.find("/api/report/") == 0) {
|
|
|
+ return handle_get_report(request);
|
|
|
} else if (request.path.find("/api/videos/") == 0) {
|
|
|
return handle_get_video_info(request);
|
|
|
} else if (request.path.find("/videos/") == 0) {
|
|
@@ -794,6 +800,121 @@ HttpResponse HttpServer::handle_static_file(const HttpRequest& request) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+HttpResponse HttpServer::handle_list_reports(const HttpRequest& request) {
|
|
|
+ try {
|
|
|
+ auto timestamps = list_timestamp_directories();
|
|
|
+
|
|
|
+ // 构建JSON响应
|
|
|
+ boost::json::array reports_array;
|
|
|
+ for (const auto& timestamp : timestamps) {
|
|
|
+ std::string report_path = output_directory_ + "/" + timestamp + "/rtsp_report.json";
|
|
|
+
|
|
|
+ // 检查报告文件是否存在
|
|
|
+ if (std::filesystem::exists(report_path)) {
|
|
|
+ // 读取报告文件
|
|
|
+ std::ifstream file(report_path);
|
|
|
+ if (file.is_open()) {
|
|
|
+ std::string content((std::istreambuf_iterator<char>(file)),
|
|
|
+ std::istreambuf_iterator<char>());
|
|
|
+ file.close();
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 解析JSON
|
|
|
+ auto report = boost::json::parse(content);
|
|
|
+ boost::json::object report_info;
|
|
|
+ report_info["timestamp"] = timestamp;
|
|
|
+ report_info["has_report"] = true;
|
|
|
+
|
|
|
+ // 提取摘要信息
|
|
|
+ if (report.is_object()) {
|
|
|
+ auto& obj = report.as_object();
|
|
|
+ if (obj.contains("summary")) {
|
|
|
+ report_info["summary"] = obj.at("summary");
|
|
|
+ }
|
|
|
+ if (obj.contains("report_generated_at")) {
|
|
|
+ report_info["generated_at"] = obj.at("report_generated_at");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ reports_array.push_back(report_info);
|
|
|
+ } catch (...) {
|
|
|
+ // JSON解析失败,跳过
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ boost::json::object result;
|
|
|
+ result["count"] = reports_array.size();
|
|
|
+ result["reports"] = reports_array;
|
|
|
+
|
|
|
+ return HttpResponse(200, "OK", boost::json::serialize(result));
|
|
|
+
|
|
|
+ } catch (const std::exception& e) {
|
|
|
+ boost::json::object error_obj;
|
|
|
+ error_obj["error"] = "Internal Server Error";
|
|
|
+ error_obj["message"] = e.what();
|
|
|
+ return HttpResponse(500, "Internal Server Error", boost::json::serialize(error_obj));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+HttpResponse HttpServer::handle_get_report(const HttpRequest& request) {
|
|
|
+ try {
|
|
|
+ // 从路径中提取时间戳 /api/report/{timestamp}
|
|
|
+ std::string path = request.path;
|
|
|
+ size_t pos = path.find_last_of('/');
|
|
|
+ if (pos == std::string::npos) {
|
|
|
+ boost::json::object error_obj;
|
|
|
+ error_obj["error"] = "Bad Request";
|
|
|
+ error_obj["message"] = "无效的请求路径";
|
|
|
+ return HttpResponse(400, "Bad Request", boost::json::serialize(error_obj));
|
|
|
+ }
|
|
|
+
|
|
|
+ std::string timestamp = path.substr(pos + 1);
|
|
|
+ std::string report_path = output_directory_ + "/" + timestamp + "/rtsp_report.json";
|
|
|
+
|
|
|
+ // 检查文件是否存在
|
|
|
+ if (!std::filesystem::exists(report_path)) {
|
|
|
+ boost::json::object error_obj;
|
|
|
+ error_obj["error"] = "Not Found";
|
|
|
+ error_obj["message"] = "报告文件不存在";
|
|
|
+ error_obj["timestamp"] = timestamp;
|
|
|
+ return HttpResponse(404, "Not Found", boost::json::serialize(error_obj));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 读取报告文件
|
|
|
+ std::ifstream file(report_path);
|
|
|
+ if (!file.is_open()) {
|
|
|
+ boost::json::object error_obj;
|
|
|
+ error_obj["error"] = "Internal Server Error";
|
|
|
+ error_obj["message"] = "无法打开报告文件";
|
|
|
+ return HttpResponse(500, "Internal Server Error", boost::json::serialize(error_obj));
|
|
|
+ }
|
|
|
+
|
|
|
+ std::string content((std::istreambuf_iterator<char>(file)),
|
|
|
+ std::istreambuf_iterator<char>());
|
|
|
+ file.close();
|
|
|
+
|
|
|
+ // 验证JSON格式
|
|
|
+ try {
|
|
|
+ boost::json::parse(content);
|
|
|
+ } catch (const std::exception& e) {
|
|
|
+ boost::json::object error_obj;
|
|
|
+ error_obj["error"] = "Internal Server Error";
|
|
|
+ error_obj["message"] = "报告文件格式错误";
|
|
|
+ return HttpResponse(500, "Internal Server Error", boost::json::serialize(error_obj));
|
|
|
+ }
|
|
|
+
|
|
|
+ return HttpResponse(200, "OK", content);
|
|
|
+
|
|
|
+ } catch (const std::exception& e) {
|
|
|
+ boost::json::object error_obj;
|
|
|
+ error_obj["error"] = "Internal Server Error";
|
|
|
+ error_obj["message"] = e.what();
|
|
|
+ return HttpResponse(500, "Internal Server Error", boost::json::serialize(error_obj));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
HttpResponse HttpServer::generate_index_page() {
|
|
|
std::string html = R"(
|
|
|
<!DOCTYPE html>
|