184 lines
6.8 KiB
C++
184 lines
6.8 KiB
C++
|
#include "AlarmClockServer.h"
|
||
|
#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 <boost/program_options.hpp>
|
||
|
#include <boost/property_tree/ini_parser.hpp>
|
||
|
#include <boost/property_tree/ptree.hpp>
|
||
|
#include <filesystem>
|
||
|
|
||
|
void initSettings();
|
||
|
|
||
|
int main(int argc, char const *argv[]) {
|
||
|
initBoostLog("HttpServer");
|
||
|
auto manager = Amass::Singleton<ServiceManager>::instance<Amass::Construct>();
|
||
|
|
||
|
boost::program_options::options_description description("Allowed options");
|
||
|
// clang-format off
|
||
|
description.add_options()
|
||
|
("help,h", "produce help message.")
|
||
|
("prefix", boost::program_options::value<std::string>(),"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<std::string>();
|
||
|
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();
|
||
|
|
||
|
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<std::string>("server");
|
||
|
}
|
||
|
|
||
|
auto port = ptree.get_optional<uint16_t>("port");
|
||
|
|
||
|
auto docRoot = ptree.get<std::string>("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<std::string>("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);
|
||
|
}
|
||
|
|
||
|
auto notebookRoot = ptree.get<std::string>("notebookRoot");
|
||
|
if (notebookRoot.empty()) {
|
||
|
LOG(fatal) << "please set notebookRoot.";
|
||
|
std::exit(105);
|
||
|
} else if (!std::filesystem::exists(notebookRoot)) {
|
||
|
LOG(fatal) << "notebook root: " << notebookRoot << " is not exists...";
|
||
|
std::exit(106);
|
||
|
}
|
||
|
|
||
|
if (!port) {
|
||
|
LOG(fatal) << "port is not a number.";
|
||
|
std::exit(255);
|
||
|
}
|
||
|
auto threads = ptree.get<unsigned int>("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<IoContext>::instance<Amass::Construct>(threads);
|
||
|
auto address = boost::asio::ip::make_address(server);
|
||
|
auto listener = std::make_shared<Listener>(*ioContext->ioContext(), boost::asio::ip::tcp::endpoint{address, *port},
|
||
|
std::make_shared<SharedState>(*ioContext->ioContext(), docRoot));
|
||
|
listener->startAccept();
|
||
|
|
||
|
auto state = listener->state();
|
||
|
state->setFileRoot(fileRoot);
|
||
|
state->setNotebookRoot(notebookRoot);
|
||
|
|
||
|
auto alarmClockServer = Amass::Singleton<AlarmClockServer>::instance<Amass::Construct>(*ioContext->ioContext());
|
||
|
alarmClockServer->listen(server, "8089");
|
||
|
|
||
|
auto wechatContext = Amass::Singleton<WeChatContext>::instance<Amass::Construct>(*ioContext->ioContext());
|
||
|
auto corpContext = Amass::Singleton<CorporationContext>::instance<Amass::Construct>(*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();
|
||
|
LOG(info) << "notebook root: " << state->notebookRoot();
|
||
|
|
||
|
// 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<UdpServer>(*ioContext->ioContext());
|
||
|
|
||
|
auto proxyAddress = boost::asio::ip::make_address(server);
|
||
|
uint16_t proxyPort = 41091;
|
||
|
auto proxy = std::make_shared<ProxyListener>(*ioContext->ioContext(),
|
||
|
boost::asio::ip::tcp::endpoint{proxyAddress, proxyPort});
|
||
|
boost::system::error_code perror;
|
||
|
proxy->run(perror);
|
||
|
|
||
|
LOG(info) << "server start successful ...";
|
||
|
ioContext->run<IoContext::Mode::Synchronous>();
|
||
|
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", 8080);
|
||
|
}
|
||
|
if (ptree.find("docRoot") == ptree.not_found()) {
|
||
|
ptree.put("docRoot", ".");
|
||
|
}
|
||
|
if (ptree.find("fileRoot") == ptree.not_found()) {
|
||
|
ptree.put("fileRoot", ".");
|
||
|
}
|
||
|
if (ptree.find("notebookRoot") == ptree.not_found()) {
|
||
|
ptree.put("notebookRoot", ".");
|
||
|
}
|
||
|
if (ptree.find("threads") == ptree.not_found()) {
|
||
|
ptree.put("threads", std::thread::hardware_concurrency());
|
||
|
}
|
||
|
|
||
|
boost::property_tree::write_ini("settings.ini", ptree);
|
||
|
}
|