Files
2026-09-11 17:12:18 +08:00

229 lines
6.9 KiB
C++

#include "ServerCore.h"
#include "Global.h"
#include "IPTable.h"
#include "ServerLogger.h"
#include "CORSProcessor.h"
#include <webcc/logger.h>
#include <webcc/server.h>
#include <webcc/utility.h>
#include "ProcessorAdapter.h"
class ServerCore::Impl
{
public:
int port = 0;
IPTable BlockedIPs;
std::thread thServer;
webcc::Server* ccServer = nullptr;
std::atomic_bool server_started = false;
public:
explicit Impl(int port)
{
this->port = port;
ccServer = new webcc::Server(boost::asio::ip::tcp::v4(), port);
ccServer->SetDefaultServerName(G_SERVER_NAME);
webcc::utility::SetCustomUA(G_SERVER_NAME);
SCLOGF_INFO("ServerCore constructed on port {}, version: <{}>", port, G_SERVER_NAME);
}
~Impl()
{
if(ccServer != nullptr)
{
// if(ccServer->IsRunning())
// ccServer->Stop();
// delete ccServer;
//Fix Crash
ccServer->Stop();
if (thServer.joinable())
thServer.join();
delete ccServer;
ccServer = nullptr;
}
}
public:
static void ServerThreadFunction(webcc::Server* server, int worker_thread, int loop_thread, std::atomic_bool* started_flag)
{
if (server == nullptr)
return;
server->set_buffer_size(65535);
SCLOGF_INFO("ServerCore thread ready: {} Worker(s), {} Loop(s)", worker_thread, loop_thread);
if (started_flag)
started_flag->store(true, std::memory_order_release);
server->Run(worker_thread, loop_thread);
return;
}
static webcc::Strings ConvertMethods(std::uint32_t dwmethod)
{
webcc::Strings res;
if (dwmethod & uns::H_GET)
res.push_back("GET");
if (dwmethod & uns::H_PUT)
res.push_back("PUT");
if (dwmethod & uns::H_HEAD)
res.push_back("HEAD");
if (dwmethod & uns::H_POST)
res.push_back("POST");
if (dwmethod & uns::H_TRACE)
res.push_back("TRACE");
if (dwmethod & uns::H_PATCH)
res.push_back("PATCH");
if (dwmethod & uns::H_DELETE)
res.push_back("DELETE");
if (dwmethod & uns::H_OPTIONS)
res.push_back("OPTIONS");
if (dwmethod & uns::H_CONNECT)
res.push_back("CONNECT");
return res;
}
};
ServerCore::ServerCore(int port) : pimpl(std::make_unique<Impl>(port))
{
}
ServerCore::~ServerCore() = default;
void ServerCore::Run(int worker_thread, int loop_thread)
{
if (pimpl->ccServer == nullptr)
return;
pimpl->ccServer->set_buffer_size(10240);
SCLOGF_INFO("ServerCore ready: {} Worker(s), {} Loop(s)", worker_thread, loop_thread);
pimpl->ccServer->Run(worker_thread, loop_thread);
return;
}
bool ServerCore::ThreadRun(int worker_thread, int loop_thread)
{
using namespace std::chrono;
if (pimpl->ccServer == nullptr)
return false;
if (pimpl->thServer.joinable())
{
SCLOG_ERROR("ServerCore::ThreadRun called while a server thread is already active");
return false; // 或直接 return,视你采纳下面的返回值方案而定
}
pimpl->server_started.store(false, std::memory_order_relaxed);
pimpl->thServer = std::thread(Impl::ServerThreadFunction, pimpl->ccServer, worker_thread, loop_thread, &pimpl->server_started);
bool reached_run = false;
for (int i = 0; i < 500; i++)
{
if (pimpl->server_started.load(std::memory_order_acquire))
{
reached_run = true;
break;
}
std::this_thread::sleep_for(1ms);
}
if (!reached_run)
{
SCLOGF_FATAL("ServerCore thread failed to schedule within 500ms (port {})", pimpl->port);
// 尽力而为的安全收尾:即使线程迟迟没被调度起来,它终究会跑到 Run(),
// 而 Run() 会一直阻塞直到 Stop() 生效——所以这里调用 Stop()+join()
// 依然能把这个半启动状态收拾干净,不会遗留一个不受控的线程。
pimpl->ccServer->Stop();
if (pimpl->thServer.joinable())
pimpl->thServer.join();
return false;
}
bool running = pimpl->ccServer->IsRunning();
if (running)
SCLOG_INFO("ServerCore Running");
else
SCLOGF_ERROR("ServerCore failed to start listening on port {}", pimpl->port);
return running;
}
void ServerCore::Stop()
{
if (pimpl->ccServer == nullptr)
return;
pimpl->ccServer->Stop();
if (pimpl->thServer.joinable())
pimpl->thServer.join();
SCLOG_INFO("ServerCore Stopped");
return;
}
bool ServerCore::Running()
{
return pimpl->ccServer->IsRunning();
}
void ServerCore::UpdateProcessor()
{
for (size_t i = 0; i < pimpl->ccServer->GetViewCount(); i++)
{
auto updatable_ptr = std::dynamic_pointer_cast<uns::IBlockedIpUpdatable>(pimpl->ccServer->AccessView(i));
if (updatable_ptr != nullptr)
updatable_ptr->ApplyIpUpdate(&pimpl->BlockedIPs);
}
SCLOG_TRACE("Blocked IP list updated");
return;
}
bool ServerCore::EnableCORSSupport()
{
return AppenedProcessor(CORSProcessor::UrlRegex(), CORSProcessor::SharedPtr(), uns::H_OPTIONS);
}
bool ServerCore::AppenedProcessor(std::string url, ServerProcessorPtr ptr, std::uint32_t methods, bool enable_ip_check)
{
if (enable_ip_check)
{
ptr->EnableIPCheck();
ptr->UpdateBlockedIPList(&pimpl->BlockedIPs);
}
auto adapter = std::make_shared<uns::ServerProcessorAdapter>(ptr);
bool bret = pimpl->ccServer->Route(webcc::UrlRegex(url), adapter, Impl::ConvertMethods(methods));
if (bret)
SCLOGF_INFO("ServerProcessor added. URL: [{}], Method code: <{}>", url, uns::toBinary(methods, 10));
else
SCLOGF_ERROR("ServerProcessor add faliure. URL: [{}], Method code: <{}>", url, uns::toBinary(methods, 10));
return bret;
}
bool ServerCore::AppenedFileReceiver(std::string url, FileReceiverPtr ptr, std::uint32_t methods, FileProcessorCallback fpcb, bool html_response)
{
ptr->SetFileCallback(fpcb);
ptr->UpdateBlockedIPs(&pimpl->BlockedIPs);
ptr->SetResponseMode(html_response);
auto adapter = std::make_shared<uns::FileReceiverAdapter>(ptr);
bool bret = pimpl->ccServer->Route(webcc::UrlRegex(url), adapter, Impl::ConvertMethods(methods));
if (bret)
SCLOGF_INFO("FileReceiver added. URL: [{}], Method code: <{}>", url, uns::toBinary(methods, 10));
else
SCLOGF_ERROR("FileReceiver add faliure. URL: [{}], Method code: <{}>", url, uns::toBinary(methods, 10));
return bret;
}
bool ServerCore::AppenedFileReceiver(std::string url, SyncFileReceiverPtr ptr, std::uint32_t methods, bool html_response)
{
ptr->UpdateBlockedIPs(&pimpl->BlockedIPs);
ptr->SetResponseMode(html_response);
auto adapter = std::make_shared<uns::SyncFileReceiverAdapter>(ptr);
bool bret = pimpl->ccServer->Route(webcc::UrlRegex(url), adapter, Impl::ConvertMethods(methods));
if (bret)
SCLOGF_INFO("SyncFileReceiver added. URL: [{}], Method code: <{}>", url, uns::toBinary(methods, 10));
else
SCLOGF_ERROR("SyncFileReceiver add faliure. URL: [{}], Method code: <{}>", url, uns::toBinary(methods, 10));
return bret;
}
void ServerCore::EnableWebCCLog(const std::string& path, int level)
{
if(path.empty())
{
WEBCC_LOG_INIT_2("", webcc::LOG_CONSOLE, level);
}
else
{
WEBCC_LOG_INIT_2(path.c_str(), webcc::LOG_CONSOLE | webcc::LOG_CONSOLE_FILE_APPEND, level);
}
}