fastweb.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. #include "fastweb.h"
  2. #include "../../utils.h"
  3. #include <iostream>
  4. #include <fstream>
  5. namespace ngs {
  6. namespace fastweb {
  7. namespace {
  8. // Upstream layout for Fastweb runtime deps:
  9. // /opt/lua54, /opt/luarocks
  10. // cmake default prefix -> /usr/local (bin/lib/share)
  11. //
  12. // ylib / HPSocket are already installed by NGS build.sh — do not rebuild them.
  13. std::string build_root() {
  14. return "/tmp/ngs-fastweb-build";
  15. }
  16. std::string lua_prefix() {
  17. return "/opt/lua54";
  18. }
  19. std::string luarocks_prefix() {
  20. return "/opt/luarocks";
  21. }
  22. std::string system_prefix() {
  23. return "/usr/local";
  24. }
  25. std::string version_file() {
  26. return join_path(share_dir(), ".ngs_version");
  27. }
  28. std::string fastweb_bin() {
  29. return join_path(system_prefix(), "bin/fastweb");
  30. }
  31. std::string toolchain_env() {
  32. const std::string lua = lua_prefix();
  33. return "export LIBRARY_PATH=\"" + join_path(system_prefix(), "lib") +
  34. ":/usr/lib/x86_64-linux-gnu:${LIBRARY_PATH:-}\" && "
  35. "export LD_LIBRARY_PATH=\"" + join_path(system_prefix(), "lib") + ":" +
  36. join_path(lua, "lib") + ":${LD_LIBRARY_PATH:-}\" && "
  37. "export LDFLAGS=\"-L" + join_path(system_prefix(), "lib") +
  38. " -L/usr/lib/x86_64-linux-gnu ${LDFLAGS:-}\" && "
  39. "export CPPFLAGS=\"-I" + join_path(system_prefix(), "include") +
  40. " ${CPPFLAGS:-}\" && "
  41. "export CPATH=\"" + join_path(system_prefix(), "include") +
  42. ":${CPATH:-}\" && "
  43. "export CPLUS_INCLUDE_PATH=\"" + join_path(system_prefix(), "include") +
  44. ":${CPLUS_INCLUDE_PATH:-}\" && ";
  45. }
  46. bool write_version_file(const std::string& version, bool debug) {
  47. if (!ensure_dir(share_dir())) {
  48. return false;
  49. }
  50. std::ofstream out(version_file());
  51. if (!out) {
  52. return false;
  53. }
  54. out << version << (debug ? " (Debug)" : " (Release)");
  55. return true;
  56. }
  57. bool lua_installed() {
  58. return path_exists(join_path(lua_prefix(), "bin/lua"));
  59. }
  60. bool luarocks_installed() {
  61. return path_exists(join_path(luarocks_prefix(), "bin/luarocks"));
  62. }
  63. bool fastweb_bin_installed() {
  64. return path_exists(fastweb_bin());
  65. }
  66. bool ylib_present() {
  67. return path_exists("/usr/local/lib/libylib.a") ||
  68. path_exists("/usr/lib/x86_64-linux-gnu/libylib.a") ||
  69. path_exists("/usr/local/lib/libylib_d.a") ||
  70. path_exists("/usr/lib/x86_64-linux-gnu/libylib_d.a");
  71. }
  72. bool hpsocket_present() {
  73. return path_exists("/usr/local/lib/libhpsocket.a") ||
  74. path_exists("/usr/lib/x86_64-linux-gnu/libhpsocket.a") ||
  75. path_exists("/lib/x86_64-linux-gnu/libhpsocket.a");
  76. }
  77. bool install_apt_deps() {
  78. std::cout << "检查/安装系统依赖...\n";
  79. const char* check =
  80. "dpkg -s git unzip wget sqlite3 libsqlite3-dev make gcc g++ cmake "
  81. "libssl-dev openssl zlib1g-dev libmimalloc-dev >/dev/null 2>&1";
  82. if (run_cmd(check, false) == 0) {
  83. std::cout << "依赖已满足。\n";
  84. return true;
  85. }
  86. int rc = run_cmd(
  87. "sudo apt-get update -y && "
  88. "sudo DEBIAN_FRONTEND=noninteractive apt-get install -y "
  89. "git unzip wget sqlite3 libsqlite3-dev make gcc g++ cmake "
  90. "libssl-dev openssl zlib1g-dev libmimalloc-dev");
  91. return rc == 0;
  92. }
  93. bool install_lua(const std::string& work) {
  94. const std::string prefix = lua_prefix();
  95. std::cout << "安装 Lua 5.4.6 -> " << prefix << "\n";
  96. const std::string tarball = "lua-5.4.6.tar.gz";
  97. if (run_cmd("cd \"" + work + "\" && "
  98. "wget -q --show-progress "
  99. "https://download.fwlua.com/software/" + tarball + " && "
  100. "tar -zxf " + tarball) != 0) {
  101. return false;
  102. }
  103. ensure_dir(prefix);
  104. const std::string src = join_path(work, "lua-5.4.6");
  105. return run_cmd(
  106. "cd \"" + src + "\" && "
  107. "make linux MYCFLAGS=\"-fPIC\" "
  108. "MYLDFLAGS=\"-Wl,-rpath," + prefix + "/lib\" && "
  109. "make INSTALL_TOP=\"" + prefix + "\" install") == 0;
  110. }
  111. bool install_luarocks(const std::string& work) {
  112. const std::string prefix = luarocks_prefix();
  113. const std::string lua = lua_prefix();
  114. std::cout << "安装 LuaRocks 3.9.1 -> " << prefix << "\n";
  115. const std::string tarball = "luarocks-3.9.1.tar.gz";
  116. if (run_cmd("cd \"" + work + "\" && "
  117. "wget -q --show-progress "
  118. "https://download.fwlua.com/software/" + tarball + " && "
  119. "tar -zxf " + tarball) != 0) {
  120. return false;
  121. }
  122. ensure_dir(prefix);
  123. const std::string src = join_path(work, "luarocks-3.9.1");
  124. return run_cmd(
  125. "cd \"" + src + "\" && "
  126. "./configure --with-lua=\"" + lua + "\" "
  127. "--lua-suffix=5.4 --versioned-rocks-dir "
  128. "--prefix=\"" + prefix + "\" && "
  129. "make && make install") == 0;
  130. }
  131. // Upstream Linux CMakeLists hardcodes ylib_d; fix to match build type.
  132. bool patch_ylib_link(const std::string& repo, bool debug) {
  133. const std::string ylib_name = debug ? "ylib_d" : "ylib";
  134. std::cout << "修正 Linux 链接库: " << ylib_name << "\n";
  135. return run_cmd(
  136. "sed -i "
  137. "-e 's/^[[:blank:]]*ylib_d[[:blank:]]*$/\\t\\t\\t" + ylib_name + "/' "
  138. "-e 's/^[[:blank:]]*ylib[[:blank:]]*$/\\t\\t\\t" + ylib_name + "/' "
  139. "\"" + join_path(repo, "CMakeLists.txt") + "\"") == 0;
  140. }
  141. bool build_fastweb(bool debug) {
  142. const std::string root = build_root();
  143. const std::string repo = join_path(root, "fastweb");
  144. if (!is_dir(repo)) {
  145. std::cout << "克隆 fastweb...\n";
  146. if (run_cmd("cd \"" + root + "\" && "
  147. "git clone https://git.ddtalk.net/1585346868/fastweb.git") != 0) {
  148. return false;
  149. }
  150. }
  151. // Never run fastweb's own build.sh — it re-clones/rebuilds ylib.
  152. // NGS already provides system ylib + HPSocket; only build fastweb itself.
  153. if (!patch_ylib_link(repo, debug)) {
  154. std::cerr << "修正 ylib 链接失败。\n";
  155. return false;
  156. }
  157. remove_path(join_path(repo, "build"));
  158. const std::string build_type = debug ? "Debug" : "Release";
  159. std::cout << "编译安装 fastweb -> " << system_prefix()
  160. << " (" << build_type << ")...\n";
  161. std::cout << " (不执行 fastweb 自带 build.sh;直接 cmake/make/make install)\n";
  162. return run_cmd(
  163. toolchain_env() +
  164. "cd \"" + repo + "\" && "
  165. "mkdir -p build && cd build && "
  166. "cmake .. -DCMAKE_BUILD_TYPE=" + build_type + " && "
  167. "make -j\"$(nproc)\" && make install") == 0;
  168. }
  169. void remove_legacy_ngs_install() {
  170. remove_path(join_path(software_root(), "fastweb"));
  171. remove_path(join_path(software_root(), "3rdparty"));
  172. remove_path(join_path(software_root(), "lua54"));
  173. remove_path(join_path(software_root(), "luarocks"));
  174. remove_path(join_path(software_root(), ".build/fastweb"));
  175. }
  176. } // namespace
  177. std::string install_dir() {
  178. return system_prefix();
  179. }
  180. std::string bin_path() {
  181. return fastweb_bin();
  182. }
  183. std::string share_dir() {
  184. return join_path(system_prefix(), "share/fastweb");
  185. }
  186. bool is_installed() {
  187. return fastweb_bin_installed();
  188. }
  189. std::string installed_version() {
  190. const std::string path = version_file();
  191. if (path_exists(path)) {
  192. std::ifstream in(path);
  193. std::string ver;
  194. if (in && std::getline(in, ver) && !ver.empty()) {
  195. return ver;
  196. }
  197. }
  198. return is_installed() ? std::string(kDefaultVersion) : "";
  199. }
  200. void show_status() {
  201. std::cout << "安装前缀: " << install_dir() << "\n";
  202. std::cout << "构建目录: " << build_root() << "\n";
  203. std::cout << "可执行文件: " << fastweb_bin() << "\n";
  204. std::cout << "模板目录: " << share_dir() << "\n";
  205. std::cout << "Lua: " << lua_prefix()
  206. << (lua_installed() ? " [已安装]" : " [未安装]") << "\n";
  207. std::cout << "LuaRocks: " << luarocks_prefix()
  208. << (luarocks_installed() ? " [已安装]" : " [未安装]") << "\n";
  209. std::cout << "ylib: "
  210. << (ylib_present() ? "[系统已有]" : "[缺失,请先 ./build.sh]") << "\n";
  211. std::cout << "HPSocket: "
  212. << (hpsocket_present() ? "[系统已有]" : "[缺失,请先 ./build.sh]") << "\n";
  213. if (is_installed()) {
  214. std::cout << "状态: 已安装\n";
  215. std::cout << "版本: " << installed_version() << "\n";
  216. } else {
  217. std::cout << "状态: 未安装\n";
  218. }
  219. }
  220. bool install(bool debug) {
  221. if (lua_installed() && luarocks_installed() && is_installed()) {
  222. std::cout << "Fastweb 及相关组件已安装。\n";
  223. std::cout << "如需重装,请先卸载。\n";
  224. return false;
  225. }
  226. if (!ylib_present() || !hpsocket_present()) {
  227. std::cerr << "缺少系统依赖 ylib / HPSocket。\n"
  228. << "请先在 NGS 根目录执行 ./build.sh 完成初始化。\n";
  229. return false;
  230. }
  231. std::cout << "检测到系统已安装 ylib / HPSocket,跳过重复编译。\n";
  232. std::cout << "清理并创建构建目录: " << build_root() << "\n";
  233. remove_path(build_root());
  234. if (!ensure_dir(build_root())) {
  235. std::cerr << "无法创建构建目录。\n";
  236. return false;
  237. }
  238. if (!install_apt_deps()) {
  239. std::cerr << "系统依赖安装失败。\n";
  240. return false;
  241. }
  242. if (!lua_installed()) {
  243. if (!install_lua(build_root())) {
  244. std::cerr << "Lua 安装失败。\n";
  245. return false;
  246. }
  247. } else {
  248. std::cout << "Lua 已安装,跳过。\n";
  249. }
  250. if (!luarocks_installed()) {
  251. if (!install_luarocks(build_root())) {
  252. std::cerr << "LuaRocks 安装失败。\n";
  253. return false;
  254. }
  255. } else {
  256. std::cout << "LuaRocks 已安装,跳过。\n";
  257. }
  258. if (!build_fastweb(debug)) {
  259. std::cerr << "fastweb 编译安装失败。\n";
  260. return false;
  261. }
  262. write_version_file(kDefaultVersion, debug);
  263. remove_legacy_ngs_install();
  264. std::cout << "\nFastweb " << kDefaultVersion << " 安装成功。\n";
  265. log_info(std::string("fastweb installed version=") + kDefaultVersion +
  266. " debug=" + (debug ? "1" : "0") + " prefix=/usr/local");
  267. std::cout << "安装前缀: " << install_dir() << "\n";
  268. std::cout << "可执行文件: " << fastweb_bin() << "\n";
  269. std::cout << "模板目录: " << share_dir() << "\n";
  270. return true;
  271. }
  272. bool uninstall() {
  273. const bool has_fw = is_installed() || is_dir(share_dir());
  274. const bool has_lua = lua_installed() || is_dir(lua_prefix());
  275. const bool has_rocks = luarocks_installed() || is_dir(luarocks_prefix());
  276. const bool has_build = is_dir(build_root());
  277. const bool has_legacy = is_dir(join_path(software_root(), "fastweb")) ||
  278. is_dir(join_path(software_root(), "3rdparty"));
  279. if (!has_fw && !has_lua && !has_rocks && !has_build && !has_legacy) {
  280. std::cout << "Fastweb 未安装,无需卸载。\n";
  281. return true;
  282. }
  283. std::cout << "卸载 Fastweb(保留系统 ylib / HPSocket)...\n";
  284. remove_path(fastweb_bin());
  285. remove_path(join_path(system_prefix(), "lib/libfastwebcore.so"));
  286. remove_path(share_dir());
  287. remove_path(join_path(system_prefix(), "include/fastweb"));
  288. remove_path(join_path(system_prefix(), "include/sol"));
  289. remove_path(lua_prefix());
  290. remove_path(luarocks_prefix());
  291. remove_path(build_root());
  292. remove_legacy_ngs_install();
  293. std::cout << "Fastweb 已卸载。\n";
  294. log_info("fastweb uninstalled");
  295. return true;
  296. }
  297. void menu() {
  298. while (true) {
  299. print_header("软件管理 - Fastweb");
  300. show_status();
  301. std::cout << "\n";
  302. std::cout << " 1) 安装 Fastweb (Release)\n";
  303. std::cout << " 2) 安装 Fastweb (Debug)\n";
  304. std::cout << " 3) 卸载 Fastweb\n";
  305. std::cout << " 0) 返回上级\n\n";
  306. int choice = read_choice("请选择: ");
  307. switch (choice) {
  308. case 1:
  309. case 2: {
  310. const bool debug = (choice == 2);
  311. std::cout << "\n确认安装 Fastweb " << kDefaultVersion
  312. << "\n Lua/LuaRocks -> /opt"
  313. << "\n Fastweb -> /usr/local (cmake/make/make install)"
  314. << "\n ylib/HPSocket 使用 NGS 已安装的系统库"
  315. << " [" << (debug ? "Debug" : "Release") << "] ? [y/N]: ";
  316. std::string confirm;
  317. std::getline(std::cin, confirm);
  318. if (confirm == "y" || confirm == "Y") {
  319. install(debug);
  320. } else {
  321. std::cout << "已取消。\n";
  322. }
  323. pause();
  324. break;
  325. }
  326. case 3: {
  327. std::cout << "\n确认卸载 Fastweb(含 /opt/lua54、/opt/luarocks,"
  328. "不删除 ylib/HPSocket)? [y/N]: ";
  329. std::string confirm;
  330. std::getline(std::cin, confirm);
  331. if (confirm == "y" || confirm == "Y") {
  332. uninstall();
  333. } else {
  334. std::cout << "已取消。\n";
  335. }
  336. pause();
  337. break;
  338. }
  339. case 0:
  340. return;
  341. default:
  342. std::cout << "无效选项。\n";
  343. pause();
  344. break;
  345. }
  346. }
  347. }
  348. } // namespace fastweb
  349. } // namespace ngs