VWeb/Source/Server.cpp
Maurice Grönwoldt 5bb68a7d02 Split VWeb into smaller headers
We have no make install support... so we don't need to have everything as a single-header and lib file.
2023-09-16 16:29:03 +02:00

145 lines
4.3 KiB
C++

#include "Includes/PreMiddleWare.h"
#include "Includes/VWeb.h"
#include <cstring>
namespace VWeb {
Server::Server() {
m_Router = CreateRef<Router>();
m_ServerConfig = CreateRef<ServerConfig>();
m_ServerConfig->EPoll = CreateRef<EPollManager>();
m_ServerConfig->Socket = CreateRef<SocketManager>(m_ServerConfig);
m_RequestHandler = CreateRef<RequestHandler>(m_ServerConfig->Socket);
auto &middleWare = m_RequestHandler->Middleware();
middleWare->Create<CookieManager>();
middleWare->Create<SessionManager>();
middleWare->Create<AuthWare>();
m_RequestHandler->m_Server = this;
};
void Server::LoadSharedLibs() {
// @TODO: LOAD .so files inside sub-folder
}
void Server::Start() {
m_ServerConfig->Socket->Init();
if (m_ServerConfig->Socket->IsErrored())
return;
m_RequestHandler->SetRouter(m_Router);
m_RequestHandler->InitThreads(m_ServerConfig->WorkerThreads);
m_WorkerThread = CreateRef<std::thread>(&Server::Execute, this);
fprintf(stdout, "[VWeb] Running Server On: 0.0.0.0:%d\n",
m_ServerConfig->Port);
}
void Server::AddRoute(const std::string &path, const Ref<Route> &route) {
m_Router->AddRoute(path, route);
}
void Server::RemoveRoute(const std::string &path) {
m_Router->DeleteRoute(path);
}
void Server::Execute() {
constexpr size_t MAX_EVENTS = 5000;
struct epoll_event events[MAX_EVENTS];
int sockID = m_ServerConfig->Socket->ID();
for (;;) {
if (m_IsExit)
break;
int eventCount = m_ServerConfig->EPoll->Wait(MAX_EVENTS, events);
for (int i = 0; i < eventCount; ++i) {
auto &event = events[i];
if ((event.events & EPOLLERR) || (event.events & EPOLLHUP)) {
m_RawRequest.Remove(event.data.fd);
SocketUtils::Close(event.data.fd);
continue;
}
if (event.events & EPOLLOUT) {
OutgoingExecute(events[i]);
}
if (event.data.fd == sockID) {
IncomingExecute(event);
} else if (event.events & EPOLLIN) {
HandleRequestReading(event);
}
}
}
}
void Server::OutgoingExecute(epoll_event &event) {
if (!m_OutRequest.Has(event.data.fd)) {
m_ServerConfig->Socket->SetReadListen(event.data.fd);
return;
}
auto &sendData = m_OutRequest.Get(event.data.fd);
auto returnVal = SocketUtils::Write(sendData);
if (returnVal == WriteState::ERRORED || returnVal == WriteState::OK) {
SocketUtils::WriteDone(sendData.SocketID);
m_OutRequest.Remove(event.data.fd);
}
}
void Server::IncomingExecute(epoll_event &event) {
for (;;) {
auto req = m_ServerConfig->Socket->Handle();
if (req.ReturnValue == EPollReturns::BREAK ||
req.ReturnValue == EPollReturns::FAILURE)
break;
else if (req.ReturnValue == EPollReturns::OK) {
if (!m_RawRequest.Add(req.SockId, req))
SocketUtils::Close(req.SockId);
} else
continue;
}
}
void Server::HandleRequestReading(epoll_event &event) {
int fd = event.data.fd;
if (!m_RawRequest.Has(fd)) {
SocketUtils::Close(fd);
return;
}
auto &data = m_RawRequest.Get(fd);
char buf[m_ServerConfig->BufferSize];
bool isFinished = false;
for (;;) {
memset(buf, 0, sizeof(buf));
ssize_t nBytes = recv(fd, buf, m_ServerConfig->BufferSize, 0);
if (nBytes < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
if (isFinished)
CreateRequest(fd);
break;
} else {
m_RawRequest.Remove(fd);
SocketUtils::Close(fd);
break;
}
} else if (nBytes == 0) {
m_RawRequest.Remove(fd);
SocketUtils::Close(fd);
} else {
if (m_ServerConfig->MaxBufferSize != -1 &&
data.CurrentBytes + nBytes > m_ServerConfig->MaxBufferSize) {
data.Data.clear();
data.Data << "GET @431 HTTP/1.1";
CreateRequest(fd);
break;
}
data.Data << buf;
data.CurrentBytes += nBytes;
if (nBytes < m_ServerConfig->BufferSize - 1) {
isFinished = true;
continue;
}
}
}
}
void Server::CreateRequest(int sockID) {
Accept &meAccept = m_RawRequest.Get(sockID);
auto request = CreateRef<Request>();
request->ID = meAccept.SockId;
request->Body = meAccept.Data.str();
m_RawRequest.Remove(sockID);
m_RequestHandler->AddRequest(request);
}
Ref<MiddleWareHandler> &Server::Middleware() {
return m_RequestHandler->Middleware();
}
} // namespace VWeb