feat(file server): implement file server with CLI options
Implement file server with CLI options for port and root directory, server initializes sessions, session handles file requests, and main function orchestrates setup and execution
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
#include "file_cli.hpp"
|
||||
|
||||
// helper for default values
|
||||
constexpr auto withDefault = [](auto value) {
|
||||
using T = decltype(value);
|
||||
return boost::program_options::value<T>()->default_value(value);
|
||||
};
|
||||
|
||||
FileCli::FileCli()
|
||||
: CliBase("File Server Options")
|
||||
, port_(9090)
|
||||
, rootDir_("./data")
|
||||
{
|
||||
}
|
||||
|
||||
void FileCli::setupOptions()
|
||||
{
|
||||
// clang-format off
|
||||
desc_.add_options()
|
||||
("help,h", "Show help message")
|
||||
("port,p", withDefault(9090), "Port to listen on")
|
||||
("root,r", withDefault(std::string("./data")), "Root directory for files");
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
int FileCli::getPort() const
|
||||
{
|
||||
return vm_["port"].as<int>();
|
||||
}
|
||||
|
||||
std::string FileCli::getRootDir() const
|
||||
{
|
||||
return vm_["root"].as<std::string>();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "cli_base.hpp"
|
||||
|
||||
class FileCli : public CliBase
|
||||
{
|
||||
public:
|
||||
FileCli();
|
||||
|
||||
int getPort() const;
|
||||
std::string getRootDir() const;
|
||||
|
||||
protected:
|
||||
void setupOptions() override;
|
||||
|
||||
private:
|
||||
int port_;
|
||||
std::string rootDir_;
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "file_server.hpp"
|
||||
#include "file_session.hpp"
|
||||
|
||||
FileServer::FileServer(IoContext &io, unsigned short port, std::string rootDir)
|
||||
: TcpServerBase(io, port)
|
||||
, rootDir_(std::move(rootDir))
|
||||
{
|
||||
}
|
||||
|
||||
void FileServer::createSession(TcpSocket socket)
|
||||
{
|
||||
std::make_shared<FileSession>(std::move(socket), rootDir_)->start();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "tcp_server_base.hpp"
|
||||
#include <string>
|
||||
|
||||
class FileServer : public TcpServerBase
|
||||
{
|
||||
public:
|
||||
FileServer(IoContext &io, unsigned short port, std::string rootDir);
|
||||
|
||||
protected:
|
||||
void createSession(TcpSocket socket) override;
|
||||
|
||||
private:
|
||||
std::string rootDir_;
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "file_session.hpp"
|
||||
#include "session_base.hpp"
|
||||
#include "logger.hpp"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
FileSession::FileSession(TcpSocket socket, std::string rootDir)
|
||||
: SessionBase(std::move(socket))
|
||||
, rootDir_(std::move(rootDir))
|
||||
{
|
||||
}
|
||||
|
||||
void FileSession::handleRequest(const std::string_view rawRequest)
|
||||
{
|
||||
// strip trailing newlines
|
||||
std::string fileName(rawRequest);
|
||||
while (!fileName.empty()
|
||||
&& (fileName.back() == '\r' || fileName.back() == '\n')) {
|
||||
fileName.pop_back();
|
||||
}
|
||||
|
||||
std::string filePath = rootDir_ + "/" + fileName;
|
||||
std::ifstream file(filePath, std::ios::binary);
|
||||
|
||||
std::ostringstream ss;
|
||||
if (file) {
|
||||
ss << file.rdbuf();
|
||||
Logger::info("File served: " + filePath);
|
||||
} else {
|
||||
ss << "File not found: " << fileName;
|
||||
Logger::warn("File not found: " + filePath);
|
||||
}
|
||||
|
||||
doWrite(ss.str());
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "session_base.hpp"
|
||||
|
||||
class FileSession : public SessionBase
|
||||
{
|
||||
public:
|
||||
FileSession(TcpSocket socket, std::string rootDir);
|
||||
|
||||
protected:
|
||||
void handleRequest(const std::string_view rawRequest) override;
|
||||
|
||||
private:
|
||||
std::string rootDir_;
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "file_cli.hpp"
|
||||
#include "file_server.hpp"
|
||||
#include "logger.hpp"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FileCli cli;
|
||||
cli.parse(argc, argv);
|
||||
|
||||
if (cli.isHelp()) {
|
||||
cli.printHelp();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Logger::init(true, "file_server.log");
|
||||
|
||||
IoContext io;
|
||||
FileServer server(io, cli.getPort(), cli.getRootDir());
|
||||
|
||||
Logger::info(
|
||||
"File server starting on port " + std::to_string(cli.getPort())
|
||||
+ ", root dir: " + cli.getRootDir()
|
||||
);
|
||||
|
||||
server.start();
|
||||
io.run();
|
||||
}
|
||||
Reference in New Issue
Block a user