#include "BoostLog.h" #include "IoContext.h" #include "Listener.h" #include "ProxyListener.h" #include "ServiceManager.h" #include "SharedState.h" #include "UdpServer.h" #include "WeChatContext/CorporationContext.h" #include "WeChatContext/WeChatContext.h" #include #include #include #include #include "Database.h" void initSettings(); int main(int argc, char const *argv[]) { boost::log::initialize("logs/HttpServer"); auto manager = Amass::Singleton::instance(); boost::program_options::options_description description("Allowed options"); // clang-format off description.add_options() ("help,h", "produce help message.") ("prefix", boost::program_options::value(),"set prefix path (default: ${pwd} )"); // clang-format on boost::program_options::variables_map values; try { boost::program_options::store(boost::program_options::parse_command_line(argc, argv, description), values); boost::program_options::notify(values); } catch (const boost::program_options::invalid_command_line_syntax &e) { LOG(fatal) << e.what(); std::exit(-1); } if (values.count("help")) { std::cout << description << std::endl; std::exit(0); } std::error_code error; auto prefix = std::filesystem::current_path(error); if (error) { LOG(fatal) << "cannot get current path,reason: " << error.message(); return -1; } if (values.count("prefix")) { prefix = values["prefix"].as(); if (prefix.empty() || !std::filesystem::exists(prefix)) { LOG(fatal) << "working directory: " << prefix << " is not exists."; return -1; } std::filesystem::current_path(prefix, error); LOG_IF(fatal, error) << "cannot set current path,reason: " << error.message(); } initSettings(); auto database = Amass::Singleton::instance(); database->open("database.sqlite"); std::string server = "0.0.0.0"; boost::property_tree::ptree ptree; boost::property_tree::read_ini("settings.ini", ptree); if (ptree.count("server") > 0) { server = ptree.get("server"); } auto port = ptree.get_optional("port"); auto docRoot = ptree.get("docRoot"); if (docRoot.empty()) { LOG(fatal) << "please set docRoot."; std::exit(101); } else if (!std::filesystem::exists(docRoot)) { LOG(fatal) << "document root: " << docRoot << " is not exists..."; std::exit(102); } auto fileRoot = ptree.get("fileRoot"); if (fileRoot.empty()) { LOG(fatal) << "please set fileRoot."; std::exit(103); } else if (!std::filesystem::exists(fileRoot)) { LOG(fatal) << "file root: " << fileRoot << " is not exists..."; std::exit(104); } if (!port) { LOG(fatal) << "port is not a number."; std::exit(255); } auto threads = ptree.get("threads"); if (threads <= 0 || threads > std::thread::hardware_concurrency()) threads = std::thread::hardware_concurrency(); BOOST_ASSERT_MSG(!server.empty(), "server.empty() == true"); auto ioContext = Amass::Singleton::instance(threads); auto address = boost::asio::ip::make_address(server); auto listener = std::make_shared(*ioContext->ioContext(), boost::asio::ip::tcp::endpoint{address, *port}, std::make_shared(*ioContext->ioContext(), docRoot)); listener->startAccept(); auto state = listener->state(); state->setFileRoot(fileRoot); auto wechatContext = Amass::Singleton::instance(*ioContext->ioContext()); auto corpContext = Amass::Singleton::instance(*ioContext->ioContext()); LOG(info) << "hardware_concurrency: " << std::thread::hardware_concurrency() << ",threads: " << threads; LOG(info) << "working directory: " << prefix.generic_string(); LOG(info) << "server: " << server << ",port: " << *port; LOG(info) << "document root: " << state->docRoot(); // Capture SIGINT and SIGTERM to perform a clean shutdown #ifndef WIN32 boost::asio::signal_set signals(*ioContext->ioContext(), SIGINT, SIGTERM, SIGHUP); #else boost::asio::signal_set signals(*ioContext->ioContext(), SIGINT, SIGTERM); #endif signals.async_wait([&ioContext](boost::system::error_code const &, int signal) { // Stop the io_context. This will cause run() // to return immediately, eventually destroying the // io_context and any remaining handlers in it. LOG(info) << "capture " << (signal == SIGINT ? "SIGINT" : "SIGTERM") << ",stop!"; ioContext->ioContext()->stop(); }); auto udpServer = std::make_shared(*ioContext->ioContext()); auto proxyAddress = boost::asio::ip::make_address(server); uint16_t proxyPort = 41091; auto proxy = std::make_shared(*ioContext->ioContext(), boost::asio::ip::tcp::endpoint{proxyAddress, proxyPort}); boost::system::error_code perror; proxy->run(perror); LOG(info) << "server start successful ..."; ioContext->run(); LOG(info) << "server exit successful ..."; return EXIT_SUCCESS; } void initSettings() { boost::property_tree::ptree ptree; if (std::filesystem::exists(std::filesystem::path("settings.ini"))) boost::property_tree::read_ini("settings.ini", ptree); if (ptree.find("server") == ptree.not_found()) { ptree.put("server", "0.0.0.0"); } if (ptree.find("port") == ptree.not_found()) { ptree.put("port", 8083); } if (ptree.find("docRoot") == ptree.not_found()) { ptree.put("docRoot", "."); } if (ptree.find("fileRoot") == ptree.not_found()) { ptree.put("fileRoot", "."); } if (ptree.find("threads") == ptree.not_found()) { ptree.put("threads", std::thread::hardware_concurrency()); } boost::property_tree::write_ini("settings.ini", ptree); }