From 167d87b41eb9a06c9609417d32c2d85031afab94 Mon Sep 17 00:00:00 2001 From: blankie Date: Mon, 3 Apr 2023 15:57:51 +0700 Subject: [PATCH] Add basic ass code --- .gitignore | 1 + .gitmodules | 3 +++ CMakeLists.txt | 35 ++++++++++++++++++++++++ config.cpp | 19 +++++++++++++ config.h | 12 +++++++++ example_config.json | 4 +++ file.h | 65 +++++++++++++++++++++++++++++++++++++++++++++ main.cpp | 44 ++++++++++++++++++++++++++++++ misc.cpp | 33 +++++++++++++++++++++++ misc.h | 7 +++++ routes/home.cpp | 5 ++++ routes/home.h | 5 ++++ thirdparty/httplib | 1 + 13 files changed, 234 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 config.cpp create mode 100644 config.h create mode 100644 example_config.json create mode 100644 file.h create mode 100644 main.cpp create mode 100644 misc.cpp create mode 100644 misc.h create mode 100644 routes/home.cpp create mode 100644 routes/home.h create mode 160000 thirdparty/httplib diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..6a59a3d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "thirdparty/httplib"] + path = thirdparty/httplib + url = https://github.com/yhirose/cpp-httplib.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..048190f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.25) + +project(pixwhile CXX) + + +find_package(nlohmann_json REQUIRED) +set(HTTPLIB_REQUIRE_OPENSSL ON) +add_subdirectory(thirdparty/httplib) + +if (CMAKE_BUILD_TYPE MATCHES "Debug") + if (NOT FLAGS) + list(APPEND FLAGS -fsanitize=undefined,thread) + endif() + # https://sourceforge.net/p/valgrind/mailman/valgrind-users/thread/Ygze8PzaQAYWlKDj%40wildebeest.org/ + list(APPEND FLAGS -gdwarf-4) +endif() + +# https://t.me/NightShadowsHangout/670691 +# # https://t.me/NightShadowsHangout/688372 +list(APPEND FLAGS -Werror -Wall -Wextra -Wshadow -Wpedantic -Wno-gnu-anonymous-struct -fPIC -fno-rtti -Wconversion -Wno-unused-parameter -Wimplicit-fallthrough) + +# i have no idea why this hack wasn't needed before but it's needed if sanitizers are used +add_link_options(${FLAGS}) + + +add_executable(${PROJECT_NAME} main.cpp misc.cpp config.cpp routes/home.cpp) +set_target_properties(${PROJECT_NAME} + PROPERTIES + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED YES + CXX_EXTENSIONS NO +) +target_include_directories(${PROJECT_NAME} PRIVATE thirdparty) +target_link_libraries(${PROJECT_NAME} PRIVATE nlohmann_json::nlohmann_json httplib::httplib) +target_compile_options(${PROJECT_NAME} PRIVATE ${FLAGS}) diff --git a/config.cpp b/config.cpp new file mode 100644 index 0000000..9454de4 --- /dev/null +++ b/config.cpp @@ -0,0 +1,19 @@ +#include + +#include "file.h" +#include "config.h" + +Config load_config(const char* path) { + File config_file(path, "r"); + return nlohmann::json::parse(config_file.get()); +} + +void from_json(const nlohmann::json& j, Config& config) { + using namespace std::string_literals; + + j.at("bind_host").get_to(config.bind_host); + j.at("bind_port").get_to(config.bind_port); + if (config.bind_port < 0) { + throw std::invalid_argument("Invalid port to bind to: "s + std::to_string(config.bind_port)); + } +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..98058a5 --- /dev/null +++ b/config.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +struct Config { + std::string bind_host = "127.0.0.1"; + int bind_port = 8080; +}; + +Config load_config(const char* path); +void from_json(const nlohmann::json& j, Config& config); diff --git a/example_config.json b/example_config.json new file mode 100644 index 0000000..b06ce88 --- /dev/null +++ b/example_config.json @@ -0,0 +1,4 @@ +{ + "bind_host": "127.0.0.1", + "bind_port": 8080 +} diff --git a/file.h b/file.h new file mode 100644 index 0000000..db7fdfd --- /dev/null +++ b/file.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include + +#include "misc.h" + +static void try_close(FILE* file); + +class File { +public: + // https://stackoverflow.com/a/2173764 + File(const File&) = delete; + File& operator=(const File&) = delete; + + inline constexpr File(File&& other) { + try_close(this->_file); + this->_file = other._file; + other._file = nullptr; + } + inline constexpr File& operator=(File&& other) { + if (this == &other) { + return *this; + } + + try_close(this->_file); + this->_file = other._file; + other._file = nullptr; + + return *this; + } + + File(const char* __restrict path, const char* __restrict mode) { + using namespace std::string_literals; + + this->_file = fopen(path, mode); + if (!this->_file) { + throw_system_error("fopen("s + quote(path) + ')'); + } + } + ~File() { + try_close(this->_file); + } + + void write(const char* data, size_t length) { + if (fwrite(data, 1, length, this->_file) != length) { + throw_system_error("fwrite()"); + } + } + inline constexpr void write(const std::string& str) { + this->write(str.data(), str.size()); + } + inline constexpr FILE* get() const noexcept { + return this->_file; + } + +protected: + FILE* _file = nullptr; +}; + +static void try_close(FILE* file) { + if (file && fclose(file)) { + perror("Failed to close a file: fclose()"); + } +} diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..ec3900c --- /dev/null +++ b/main.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +#include "config.h" +#include "routes/home.h" + +int main(int argc, char** argv) { + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argc > 0 ? argv[0] : "pixwhile"); + return 1; + } + + Config config; + try { + config = load_config(argv[1]); + } catch (const std::exception& e) { + fprintf(stderr, "Failed to load config: %s\n", e.what()); + return 1; + } + + httplib::Server server; + server.Get("/", home_route); + + if (config.bind_port != 0) { + if (!server.bind_to_port(config.bind_host, config.bind_port)) { + fprintf(stderr, "Failed to bind to %s:%d\n", config.bind_host.c_str(), config.bind_port); + return 1; + } + } else { + int port = server.bind_to_any_port(config.bind_host); + if (port == -1) { + fprintf(stderr, "Failed to bind to %s:\n", config.bind_host.c_str()); + return 1; + } + config.bind_port = port; + } + printf("Listening on %s:%d...\n", config.bind_host.c_str(), config.bind_port); + + if (!server.listen_after_bind()) { + fprintf(stderr, "Failed to listen on %s:%d\n", config.bind_host.c_str(), config.bind_port); + return 1; + } +} diff --git a/misc.cpp b/misc.cpp new file mode 100644 index 0000000..6da5a7a --- /dev/null +++ b/misc.cpp @@ -0,0 +1,33 @@ +#include +#include +#include + +#include "misc.h" + +std::string quote(const std::string& str) { + std::stringstream ss; + ss << std::quoted(str); + return ss.str(); +} + +void throw_system_error(int err, const char* what) { + if (err == ENOMEM) { + throw std::bad_alloc(); + } + throw std::system_error(err, std::generic_category(), what); +} + +void throw_system_error(int err, std::string what) { + if (err == ENOMEM) { + throw std::bad_alloc(); + } + throw std::system_error(err, std::generic_category(), std::move(what)); +} + +void throw_system_error(const char* what) { + throw_system_error(errno, what); +} + +void throw_system_error(std::string what) { + throw_system_error(errno, std::move(what)); +} diff --git a/misc.h b/misc.h new file mode 100644 index 0000000..94785ee --- /dev/null +++ b/misc.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +std::string quote(const std::string& str); +void throw_system_error(const char* what); +void throw_system_error(std::string what); diff --git a/routes/home.cpp b/routes/home.cpp new file mode 100644 index 0000000..3e7db15 --- /dev/null +++ b/routes/home.cpp @@ -0,0 +1,5 @@ +#include "home.h" + +void home_route(const httplib::Request& req, httplib::Response& res) { + res.set_content("awoo", "text/plain"); +} diff --git a/routes/home.h b/routes/home.h new file mode 100644 index 0000000..582811c --- /dev/null +++ b/routes/home.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void home_route(const httplib::Request& req, httplib::Response& res); diff --git a/thirdparty/httplib b/thirdparty/httplib new file mode 160000 index 0000000..e5804d4 --- /dev/null +++ b/thirdparty/httplib @@ -0,0 +1 @@ +Subproject commit e5804d4a50eb2fa0412d449a2fee86d613ad7104