Add basic ass code
This commit is contained in:
commit
167d87b41e
|
@ -0,0 +1 @@
|
|||
/build
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "thirdparty/httplib"]
|
||||
path = thirdparty/httplib
|
||||
url = https://github.com/yhirose/cpp-httplib.git
|
|
@ -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})
|
|
@ -0,0 +1,19 @@
|
|||
#include <stdexcept>
|
||||
|
||||
#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));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
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);
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"bind_host": "127.0.0.1",
|
||||
"bind_port": 8080
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
#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()");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#include <cstdio>
|
||||
#include <httplib/httplib.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "config.h"
|
||||
#include "routes/home.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <path/to/config/file.json>\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:<any>\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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <system_error>
|
||||
|
||||
#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));
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string quote(const std::string& str);
|
||||
void throw_system_error(const char* what);
|
||||
void throw_system_error(std::string what);
|
|
@ -0,0 +1,5 @@
|
|||
#include "home.h"
|
||||
|
||||
void home_route(const httplib::Request& req, httplib::Response& res) {
|
||||
res.set_content("awoo", "text/plain");
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <httplib/httplib.h>
|
||||
|
||||
void home_route(const httplib::Request& req, httplib::Response& res);
|
|
@ -0,0 +1 @@
|
|||
Subproject commit e5804d4a50eb2fa0412d449a2fee86d613ad7104
|
Loading…
Reference in New Issue