sweeper_video/src/tunnel_client.cpp

124 lines
3.3 KiB
C++
Raw Normal View History

2026-01-21 14:02:52 +08:00
#include "tunnel_client.hpp"
#include <nlohmann/json.hpp>
#include <websocketpp/client.hpp>
#include <websocketpp/config/asio_no_tls_client.hpp>
#include "httplib.h"
using json = nlohmann::json;
using ws_client = websocketpp::client<websocketpp::config::asio_client>;
TunnelClient::TunnelClient(const std::string& vid, const std::string& server_ws_url, int local_http_port)
: vid_(vid), ws_url_(server_ws_url + "?vid=" + vid), local_port_(local_http_port)
{
}
void TunnelClient::start()
{
running_ = true;
th_ = std::thread(&TunnelClient::run_loop, this);
}
void TunnelClient::stop()
{
running_ = false;
if (th_.joinable()) th_.join();
}
std::string TunnelClient::handle_local_http(const std::string& method, const std::string& path, const std::string& body)
{
httplib::Client cli("127.0.0.1", local_port_);
cli.set_read_timeout(10, 0);
httplib::Result res;
if (method == "GET")
{
res = cli.Get(path.c_str());
}
else if (method == "POST")
{
res = cli.Post(path.c_str(), body, "application/json");
}
else
{
2026-01-21 14:15:46 +08:00
return json({{"status", 405}, {"body", "unsupported method"}}).dump();
2026-01-21 14:02:52 +08:00
}
if (!res)
{
2026-01-21 14:15:46 +08:00
return json({{"status", 500}, {"body", "local http error"}}).dump();
2026-01-21 14:02:52 +08:00
}
2026-01-21 14:15:46 +08:00
return json({{"status", res->status}, {"body", res->body}}).dump();
2026-01-21 14:02:52 +08:00
}
void TunnelClient::run_loop()
{
ws_client c;
2026-01-21 14:15:46 +08:00
c.clear_access_channels(websocketpp::log::alevel::all);
2026-01-21 14:02:52 +08:00
c.init_asio();
websocketpp::connection_hdl hdl;
2026-01-21 14:15:46 +08:00
// ----------------------- WebSocket 回调 -----------------------
2026-01-21 14:02:52 +08:00
c.set_open_handler(
[&](websocketpp::connection_hdl h)
{
hdl = h;
printf("[Tunnel] Connected to server\n");
});
c.set_close_handler([&](websocketpp::connection_hdl) { printf("[Tunnel] Disconnected from server\n"); });
c.set_message_handler(
[&](websocketpp::connection_hdl, ws_client::message_ptr msg)
{
2026-01-21 14:15:46 +08:00
try
{
std::string payload = msg->get_payload();
json req = json::parse(payload);
std::string req_id = req["req_id"];
std::string method = req["method"];
std::string path = req["path"];
std::string body = req.value("body", "");
std::string local_result = handle_local_http(method, path, body);
json resp;
resp["req_id"] = req_id;
resp["resp"] = json::parse(local_result);
c.send(hdl, resp.dump(), websocketpp::frame::opcode::text);
}
catch (...)
{
printf("[Tunnel] JSON or HTTP error\n");
}
2026-01-21 14:02:52 +08:00
});
2026-01-21 14:15:46 +08:00
// ----------------------- 建立连接 -----------------------
2026-01-21 14:02:52 +08:00
websocketpp::lib::error_code ec;
auto conn = c.get_connection(ws_url_, ec);
if (ec)
{
printf("[Tunnel] Connection init failed: %s\n", ec.message().c_str());
return;
}
c.connect(conn);
2026-01-21 14:15:46 +08:00
// ----------------------- 主循环 -----------------------
2026-01-21 14:02:52 +08:00
while (running_)
{
2026-01-21 14:15:46 +08:00
// 处理一次事件
c.run_one();
// 如果连接停止(断线、错误等)——退出 loop
if (c.stopped()) break;
2026-01-21 14:02:52 +08:00
}
printf("[Tunnel] Loop exit\n");
}