#include "tunnel_client.hpp" #include #include #include #include "httplib.h" using json = nlohmann::json; using ws_client = websocketpp::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"); }