新增反向隧道代理

This commit is contained in:
cxh 2026-01-21 14:02:52 +08:00
parent 69f8196872
commit 7da50d33c8
3 changed files with 164 additions and 0 deletions

25
include/tunnel_client.hpp Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include <atomic>
#include <string>
#include <thread>
class TunnelClient
{
public:
TunnelClient(const std::string& vid, const std::string& server_ws_url, int local_http_port);
void start();
void stop();
private:
void run_loop();
std::string handle_local_http(const std::string& method, const std::string& path, const std::string& body);
private:
std::string vid_;
std::string ws_url_;
int local_port_;
std::atomic<bool> running_{false};
std::thread th_;
};

View File

@ -12,8 +12,10 @@
#include "record_manager.hpp"
#include "rtmp_manager.hpp"
#include "serial_AT.hpp"
#include "tunnel_client.hpp"
std::atomic<bool> g_running(true);
TunnelClient* g_tunnel_client = nullptr;
static void signal_handler(int signum)
{
@ -62,6 +64,18 @@ int main()
LOG_INFO("[MAIN] Starting all record streams...");
RTMPManager::start_all();
{
std::string vid = g_app_config.vehicle_id;
int local_http_port = 2980;
std::string tunnel_server = "ws://36.153.162.171:2088/tunnel";
g_tunnel_client = new TunnelClient(vid, tunnel_server, local_http_port);
g_tunnel_client->start();
LOG_INFO("[MAIN] TunnelClient started: %s", tunnel_server.c_str());
}
// 启动 MQTT 线程
std::thread mqtt_thread(
[]
@ -84,6 +98,14 @@ int main()
// ---------- 退出清理 ----------
LOG_INFO("[MAIN] Shutdown requested. Stopping RTMP streams...");
if (g_tunnel_client)
{
g_tunnel_client->stop();
delete g_tunnel_client;
g_tunnel_client = nullptr;
LOG_INFO("[MAIN] TunnelClient stopped.");
}
// 停止 RecordManager 自动扫描线程
if (g_record_manager) g_record_manager->stopAutoScan();

117
src/tunnel_client.cpp Normal file
View File

@ -0,0 +1,117 @@
#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
{
json err = {{"status", 405}, {"body", "unsupported method"}};
return err.dump();
}
if (!res)
{
json err = {{"status", 500}, {"body", "local http error"}};
return err.dump();
}
json resp = {{"status", res->status}, {"body", res->body}};
return resp.dump();
}
void TunnelClient::run_loop()
{
ws_client c;
c.init_asio();
websocketpp::connection_hdl hdl;
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)
{
// 服务器传来的 HTTP 请求(JSON)
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", "");
// 转发给本地 HTTP 服务
std::string result = handle_local_http(method, path, body);
// 包装 response
json resp;
resp["req_id"] = req_id;
resp["resp"] = json::parse(result);
// 发送回服务器
c.send(hdl, resp.dump(), websocketpp::frame::opcode::text);
});
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);
while (running_)
{
c.run_once();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
printf("[Tunnel] Loop exit\n");
}