CollisionAvoidance/src/network/HTTPDataSource.cpp

221 lines
7.0 KiB
C++
Raw Blame History

#include "HTTPDataSource.h"
#include "utils/Logger.h"
#include <nlohmann/json.hpp>
#include <regex>
using json = nlohmann::json;
HTTPDataSource::HTTPDataSource(const ConnectionConfig& config)
: host_(config.host)
, port_(std::to_string(config.port)) {
// 设置坐标转换器的参考点(浦东机场坐标)
coordinateConverter_.setReferencePoint(31.143494, 121.805214);
}
HTTPDataSource::~HTTPDataSource() {
disconnect();
}
std::optional<VehicleData> HTTPDataSource::getData() {
if (dataCache_.empty()) {
Logger::debug("Data cache is empty, attempting to fetch new data");
if (!fetchData()) {
Logger::error("Failed to fetch new data");
return std::nullopt;
}
}
if (dataCache_.empty()) {
Logger::debug("No data available after fetch");
return std::nullopt;
}
auto data = std::move(dataCache_.front());
dataCache_.pop();
Logger::debug("Returning vehicle: ", data.id);
return data;
}
bool HTTPDataSource::connect() {
try {
Logger::debug("Connecting to ", host_, ":", port_);
auto resolver = asio::ip::tcp::resolver(io_context_);
auto endpoints = resolver.resolve(host_, port_);
socket_ = std::make_unique<asio::ip::tcp::socket>(io_context_);
asio::connect(*socket_, endpoints);
Logger::info("Connected to server");
return true;
}
catch (const std::exception& e) {
Logger::error("Connection error: ", e.what());
return false;
}
}
void HTTPDataSource::disconnect() {
if (socket_ && socket_->is_open()) {
boost::system::error_code ec;
socket_->close(ec);
}
socket_.reset();
}
bool HTTPDataSource::fetchData() {
if (!connect()) {
return false;
}
// 构造 HTTP 请求
std::stringstream request;
request << "GET /api/vehicles HTTP/1.1\r\n"
<< "Host: " << host_ << "\r\n"
<< "Connection: close\r\n"
<< "Accept: application/json\r\n"
<< "\r\n";
// 发送请求
boost::system::error_code ec;
asio::write(*socket_, asio::buffer(request.str()), ec);
if (ec) {
Logger::error("Failed to send request: ", ec.message());
disconnect();
return false;
}
// <20><>取响应
std::string response;
if (!readResponse(response)) {
disconnect();
return false;
}
// 解析数据
std::vector<VehicleData> vehicles;
if (parseResponse(response, vehicles)) {
std::lock_guard<std::mutex> lock(cacheMutex_);
for (auto& vehicle : vehicles) {
vehicle.updateLocalPosition(coordinateConverter_);
dataCache_.push(vehicle);
}
Logger::info("Cached ", vehicles.size(), " vehicles");
}
disconnect();
return !vehicles.empty();
}
bool HTTPDataSource::readResponse(std::string& response) {
try {
Logger::debug("Reading response");
asio::streambuf response_buf;
boost::system::error_code ec;
// 读取响应头
size_t header_length = asio::read_until(*socket_, response_buf, "\r\n\r\n", ec);
if (ec) {
Logger::error("Failed to read headers: ", ec.message());
return false;
}
// 提取响应头
std::string header{asio::buffers_begin(response_buf.data()),
asio::buffers_begin(response_buf.data()) + header_length};
Logger::debug("Header received:\n", header);
// 解析 Content-Length
std::regex content_length_regex("Content-Length: (\\d+)");
std::smatch matches;
if (!std::regex_search(header, matches, content_length_regex)) {
Logger::error("No Content-Length found");
return false;
}
size_t content_length = std::stoul(matches[1]);
Logger::debug("Content-Length: ", content_length);
// 读取响应体
std::string body;
size_t total_read = 0;
while (total_read < content_length) {
std::vector<char> buf(1024);
size_t to_read = std::min(buf.size(), content_length - total_read);
size_t bytes_read = socket_->read_some(asio::buffer(buf, to_read), ec);
if (ec) {
Logger::error("Error reading body: ", ec.message());
return false;
}
body.append(buf.data(), bytes_read);
total_read += bytes_read;
Logger::debug("Read ", total_read, " of ", content_length, " bytes");
}
response = body;
Logger::info("Successfully read complete response");
return true;
}
catch (const std::exception& e) {
Logger::error("Exception in readResponse: ", e.what());
return false;
}
}
bool HTTPDataSource::parseResponse(const std::string& response, std::vector<VehicleData>& vehicles) {
try {
Logger::debug("Parsing response data, length: ", response.length());
auto j = json::parse(response);
if (!j.contains("vehicles") || !j["vehicles"].is_array()) {
Logger::error("Invalid response format: missing or invalid 'vehicles' array");
return false;
}
for (const auto& vehicle : j["vehicles"]) {
try {
VehicleData data;
// 解析基本信息
data.id = vehicle["id"].get<std::string>();
std::string typeStr = vehicle["type"].get<std::string>();
data.type = (typeStr == "AIRCRAFT") ? VehicleType::AIRCRAFT : VehicleType::VEHICLE;
// 解析地理坐标
data.geo.latitude = vehicle["position"]["latitude"].get<double>();
data.geo.longitude = vehicle["position"]["longitude"].get<double>();
// 解析其他属性
data.heading = vehicle["heading"].get<double>();
data.timestamp = vehicle["timestamp"].get<uint64_t>();
if (data.type == VehicleType::AIRCRAFT) {
data.altitude = vehicle["altitude"].get<double>();
}
vehicles.push_back(data);
Logger::debug("Parsed vehicle: ", data.id,
", type: ", typeStr,
", pos: (", data.geo.latitude, ",", data.geo.longitude, ")");
}
catch (const std::exception& e) {
Logger::error("Error parsing vehicle data: ", e.what());
continue;
}
}
Logger::info("Successfully parsed ", vehicles.size(), " vehicles");
return !vehicles.empty();
}
catch (const std::exception& e) {
Logger::error("Error parsing response: ", e.what());
return false;
}
}
bool HTTPDataSource::isAvailable() const {
return socket_ && socket_->is_open();
}