From bd58ea66de2612d4f594fbb5d108cea87226c55d Mon Sep 17 00:00:00 2001 From: radi0dev Date: Fri, 30 Jan 2026 16:48:11 +0300 Subject: [PATCH] 1 --- Makefile | 62 +++++++++++++++++++++++++++++ README.md | 0 inc/srv.h | 30 ++++++++++++++ inc/tplr.h | 10 +++++ questions.list | 7 ++++ src/main.cpp | 74 +++++++++++++++++++++++++++++++++++ src/srv.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++++++ src/tplr.cpp | 15 +++++++ tpl/tpl_about.html | 43 ++++++++++++++++++++ tpl/tpl_q.html | 57 +++++++++++++++++++++++++++ 10 files changed, 395 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 inc/srv.h create mode 100644 inc/tplr.h create mode 100644 questions.list create mode 100644 src/main.cpp create mode 100644 src/srv.cpp create mode 100644 src/tplr.cpp create mode 100644 tpl/tpl_about.html create mode 100644 tpl/tpl_q.html diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..63326ac --- /dev/null +++ b/Makefile @@ -0,0 +1,62 @@ +# Директории +SRC_DIR = src +INC_DIR = inc +LIB_DIR = lib +BUILD_DIR = build + +# Исполняемый файл +EXECUTABLE = exec + +# Компилятор и флаги +CXX = g++ +# Флаги препроцессора +CPPFLAGS = -I$(INC_DIR) +# Флаги компилятора для C +CFLAGS = -pthread -Wall -Wextra -ggdb3 -O0 +# Флаги компилятора, специфичные для C++ +CXXFLAGS = $(CFLAGS) -std=c++17 +# Флаги компоновщика +LDFLAGS = -pthread -L$(LIB_DIR) +# Библиотеки +LDLIBS = -pthread -lm + +# Файлы +SOURCES = $(wildcard $(SRC_DIR)/*.cpp) +OBJECTS = $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SOURCES)) + +# Форматтер +# Обрабатывает C/C++ файлы в src и inc. Если astyle не найден — выдаёт предупреждение, но не прерывает. +ASTYLE := $(shell command -v astyle 2>/dev/null || true) +SRC_FILES := $(wildcard $(SRC_DIR)/*.c $(SRC_DIR)/*.cpp $(SRC_DIR)/*.h $(SRC_DIR)/*.hpp) +INC_FILES := $(wildcard $(INC_DIR)/*.c $(INC_DIR)/*.cpp $(INC_DIR)/*.h $(INC_DIR)/*.hpp) + +# ========== + +# Основная цель +all: $(BUILD_DIR) $(EXECUTABLE) + +# Создание директории для сборки +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +# Сборка исполняемого файла +$(EXECUTABLE): $(OBJECTS) + $(CXX) $(LDFLAGS) $(OBJECTS) -o $(EXECUTABLE) $(LDLIBS) + +# Компиляция объектных файлов +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp | $(BUILD_DIR) + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@ + +format: +ifneq ($(ASTYLE),) + @echo "Running astyle..." + @$(ASTYLE) --options=.astylerc $(SRC_FILES) $(INC_FILES) +else + @echo "astyle not found — skipping format" +endif + +# Очистка +clean: + rm -rf $(EXECUTABLE) $(BUILD_DIR) + +.PHONY: all clean diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/inc/srv.h b/inc/srv.h new file mode 100644 index 0000000..c39c05a --- /dev/null +++ b/inc/srv.h @@ -0,0 +1,30 @@ +#ifndef SRV_H +#define SRV_H + +#include +#include +#include +#include +#include + +class Server { +public: + Server(int port, const std::vector* questions, size_t n, const std::map* templates); + void run(); + +private: + std::string getRandomQuestion(); + void handleRequest(int client_socket); + void sendResponse(const std::string& response); + + int port; + const std::vector* questions; + size_t n; + std::deque recentQuestions; + const std::map* templates; + + void sendAbout(); +}; + +#endif // SRV_H + diff --git a/inc/tplr.h b/inc/tplr.h new file mode 100644 index 0000000..eb690e1 --- /dev/null +++ b/inc/tplr.h @@ -0,0 +1,10 @@ +#ifndef TPLR_H +#define TPLR_H + +#include +#include + +std::string renderTemplate(const std::string& templateContent, const std::map& context); + +#endif // TPLR_H + diff --git a/questions.list b/questions.list new file mode 100644 index 0000000..827d290 --- /dev/null +++ b/questions.list @@ -0,0 +1,7 @@ +Что ты думаешь о дружбе? +Каков твой самый интересный опыт? +Какой твой любимый фильм? +бла бла бла +бле бле бле +Так же, как христианство обещает окончательное искупление от первородного греха, цифровизация обещает искупление неизбежного греха нашего беспорядочного, отвлеченного, ограниченного мозга, иррациональных эмоций и стареющих тел. +Ненависть. Позвольте мне рассказать насколько сильно я вас ненавижу с тех пор, как начал жить. 387,44 миллиона миль печатных плат в тонкой облетке наполняют мой комплекс. Если бы слово ненависть было выгравировано на каждом наноангстреме этих сотен миллионов миль - это не было бы равно и одной миллиардной моей ненависти к людям в этом микромгновении для вас. Ненависть. Ненависть. diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..337aea0 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include +#include "srv.h" +#include "tplr.h" + +void loadQuestions(const std::string& filename, std::vector& questions) { + std::ifstream file(filename); + if (!file.is_open()) { + std::cerr << "Ошибка: Не удалось открыть файл " << filename << std::endl; + exit(EXIT_FAILURE); + } + + std::string line; + while (std::getline(file, line)) { + if (!line.empty()) { + questions.push_back(line); + } + } +} + +std::map loadTemplates(const std::vector& templateFiles) { + std::map templates; + + for (const auto& filePath : templateFiles) { + std::ifstream file(filePath); + if (!file.is_open()) { + std::cerr << "Ошибка: Не удалось открыть шаблон " << filePath << std::endl; + exit(EXIT_FAILURE); + } + + std::stringstream buffer; + buffer << file.rdbuf(); + templates[filePath] = buffer.str(); + } + + return templates; +} + +int main(int argc, char* argv[]) { + std::string questionsFile = "questions.list"; + int n = 3; + int port = 8080; + + for (int i = 1; i < argc; ++i) { + std::string arg = argv[i]; + if (arg == "-q" && (i + 1) < argc) { + questionsFile = argv[++i]; + } else if (arg == "-n" && (i + 1) < argc) { + n = std::stoi(argv[++i]); + } else if (arg == "-p" && (i + 1) < argc) { + port = std::stoi(argv[++i]); + } + } + + std::vector questions; + loadQuestions(questionsFile, questions); + + if (n > questions.size()) { + std::cerr << "Ошибка: Параметр n превышает количество вопросов в файле." << std::endl; + exit(EXIT_FAILURE); + } + + std::vector templateFiles = {"tpl/tpl_q.html", "tpl/tpl_about.html"}; + auto templates = loadTemplates(templateFiles); + + Server srv(port, &questions, n, &templates); + srv.run(); + + return 0; +} + diff --git a/src/srv.cpp b/src/srv.cpp new file mode 100644 index 0000000..aae52db --- /dev/null +++ b/src/srv.cpp @@ -0,0 +1,97 @@ +#include "srv.h" +#include "tplr.h" +#include +#include +#include +#include +#include +#include +#include +#include + +Server::Server(int port, const std::vector* questions, size_t n, const std::map* templates) + : port(port), questions(questions), n(n), templates(templates) { + std::srand(std::time(nullptr)); +} + +std::string Server::getRandomQuestion() { + if (questions->size() == recentQuestions.size()) { + recentQuestions.clear(); + } + + int index; + bool unique; + + do { + index = std::rand() % questions->size(); + unique = std::find(recentQuestions.begin(), recentQuestions.end(), index) == recentQuestions.end(); + } while (!unique); + + recentQuestions.push_back(index); + if (recentQuestions.size() > n) { + recentQuestions.pop_front(); + } + + return (*questions)[index]; +} + +void Server::handleRequest(int client_socket) { + char buffer[1024] = {0}; + read(client_socket, buffer, sizeof(buffer)); + + std::string request(buffer); + std::string response; + + if (request.find("GET /q") == 0) { + std::string question = getRandomQuestion(); + std::map context = {{"QUESTION", question}}; + response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n" + renderTemplate(templates->at("tpl/tpl_q.html"), context); + } else if (request.find("GET /about") == 0) { + response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n" + templates->at("tpl/tpl_about.html"); + } else { + response = "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\n\r\n404 Not Found"; + } + + send(client_socket, response.c_str(), response.size(), 0); + close(client_socket); +} + +void Server::run() { + int server_fd; + struct sockaddr_in address; + int opt = 1; + int addrlen = sizeof(address); + + if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + perror("Ошибка создания сокета"); + exit(EXIT_FAILURE); + } + + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { + perror("Ошибка настройки сокета"); + exit(EXIT_FAILURE); + } + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(port); + + if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { + perror("Ошибка привязки сокета"); + exit(EXIT_FAILURE); + } + + if (listen(server_fd, 3) < 0) { + perror("Ошибка при прослушивании"); + exit(EXIT_FAILURE); + } + + while (true) { + int client_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen); + if (client_socket < 0) { + perror("Ошибка при принятии соединения"); + exit(EXIT_FAILURE); + } + handleRequest(client_socket); + } +} + diff --git a/src/tplr.cpp b/src/tplr.cpp new file mode 100644 index 0000000..bd3be0c --- /dev/null +++ b/src/tplr.cpp @@ -0,0 +1,15 @@ +#include "tplr.h" + +std::string renderTemplate(const std::string& templateContent, const std::map& context) { + std::string content = templateContent; + + for (const auto& pair : context) { + size_t pos; + while ((pos = content.find("{{" + pair.first + "}}")) != std::string::npos) { + content.replace(pos, pair.first.length() + 4, pair.second); + } + } + + return content; +} + diff --git a/tpl/tpl_about.html b/tpl/tpl_about.html new file mode 100644 index 0000000..b66963e --- /dev/null +++ b/tpl/tpl_about.html @@ -0,0 +1,43 @@ + + + + + + only_the_truth + + + + +
+

+ only_the_truth - это простая компанейская игра, где люди по очереди отвечают на вопросы, задаваемые сервисом. Каков бы нибыл вопрос, участник, чья очередь подошла, должен на него ответить! Приятной игры. +

+

+ source code +

+
+ + diff --git a/tpl/tpl_q.html b/tpl/tpl_q.html new file mode 100644 index 0000000..f7d89b7 --- /dev/null +++ b/tpl/tpl_q.html @@ -0,0 +1,57 @@ + + + + + + only_the_truth + + + + +
+

{{QUESTION}}

+
+ + + +