remove some code.
All checks were successful
Deploy / Build (push) Successful in 6m7s

This commit is contained in:
amass 2025-01-10 21:49:22 +08:00
parent 0511259075
commit 7554691cfd
10 changed files with 132 additions and 154 deletions

View File

@ -9,6 +9,7 @@
#include "SystemUsage.h" #include "SystemUsage.h"
#include "WeChatContext/CorporationContext.h" #include "WeChatContext/CorporationContext.h"
#include <Wt/Dbo/Json.h> #include <Wt/Dbo/Json.h>
#include <boost/asio/strand.hpp>
#include <boost/json/object.hpp> #include <boost/json/object.hpp>
#include <boost/json/serialize.hpp> #include <boost/json/serialize.hpp>
#include <boost/process/v2/process.hpp> #include <boost/process/v2/process.hpp>
@ -17,22 +18,23 @@
constexpr auto IpcUrl = "ipc:///tmp/nng_ipc_server"; constexpr auto IpcUrl = "ipc:///tmp/nng_ipc_server";
static std::vector<std::string> urlFilter = { static std::vector<std::string> urlFilter = {
"/", "/", "/search", "/LoginPage", "/MessageBoard", "/我的笔记", "/我的笔记/", "/我的博客",
"/search",
"/LoginPage",
"/MessageBoard",
"/我的笔记",
"/我的笔记/",
"/我的博客",
}; };
Application::Application(const std::string &path) class ApplicationPrivate {
: ApplicationSettings(path), m_router{std::make_shared<boost::urls::router<RequestHandler>>()} { public:
std::shared_ptr<boost::urls::router<Application::RequestHandler>> router;
std::shared_ptr<boost::asio::ip::tcp::acceptor> acceptor;
};
Application::Application(const std::string &path) : ApplicationSettings(path), m_d{new ApplicationPrivate()} {
using namespace boost::urls;
m_d->router = std::make_shared<router<RequestHandler>>();
// clang-format off // clang-format off
m_router->insert("/{path*}",[this](HttpSession &session, const Request &request, const boost::urls::matches &matches) { m_d->router->insert("/{path*}",[this](HttpSession &session, const Request &request, const matches &matches) {
using namespace boost::beast; using namespace boost::beast;
boost::urls::url_view view(request.target()); url_view view(request.target());
auto target = view.path(); auto target = view.path();
LOG(info) << target; LOG(info) << target;
if (target.find("..") != boost::beast::string_view::npos) { if (target.find("..") != boost::beast::string_view::npos) {
@ -65,12 +67,12 @@ Application::Application(const std::string &path)
session.reply(std::move(res)); session.reply(std::move(res));
}); });
m_router->insert("/wechat/{session*}",[this](HttpSession &session, const Request &request, const boost::urls::matches &matches) { m_d->router->insert("/wechat/{session*}",[this](HttpSession &session, const Request &request, const matches &matches) {
ServiceLogic::onWechat(shared_from_this(), request, ServiceLogic::onWechat(shared_from_this(), request,
[&session](auto &&response) { session.reply(std::move(response)); }); [&session](auto &&response) { session.reply(std::move(response)); });
}); });
m_router->insert("/api/v1/tasklist", [this](HttpSession &session, const Request &request, const boost::urls::matches &matches) { m_d->router->insert("/api/v1/tasklist", [this](HttpSession &session, const Request &request, const matches &matches) {
using namespace boost::beast; using namespace boost::beast;
auto database = Database::session(); auto database = Database::session();
Tasks tasks = database->find<Task>(); Tasks tasks = database->find<Task>();
@ -86,7 +88,7 @@ Application::Application(const std::string &path)
session.reply(std::move(s)); session.reply(std::move(s));
}); });
m_router->insert("/api/v1/task/add", [this](HttpSession &session, const Request &request, const boost::urls::matches &matches) mutable { m_d->router->insert("/api/v1/task/add", [this](HttpSession &session, const Request &request, const matches &matches) mutable {
using namespace boost::beast; using namespace boost::beast;
using namespace std::chrono; using namespace std::chrono;
LOG(info) << "add task: " << request.body(); LOG(info) << "add task: " << request.body();
@ -118,7 +120,7 @@ Application::Application(const std::string &path)
session.reply(std::move(s)); session.reply(std::move(s));
}); });
m_router->insert("/api/v1/task/delete/{id}", [this](HttpSession &session, const Request &request,const boost::urls::matches &matches) { m_d->router->insert("/api/v1/task/delete/{id}", [this](HttpSession &session, const Request &request,const matches &matches) {
using namespace boost::beast; using namespace boost::beast;
LOG(info) << "delete task: " << matches.at("id"); LOG(info) << "delete task: " << matches.at("id");
auto database = Database::session();; auto database = Database::session();;
@ -139,14 +141,14 @@ Application::Application(const std::string &path)
session.reply(std::move(s)); session.reply(std::move(s));
}); });
m_router->insert("/notify", [this](HttpSession &session, const Request &request, const boost::urls::matches &matches) { m_d->router->insert("/notify", [this](HttpSession &session, const Request &request, const matches &matches) {
auto corp = Amass::Singleton<CorporationContext>::instance(); auto corp = Amass::Singleton<CorporationContext>::instance();
corp->notify(request); corp->notify(request);
session.reply( session.reply(
ServiceLogic::make_200<boost::beast::http::string_body>(request, "notify successed.\n", "text/html")); ServiceLogic::make_200<boost::beast::http::string_body>(request, "notify successed.\n", "text/html"));
}); });
m_router->insert("/api/v1/visit_analysis", [this](HttpSession &session, const Request &request, const boost::urls::matches &matches) { m_d->router->insert("/api/v1/visit_analysis", [this](HttpSession &session, const Request &request, const matches &matches) {
using namespace boost::beast; using namespace boost::beast;
auto rootJson = boost::json::parse(request.body()); auto rootJson = boost::json::parse(request.body());
auto &root = rootJson.as_object(); auto &root = rootJson.as_object();
@ -188,7 +190,7 @@ Application::Application(const std::string &path)
session.reply(std::move(s)); session.reply(std::move(s));
}); });
m_router->insert("/api/v1/most_viewed_urls", [this](HttpSession &session, const Request &request, const boost::urls::matches &matches) { m_d->router->insert("/api/v1/most_viewed_urls", [this](HttpSession &session, const Request &request, const matches &matches) {
using namespace boost::beast; using namespace boost::beast;
int size = 5; int size = 5;
std::error_code error; std::error_code error;
@ -226,7 +228,7 @@ Application::Application(const std::string &path)
session.reply(std::move(s)); session.reply(std::move(s));
}); });
m_router->insert("/api/v1/latest_viewed_urls", [this](HttpSession &session, const Request &request, const boost::urls::matches &matches) { m_d->router->insert("/api/v1/latest_viewed_urls", [this](HttpSession &session, const Request &request, const matches &matches) {
using namespace boost::beast; using namespace boost::beast;
using namespace std::chrono; using namespace std::chrono;
int size = 5; int size = 5;
@ -265,7 +267,7 @@ Application::Application(const std::string &path)
s.prepare_payload(); s.prepare_payload();
session.reply(std::move(s)); session.reply(std::move(s));
}); });
m_router->insert("/api/v1/search/reindex", [this](HttpSession &session, const Request &request, const boost::urls::matches &matches) { m_d->router->insert("/api/v1/search/reindex", [this](HttpSession &session, const Request &request, const matches &matches) {
using namespace boost::beast; using namespace boost::beast;
std::string authorizationHeader; std::string authorizationHeader;
if (request.count(http::field::authorization)) { if (request.count(http::field::authorization)) {
@ -326,24 +328,59 @@ Application::Application(const std::string &path)
alarmTask(); alarmTask();
} }
Application::~Application() {
if (m_d != nullptr) {
delete m_d;
}
}
boost::asio::io_context &Application::ioContext() { boost::asio::io_context &Application::ioContext() {
return *m_ioContext->ioContext(); return *m_ioContext->ioContext();
} }
const Application::RequestHandler *Application::find(boost::urls::segments_encoded_view path, void Application::insertUrl(std::string_view url, RequestHandler &&handler) {
boost::urls::matches_base &matches) const noexcept { m_d->router->insert(url, std::move(handler));
const Application::RequestHandler *ret = nullptr;
try {
ret = m_router->find(path, matches);
} catch (const std::exception &e) {
boost::stacktrace::stacktrace trace = boost::stacktrace::stacktrace::from_current_exception();
LOG(error) << e.what() << ", trace:\n" << trace;
}
return ret;
} }
void Application::insertUrl(std::string_view url, RequestHandler &&handler) { void Application::startAcceptHttpConnections(const std::string &address, uint16_t port) {
m_router->insert(url, std::move(handler)); m_d->acceptor = std::make_shared<boost::asio::ip::tcp::acceptor>(*m_ioContext->ioContext());
boost::beast::error_code error;
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::make_address(address), port);
m_d->acceptor->open(endpoint.protocol(), error);
if (error) {
LOG(error) << error.message();
return;
}
m_d->acceptor->set_option(boost::asio::socket_base::reuse_address(true), error);
if (error) {
LOG(error) << error.message();
return;
}
m_d->acceptor->bind(endpoint, error);
if (error) {
LOG(error) << error.message();
return;
}
m_d->acceptor->listen(boost::asio::socket_base::max_listen_connections, error);
if (error) {
LOG(error) << error.message();
return;
}
asyncAcceptHttpConnections();
}
void Application::asyncAcceptHttpConnections() {
auto socket = std::make_shared<boost::asio::ip::tcp::socket>(boost::asio::make_strand(*m_ioContext->ioContext()));
m_d->acceptor->async_accept(*socket, [self{shared_from_this()}, socket](const boost::system::error_code &error) {
if (error) {
if (error == boost::asio::error::operation_aborted) return;
LOG(error) << error.message();
} else {
auto session = std::make_shared<HttpSession>(std::move(*socket), self->m_d->router);
session->run();
}
self->asyncAcceptHttpConnections();
});
} }
int Application::exec() { int Application::exec() {

View File

@ -3,10 +3,10 @@
#include "ApplicationSettings.h" #include "ApplicationSettings.h"
#include "Singleton.h" #include "Singleton.h"
#include "router.hpp"
#include <boost/asio/system_timer.hpp> #include <boost/asio/system_timer.hpp>
#include <boost/beast/http/string_body.hpp> #include <boost/beast/http/string_body.hpp>
#include <thread> #include <thread>
#include "matches.hpp"
class HttpSession; class HttpSession;
class SystemUsage; class SystemUsage;
@ -18,6 +18,7 @@ class Socket;
} }
} // namespace Nng } // namespace Nng
class ApplicationPrivate;
class Application : public ApplicationSettings<Application>, public std::enable_shared_from_this<Application> { class Application : public ApplicationSettings<Application>, public std::enable_shared_from_this<Application> {
public: public:
using Pointer = std::shared_ptr<Application>; using Pointer = std::shared_ptr<Application>;
@ -36,21 +37,23 @@ public:
INITIALIZE_FIELDS(Server, Port, Threads, ApplicationRoot, DocumentRoot); INITIALIZE_FIELDS(Server, Port, Threads, ApplicationRoot, DocumentRoot);
Application(const std::string &path); Application(const std::string &path);
~Application();
boost::asio::io_context &ioContext(); boost::asio::io_context &ioContext();
int exec(); int exec();
const RequestHandler *find(boost::urls::segments_encoded_view path, boost::urls::matches_base &matches) const noexcept; void startAcceptHttpConnections(const std::string &address, uint16_t port);
void insertUrl(std::string_view url, RequestHandler &&handler); void insertUrl(std::string_view url, RequestHandler &&handler);
static void requetExit(); static void requetExit();
protected: protected:
void alarmTask(); void alarmTask();
void startAcceptRequest(); void startAcceptRequest();
void asyncAcceptHttpConnections();
private: private:
ApplicationPrivate *m_d = nullptr;
int m_status = 0; int m_status = 0;
std::shared_ptr<IoContext> m_ioContext; std::shared_ptr<IoContext> m_ioContext;
std::shared_ptr<boost::urls::router<RequestHandler>> m_router;
std::shared_ptr<boost::asio::system_timer> m_timer; std::shared_ptr<boost::asio::system_timer> m_timer;
std::shared_ptr<SystemUsage> m_systemUsage; std::shared_ptr<SystemUsage> m_systemUsage;
std::shared_ptr<Nng::Asio::Socket> m_replyer; std::shared_ptr<Nng::Asio::Socket> m_replyer;

View File

@ -5,7 +5,6 @@ add_subdirectory(WebRTC)
add_executable(Server main.cpp add_executable(Server main.cpp
Application.h Application.cpp Application.h Application.cpp
HttpSession.h HttpSession.cpp HttpSession.h HttpSession.cpp
Listener.h Listener.cpp
ResponseUtility.h ResponseUtility.cpp ResponseUtility.h ResponseUtility.cpp
ServiceLogic.h ServiceLogic.inl ServiceLogic.cpp ServiceLogic.h ServiceLogic.inl ServiceLogic.cpp
ServiceManager.h ServiceManager.h

View File

@ -1,5 +1,7 @@
#include "HttpSession.h" #include "HttpSession.h"
#include "Application.h" #include "BoostLog.h"
#include <boost/beast/http/read.hpp>
#include <boost/beast/version.hpp>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/stacktrace.hpp> #include <boost/stacktrace.hpp>
#include <boost/url/parse_path.hpp> #include <boost/url/parse_path.hpp>
@ -7,7 +9,8 @@
#include <iostream> #include <iostream>
#include <limits> #include <limits>
HttpSession::HttpSession(boost::asio::ip::tcp::socket &&socket) : m_stream(std::move(socket)) { HttpSession::HttpSession(boost::asio::ip::tcp::socket &&socket, const std::shared_ptr<boost::urls::router<RequestHandler>> &router)
: m_stream(std::move(socket)), m_router(router) {
} }
void HttpSession::run() { void HttpSession::run() {
@ -18,6 +21,10 @@ boost::beast::tcp_stream::executor_type HttpSession::executor() {
return m_stream.get_executor(); return m_stream.get_executor();
} }
boost::asio::ip::tcp::socket HttpSession::releaseSocket() {
return m_stream.release_socket();
}
void HttpSession::errorReply(const Request &request, boost::beast::http::status status, boost::beast::string_view message) { void HttpSession::errorReply(const Request &request, boost::beast::http::status status, boost::beast::string_view message) {
using namespace boost::beast; using namespace boost::beast;
// invalid route // invalid route
@ -43,23 +50,25 @@ void HttpSession::doRead() {
// Set the timeout. // Set the timeout.
m_stream.expires_after(std::chrono::seconds(30)); m_stream.expires_after(std::chrono::seconds(30));
boost::beast::http::async_read( // clang-format off
m_stream, m_buffer, *m_parser, boost::beast::http::async_read(m_stream, m_buffer, *m_parser, [self{shared_from_this()}](const boost::system::error_code &ec, std::size_t bytes_transferred) {
[self{shared_from_this()}](const boost::system::error_code &ec, std::size_t bytes_transferred) { self->onRead(ec, bytes_transferred);
self->onRead(ec, bytes_transferred); });
}); // clang-format on
} }
void HttpSession::onRead(boost::beast::error_code ec, std::size_t) { void HttpSession::onRead(const boost::beast::error_code &error, std::size_t) {
using namespace boost::beast; using namespace boost::beast;
// This means they closed the connection if (error) {
if (ec == http::error::end_of_stream) { if (error == http::error::end_of_stream) {
m_stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); boost::beast::error_code e;
m_stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_send, e);
} else if (error != boost::asio::error::operation_aborted) {
LOG(info) << error << " : " << error.message();
}
return; return;
} } else if (m_router.expired()) {
if (ec) { LOG(error) << "router is null.";
if (ec == boost::asio::error::operation_aborted) return;
LOG(info) << ec << " : " << ec.message();
return; return;
} }
@ -70,11 +79,9 @@ void HttpSession::onRead(boost::beast::error_code ec, std::size_t) {
errorReply(request, http::status::bad_request, "Illegal request-target"); errorReply(request, http::status::bad_request, "Illegal request-target");
return; return;
} }
auto router = m_router.lock();
auto application = Amass::Singleton<Application>::instance();
boost::urls::matches matches; boost::urls::matches matches;
auto handler = application->find(*path, matches); auto handler = router->find(*path, matches);
if (handler) { if (handler) {
try { try {
(*handler)(*this, request, matches); (*handler)(*this, request, matches);

View File

@ -1,7 +1,12 @@
#ifndef HTTPSESSION_H #ifndef HTTPSESSION_H
#define HTTPSESSION_H #define HTTPSESSION_H
#include "boost/beast.hpp" #include "router.hpp"
#include <boost/beast/core/flat_buffer.hpp>
#include <boost/beast/core/tcp_stream.hpp>
#include <boost/beast/http/parser.hpp>
#include <boost/beast/http/string_body.hpp>
#include <boost/beast/http/write.hpp>
#include <cstdlib> #include <cstdlib>
#include <memory> #include <memory>
#include <optional> #include <optional>
@ -10,14 +15,12 @@
*/ */
class HttpSession : public std::enable_shared_from_this<HttpSession> { class HttpSession : public std::enable_shared_from_this<HttpSession> {
void doRead(); void doRead();
void onRead(boost::beast::error_code ec, std::size_t);
void onWrite(boost::beast::error_code ec, std::size_t, bool close); void onWrite(boost::beast::error_code ec, std::size_t, bool close);
// void sendResponse(boost::beast::http::response<boost::beast::http::string_body> &&response);
public: public:
using Request = boost::beast::http::request<boost::beast::http::string_body>; using Request = boost::beast::http::request<boost::beast::http::string_body>;
HttpSession(boost::asio::ip::tcp::socket &&socket); using RequestHandler = std::function<void(HttpSession &, const Request &, const boost::urls::matches &)>;
HttpSession(boost::asio::ip::tcp::socket &&socket, const std::shared_ptr<boost::urls::router<RequestHandler>> &router);
template <typename Response> template <typename Response>
void reply(Response &&response) { void reply(Response &&response) {
using ResponseType = typename std::decay_t<decltype(response)>; using ResponseType = typename std::decay_t<decltype(response)>;
@ -28,10 +31,15 @@ public:
} }
void errorReply(const Request &request, boost::beast::http::status status, boost::beast::string_view message); void errorReply(const Request &request, boost::beast::http::status status, boost::beast::string_view message);
boost::beast::tcp_stream::executor_type executor(); boost::beast::tcp_stream::executor_type executor();
boost::asio::ip::tcp::socket releaseSocket();
void run(); void run();
protected:
void onRead(const boost::beast::error_code &error, std::size_t);
private: private:
boost::beast::tcp_stream m_stream; boost::beast::tcp_stream m_stream;
std::weak_ptr<boost::urls::router<RequestHandler>> m_router;
boost::beast::flat_buffer m_buffer{std::numeric_limits<std::uint32_t>::max()}; boost::beast::flat_buffer m_buffer{std::numeric_limits<std::uint32_t>::max()};
std::optional<boost::beast::http::request_parser<boost::beast::http::string_body>> m_parser; std::optional<boost::beast::http::request_parser<boost::beast::http::string_body>> m_parser;
}; };

View File

@ -1,63 +0,0 @@
#include "Listener.h"
#include "HttpSession.h"
#include <boost/asio.hpp>
#include <iostream>
Listener::Listener(boost::asio::io_context &ioc, boost::asio::ip::tcp::endpoint endpoint)
: m_ioContext(ioc), m_acceptor(ioc) {
boost::beast::error_code ec;
// Open the acceptor
m_acceptor.open(endpoint.protocol(), ec);
if (ec) {
fail(ec, "open");
return;
}
// Allow address reuse
m_acceptor.set_option(boost::asio::socket_base::reuse_address(true), ec);
if (ec) {
fail(ec, "set_option");
return;
}
// Bind to the server address
m_acceptor.bind(endpoint, ec);
if (ec) {
fail(ec, "bind");
return;
}
// Start listening for connections
m_acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
if (ec) {
fail(ec, "listen");
return;
}
}
void Listener::startAccept() {
// The new connection gets its own strand
auto client = std::make_shared<boost::asio::ip::tcp::socket>(boost::asio::make_strand(m_ioContext));
m_acceptor.async_accept(
*client, [self{shared_from_this()}, client](const boost::system::error_code &ec) { self->onAccept(ec, client); });
}
void Listener::fail(boost::beast::error_code ec, char const *what) {
// Don't report on canceled operations
if (ec == boost::asio::error::operation_aborted) return;
std::cerr << what << ": " << ec.message() << "\n";
}
// Handle a connection
void Listener::onAccept(boost::beast::error_code ec, std::shared_ptr<boost::asio::ip::tcp::socket> socket) {
if (ec) {
if (ec == boost::asio::error::operation_aborted) return;
std::cerr << "accept: " << ec.message() << "\n";
} else { // Launch a new session for this connection
auto session = std::make_shared<HttpSession>(std::move(*socket));
session->run();
}
startAccept();
}

View File

@ -1,25 +0,0 @@
#ifndef LISTENER_H
#define LISTENER_H
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <memory>
#include <string>
class Listener : public std::enable_shared_from_this<Listener> {
public:
Listener(boost::asio::io_context &ioc, boost::asio::ip::tcp::endpoint endpoint);
// Start accepting incoming connections
void startAccept();
protected:
void fail(boost::beast::error_code ec, char const *what);
void onAccept(boost::beast::error_code ec, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
private:
boost::asio::io_context &m_ioContext;
boost::asio::ip::tcp::acceptor m_acceptor;
};
#endif // LISTENER_H

View File

@ -1,4 +1,18 @@
#include "SignalServer.h" #include "SignalServer.h"
#include "../Application.h"
#include <boost/beast/websocket/rfc6455.hpp>
SignalServer::SignalServer(Application &app) {
using namespace boost::urls;
// clang-format off
app.insertUrl("/api/v1/webrtc/signal/{id}", [this](HttpSession &session, const Application::Request &request, const matches &matches) {
auto id = matches.at("id");
if (boost::beast::websocket::is_upgrade(request)) {
auto ws = std::make_shared<WebSocketSignalSession>();
}
});
// clang-format on
}
void SignalServer::join(const std::string &id, WebSocketSignalSession *client) { void SignalServer::join(const std::string &id, WebSocketSignalSession *client) {
m_clients.insert({id, client}); m_clients.insert({id, client});

View File

@ -6,9 +6,11 @@
#include <unordered_map> #include <unordered_map>
class WebSocketSignalSession; class WebSocketSignalSession;
class Application;
class SignalServer { class SignalServer {
public: public:
SignalServer(Application &app);
void join(const std::string &id, WebSocketSignalSession *client); void join(const std::string &id, WebSocketSignalSession *client);
void leave(const std::string &id); void leave(const std::string &id);
WebSocketSignalSession *client(const std::string &id); WebSocketSignalSession *client(const std::string &id);

View File

@ -2,7 +2,6 @@
#include "BoostLog.h" #include "BoostLog.h"
#include "Database/Session.h" #include "Database/Session.h"
#include "IoContext.h" #include "IoContext.h"
#include "Listener.h"
#include "Live2dBackend.h" #include "Live2dBackend.h"
#include "MediaServer.h" #include "MediaServer.h"
#include "ProxyListener.h" #include "ProxyListener.h"
@ -10,6 +9,7 @@
#include "WeChatContext/CorporationContext.h" #include "WeChatContext/CorporationContext.h"
#include "WeChatContext/WeChatContext.h" #include "WeChatContext/WeChatContext.h"
#include "WebApplication/Application.h" #include "WebApplication/Application.h"
#include <boost/asio/signal_set.hpp>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <boost/property_tree/ini_parser.hpp> #include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
@ -64,11 +64,7 @@ int main(int argc, char const *argv[]) {
} }
BOOST_ASSERT_MSG(!application->getServer().empty(), "server.empty() == true"); BOOST_ASSERT_MSG(!application->getServer().empty(), "server.empty() == true");
Database::initialize(std::format("{}/database.sqlite", application->getApplicationRoot())); Database::initialize(std::format("{}/database.sqlite", application->getApplicationRoot()));
auto address = boost::asio::ip::make_address(application->getServer()); application->startAcceptHttpConnections(application->getServer(), application->getPort());
auto listener =
std::make_shared<Listener>(application->ioContext(), boost::asio::ip::tcp::endpoint{address, application->getPort()});
listener->startAccept();
auto wechatContext = Singleton<WeChatContext>::instance<Construct>(application->ioContext()); auto wechatContext = Singleton<WeChatContext>::instance<Construct>(application->ioContext());
auto corpContext = Singleton<CorporationContext>::instance<Construct>(application->ioContext()); auto corpContext = Singleton<CorporationContext>::instance<Construct>(application->ioContext());
corpContext->start(); corpContext->start();