#include "fastweb.h" #include "../../utils.h" #include #include namespace ngs { namespace fastweb { namespace { // Upstream layout for Fastweb runtime deps: // /opt/lua54, /opt/luarocks // cmake default prefix -> /usr/local (bin/lib/share) // // ylib / HPSocket are already installed by NGS build.sh — do not rebuild them. std::string build_root() { return "/tmp/ngs-fastweb-build"; } std::string lua_prefix() { return "/opt/lua54"; } std::string luarocks_prefix() { return "/opt/luarocks"; } std::string system_prefix() { return "/usr/local"; } std::string version_file() { return join_path(share_dir(), ".ngs_version"); } std::string fastweb_bin() { return join_path(system_prefix(), "bin/fastweb"); } std::string toolchain_env() { const std::string lua = lua_prefix(); return "export LIBRARY_PATH=\"" + join_path(system_prefix(), "lib") + ":/usr/lib/x86_64-linux-gnu:${LIBRARY_PATH:-}\" && " "export LD_LIBRARY_PATH=\"" + join_path(system_prefix(), "lib") + ":" + join_path(lua, "lib") + ":${LD_LIBRARY_PATH:-}\" && " "export LDFLAGS=\"-L" + join_path(system_prefix(), "lib") + " -L/usr/lib/x86_64-linux-gnu ${LDFLAGS:-}\" && " "export CPPFLAGS=\"-I" + join_path(system_prefix(), "include") + " ${CPPFLAGS:-}\" && " "export CPATH=\"" + join_path(system_prefix(), "include") + ":${CPATH:-}\" && " "export CPLUS_INCLUDE_PATH=\"" + join_path(system_prefix(), "include") + ":${CPLUS_INCLUDE_PATH:-}\" && "; } bool write_version_file(const std::string& version, bool debug) { if (!ensure_dir(share_dir())) { return false; } std::ofstream out(version_file()); if (!out) { return false; } out << version << (debug ? " (Debug)" : " (Release)"); return true; } bool lua_installed() { return path_exists(join_path(lua_prefix(), "bin/lua")); } bool luarocks_installed() { return path_exists(join_path(luarocks_prefix(), "bin/luarocks")); } bool fastweb_bin_installed() { return path_exists(fastweb_bin()); } bool ylib_present() { return path_exists("/usr/local/lib/libylib.a") || path_exists("/usr/lib/x86_64-linux-gnu/libylib.a") || path_exists("/usr/local/lib/libylib_d.a") || path_exists("/usr/lib/x86_64-linux-gnu/libylib_d.a"); } bool hpsocket_present() { return path_exists("/usr/local/lib/libhpsocket.a") || path_exists("/usr/lib/x86_64-linux-gnu/libhpsocket.a") || path_exists("/lib/x86_64-linux-gnu/libhpsocket.a"); } bool install_apt_deps() { std::cout << "检查/安装系统依赖...\n"; const char* check = "dpkg -s git unzip wget sqlite3 libsqlite3-dev make gcc g++ cmake " "libssl-dev openssl zlib1g-dev libmimalloc-dev >/dev/null 2>&1"; if (run_cmd(check, false) == 0) { std::cout << "依赖已满足。\n"; return true; } int rc = run_cmd( "sudo apt-get update -y && " "sudo DEBIAN_FRONTEND=noninteractive apt-get install -y " "git unzip wget sqlite3 libsqlite3-dev make gcc g++ cmake " "libssl-dev openssl zlib1g-dev libmimalloc-dev"); return rc == 0; } bool install_lua(const std::string& work) { const std::string prefix = lua_prefix(); std::cout << "安装 Lua 5.4.6 -> " << prefix << "\n"; const std::string tarball = "lua-5.4.6.tar.gz"; if (run_cmd("cd \"" + work + "\" && " "wget -q --show-progress " "https://download.fwlua.com/software/" + tarball + " && " "tar -zxf " + tarball) != 0) { return false; } ensure_dir(prefix); const std::string src = join_path(work, "lua-5.4.6"); return run_cmd( "cd \"" + src + "\" && " "make linux MYCFLAGS=\"-fPIC\" " "MYLDFLAGS=\"-Wl,-rpath," + prefix + "/lib\" && " "make INSTALL_TOP=\"" + prefix + "\" install") == 0; } bool install_luarocks(const std::string& work) { const std::string prefix = luarocks_prefix(); const std::string lua = lua_prefix(); std::cout << "安装 LuaRocks 3.9.1 -> " << prefix << "\n"; const std::string tarball = "luarocks-3.9.1.tar.gz"; if (run_cmd("cd \"" + work + "\" && " "wget -q --show-progress " "https://download.fwlua.com/software/" + tarball + " && " "tar -zxf " + tarball) != 0) { return false; } ensure_dir(prefix); const std::string src = join_path(work, "luarocks-3.9.1"); return run_cmd( "cd \"" + src + "\" && " "./configure --with-lua=\"" + lua + "\" " "--lua-suffix=5.4 --versioned-rocks-dir " "--prefix=\"" + prefix + "\" && " "make && make install") == 0; } // Upstream Linux CMakeLists hardcodes ylib_d; fix to match build type. bool patch_ylib_link(const std::string& repo, bool debug) { const std::string ylib_name = debug ? "ylib_d" : "ylib"; std::cout << "修正 Linux 链接库: " << ylib_name << "\n"; return run_cmd( "sed -i " "-e 's/^[[:blank:]]*ylib_d[[:blank:]]*$/\\t\\t\\t" + ylib_name + "/' " "-e 's/^[[:blank:]]*ylib[[:blank:]]*$/\\t\\t\\t" + ylib_name + "/' " "\"" + join_path(repo, "CMakeLists.txt") + "\"") == 0; } bool build_fastweb(bool debug) { const std::string root = build_root(); const std::string repo = join_path(root, "fastweb"); if (!is_dir(repo)) { std::cout << "克隆 fastweb...\n"; if (run_cmd("cd \"" + root + "\" && " "git clone https://git.ddtalk.net/1585346868/fastweb.git") != 0) { return false; } } // Never run fastweb's own build.sh — it re-clones/rebuilds ylib. // NGS already provides system ylib + HPSocket; only build fastweb itself. if (!patch_ylib_link(repo, debug)) { std::cerr << "修正 ylib 链接失败。\n"; return false; } remove_path(join_path(repo, "build")); const std::string build_type = debug ? "Debug" : "Release"; std::cout << "编译安装 fastweb -> " << system_prefix() << " (" << build_type << ")...\n"; std::cout << " (不执行 fastweb 自带 build.sh;直接 cmake/make/make install)\n"; return run_cmd( toolchain_env() + "cd \"" + repo + "\" && " "mkdir -p build && cd build && " "cmake .. -DCMAKE_BUILD_TYPE=" + build_type + " && " "make -j\"$(nproc)\" && make install") == 0; } void remove_legacy_ngs_install() { remove_path(join_path(software_root(), "fastweb")); remove_path(join_path(software_root(), "3rdparty")); remove_path(join_path(software_root(), "lua54")); remove_path(join_path(software_root(), "luarocks")); remove_path(join_path(software_root(), ".build/fastweb")); } } // namespace std::string install_dir() { return system_prefix(); } std::string bin_path() { return fastweb_bin(); } std::string share_dir() { return join_path(system_prefix(), "share/fastweb"); } bool is_installed() { return fastweb_bin_installed(); } std::string installed_version() { const std::string path = version_file(); if (path_exists(path)) { std::ifstream in(path); std::string ver; if (in && std::getline(in, ver) && !ver.empty()) { return ver; } } return is_installed() ? std::string(kDefaultVersion) : ""; } void show_status() { std::cout << "安装前缀: " << install_dir() << "\n"; std::cout << "构建目录: " << build_root() << "\n"; std::cout << "可执行文件: " << fastweb_bin() << "\n"; std::cout << "模板目录: " << share_dir() << "\n"; std::cout << "Lua: " << lua_prefix() << (lua_installed() ? " [已安装]" : " [未安装]") << "\n"; std::cout << "LuaRocks: " << luarocks_prefix() << (luarocks_installed() ? " [已安装]" : " [未安装]") << "\n"; std::cout << "ylib: " << (ylib_present() ? "[系统已有]" : "[缺失,请先 ./build.sh]") << "\n"; std::cout << "HPSocket: " << (hpsocket_present() ? "[系统已有]" : "[缺失,请先 ./build.sh]") << "\n"; if (is_installed()) { std::cout << "状态: 已安装\n"; std::cout << "版本: " << installed_version() << "\n"; } else { std::cout << "状态: 未安装\n"; } } bool install(bool debug) { if (lua_installed() && luarocks_installed() && is_installed()) { std::cout << "Fastweb 及相关组件已安装。\n"; std::cout << "如需重装,请先卸载。\n"; return false; } if (!ylib_present() || !hpsocket_present()) { std::cerr << "缺少系统依赖 ylib / HPSocket。\n" << "请先在 NGS 根目录执行 ./build.sh 完成初始化。\n"; return false; } std::cout << "检测到系统已安装 ylib / HPSocket,跳过重复编译。\n"; std::cout << "清理并创建构建目录: " << build_root() << "\n"; remove_path(build_root()); if (!ensure_dir(build_root())) { std::cerr << "无法创建构建目录。\n"; return false; } if (!install_apt_deps()) { std::cerr << "系统依赖安装失败。\n"; return false; } if (!lua_installed()) { if (!install_lua(build_root())) { std::cerr << "Lua 安装失败。\n"; return false; } } else { std::cout << "Lua 已安装,跳过。\n"; } if (!luarocks_installed()) { if (!install_luarocks(build_root())) { std::cerr << "LuaRocks 安装失败。\n"; return false; } } else { std::cout << "LuaRocks 已安装,跳过。\n"; } if (!build_fastweb(debug)) { std::cerr << "fastweb 编译安装失败。\n"; return false; } write_version_file(kDefaultVersion, debug); remove_legacy_ngs_install(); std::cout << "\nFastweb " << kDefaultVersion << " 安装成功。\n"; log_info(std::string("fastweb installed version=") + kDefaultVersion + " debug=" + (debug ? "1" : "0") + " prefix=/usr/local"); std::cout << "安装前缀: " << install_dir() << "\n"; std::cout << "可执行文件: " << fastweb_bin() << "\n"; std::cout << "模板目录: " << share_dir() << "\n"; return true; } bool uninstall() { const bool has_fw = is_installed() || is_dir(share_dir()); const bool has_lua = lua_installed() || is_dir(lua_prefix()); const bool has_rocks = luarocks_installed() || is_dir(luarocks_prefix()); const bool has_build = is_dir(build_root()); const bool has_legacy = is_dir(join_path(software_root(), "fastweb")) || is_dir(join_path(software_root(), "3rdparty")); if (!has_fw && !has_lua && !has_rocks && !has_build && !has_legacy) { std::cout << "Fastweb 未安装,无需卸载。\n"; return true; } std::cout << "卸载 Fastweb(保留系统 ylib / HPSocket)...\n"; remove_path(fastweb_bin()); remove_path(join_path(system_prefix(), "lib/libfastwebcore.so")); remove_path(share_dir()); remove_path(join_path(system_prefix(), "include/fastweb")); remove_path(join_path(system_prefix(), "include/sol")); remove_path(lua_prefix()); remove_path(luarocks_prefix()); remove_path(build_root()); remove_legacy_ngs_install(); std::cout << "Fastweb 已卸载。\n"; log_info("fastweb uninstalled"); return true; } void menu() { while (true) { print_header("软件管理 - Fastweb"); show_status(); std::cout << "\n"; std::cout << " 1) 安装 Fastweb (Release)\n"; std::cout << " 2) 安装 Fastweb (Debug)\n"; std::cout << " 3) 卸载 Fastweb\n"; std::cout << " 0) 返回上级\n\n"; int choice = read_choice("请选择: "); switch (choice) { case 1: case 2: { const bool debug = (choice == 2); std::cout << "\n确认安装 Fastweb " << kDefaultVersion << "\n Lua/LuaRocks -> /opt" << "\n Fastweb -> /usr/local (cmake/make/make install)" << "\n ylib/HPSocket 使用 NGS 已安装的系统库" << " [" << (debug ? "Debug" : "Release") << "] ? [y/N]: "; std::string confirm; std::getline(std::cin, confirm); if (confirm == "y" || confirm == "Y") { install(debug); } else { std::cout << "已取消。\n"; } pause(); break; } case 3: { std::cout << "\n确认卸载 Fastweb(含 /opt/lua54、/opt/luarocks," "不删除 ylib/HPSocket)? [y/N]: "; std::string confirm; std::getline(std::cin, confirm); if (confirm == "y" || confirm == "Y") { uninstall(); } else { std::cout << "已取消。\n"; } pause(); break; } case 0: return; default: std::cout << "无效选项。\n"; pause(); break; } } } } // namespace fastweb } // namespace ngs