diff --git a/README.md b/README.md index 6c9997f..e1d0fb8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,60 @@ -# ИУ9-21Б Вэб-чат C.A +# IU9 C.A. WEB CHAT -Сделан на летней практике 5-ю первокурсниками ИУ9 +C.A. stands for Collarbone Annihilation. + +Сделан на летней практике 5-ю первокурсниками из ИУ9-21Б. + +# Dependencies + +iu9-ca-web-chat использует +- C++ +- [regexis024-build-system]( + https://peppermintgingerbread.zip/collarbone-annihilation/regexis024-build-system + ) +- [libregexis024]( + https://peppermintgingerbread.zip/kme-devline/libregexis024 + ) +- [libjsonincpp]( + https://peppermintgingerbread.zip/collarbone-annihilation/libjsonincpp + ) +- [sqlite3]( + https://www.sqlite.org + ) +- pkg-config и pkg-config файлики для всех этих зависимостей + +Сервис так же использует библиотеки engine_engine_number_9 и new_york_transit_line, +размещённые прямо в репозитории. + +Работает только на unix системах. + +# Compilation + +```sh +./building/build_build_sytem.sh +./building/main bi ./ "absolute/path/to/installation/root" +``` +# Usage + +Помимо самого бинарника нужен файл с настройками сервиса. Формат настроек: JSON. +Комментарии не поддерживаются. Пример такого файла находится в example/config.json. +Вместе с бинарным фалом так же распространяются ассеты, необъходимые для работы сайта. +Их можно найти в папке assets. В настроках (поле `["assets"]`) указывается путь до +папки с ассетами. Путь может быть как абсолютным, так и относительным к рабочей директории. +Поле настроек `["database"]` указывает как соединиться с базой данных. +Поддерживается только база данных sqlite. Поддерживается только хранение в файле. +Поле `["database"]["file"]` указывает путь где хранится sqlite база данных. + +Перед тем как использовать сервис нужно его проинициализировать (а точнее проинициализировать +базу данных): + +`ROOT_PW="" iu9-ca-web-chat /path/to/config.json initialize` + +Переменная окружения `ROOT_PW` читается для устаановки пароля root пользователю раз и навсегда. +Далее можно запускать сервис: + +`iu9-ca-web-chat /path/to/config.json run` + +Для остановки сервиса киньте ему SIGTERM или SIGINT. # Список участников @@ -10,3 +64,13 @@ 4. [Каримов Адель](https://gitflic.ru/user/ra1n) 5. [Яковлев Антон](https://gitflic.ru/user/yakovlevanton) +# Комментарии (для разработчиков) + +Зачем писать комментарии в коде, если можно их вынести в отдельные пдф-ки? + +- [API сервиса]( + https://peppermintgingerbread.zip/collarbone-annihilation/iu9-ca-chat-api) +- [Доки New York Transit Line]( + https://peppermintgingerbread.zip/collarbone-annihilation/new_york_transit_line_documentation_rus) + +О том как работает всё остальное можно только догадываться. diff --git a/building/main.cpp b/building/main.cpp index 5eb43fa..48ba626 100644 --- a/building/main.cpp +++ b/building/main.cpp @@ -141,7 +141,11 @@ struct CAWebChat { T.external_deps = { CTargetDependenceOnExternalLibrary{"sqlite3"} }; - T.units = {"main.cpp"}; + T.units = { + "main.cpp", + "initialize.cpp", + "run.cpp", + }; for (std::string& u: T.units) u = "web_chat/" + u; T.include_pr = "web_chat"; diff --git a/src/web_chat/actions.h b/src/web_chat/actions.h new file mode 100644 index 0000000..edea856 --- /dev/null +++ b/src/web_chat/actions.h @@ -0,0 +1,9 @@ +#ifndef IU9_CA_WEB_CHAT_ACTIONS_H +#define IU9_CA_WEB_CHAT_ACTIONS_H + +#include + +void run_website(const json::JSON& config); +void initialize_website(const json::JSON& config, const std::string& root_pw); + +#endif diff --git a/src/web_chat/initialize.cpp b/src/web_chat/initialize.cpp new file mode 100644 index 0000000..a14406a --- /dev/null +++ b/src/web_chat/initialize.cpp @@ -0,0 +1,5 @@ +#include "actions.h" + +void initialize_website(const json::JSON& config, const std::string& root_pw) { + +} \ No newline at end of file diff --git a/src/web_chat/main.cpp b/src/web_chat/main.cpp index c14e7c3..8d90e25 100644 --- a/src/web_chat/main.cpp +++ b/src/web_chat/main.cpp @@ -1,122 +1,39 @@ #include -#include -#include -#include -#include +#include #include -#include #include -#include -#include -#include - -bool termination = false; - -void sigterm_action(int) { - termination = true; -} +#include "actions.h" void usage(char** argv) { printf("Usage: %s \n", argv[0]); exit(1); } -std::string unsafe_client_request_stringification(const een9::ClientRequest& req) { - std::string text = "\n\nGot some cool stuff\n"; - text += (req.method + " " + req.uri_path + " " + req.http_version + "\n"); - for (auto& p: req.headers) { - text += p.first; text += ": "; text += p.second; text += "\n"; - } - text += "Body\n"; text += req.body; text += "\n"; - return text; -} - int main(int argc, char** argv){ try { een9_ASSERT_pl(argc > 0); - if (argc < 1 + 1) + if (argc != 1 + 2) usage(argv); - if (!een9::isRegularFile(argv[1]) || !een9::endsIn(argv[1], ".json")) { + std::string config_file = argv[1]; + if (!een9::isRegularFile(config_file) || !een9::endsIn(config_file, ".json")) { printf("\"%s\" is not a json file\n", argv[1]); usage(argv); } - std::string config_file = argv[1]; - + std::string cmd = argv[2]; std::string config_text; een9::readFile(config_file, config_text); - json::JSON config = json::parse_str_flawless(config_text); - een9_ASSERT(config.isDictionary(), "config root is not dictionary"); - een9_ASSERT(config["assets"].g().isString(), "config[\"\assets\"] is not string"); - std::string assets_dir = config["assets"].g().asString(); - een9_ASSERT(een9::isDirectory(assets_dir), "\"" + assets_dir + "\" is not a directory"); + const json::JSON config = json::parse_str_flawless(config_text); - een9::StaticAssetManagerSlaveModule samI; - samI.update({ - een9::StaticAssetManagerRule{assets_dir + "/css", "/assets/css", {{".css", "text/css"}} }, - een9::StaticAssetManagerRule{assets_dir + "/js", "/assets/js", {{".js", "text/js"}} }, - een9::StaticAssetManagerRule{assets_dir + "/img", "/assets/img", { - {".jpg", "image/jpg"}, {".png", "image/png"}, {".svg", "image/svg+xml"} - } }, - }); - - json::JSON& config_presentation = config["presentation"].g(); - - /* Because templaters use libjsonincpp, they can't be READ by two thread simultaneously */ - std::vector> templaters_copies(8); - for (int i = 0; i < 8; i++) { - templaters_copies[i] = std::make_unique( - nytl::TemplaterSettings{nytl::TemplaterDetourRules{assets_dir + "/HypertextPages"}}); - templaters_copies[i]->update(); - } - - // printf("%s\n", templaters_copies[0]->render("list-rooms", {&config_presentation}).c_str()); - // return 0; - - een9::MainloopParameters params; - params.guest_core = [&samI, &templaters_copies, config_presentation] - (const een9::SlaveTask& task, const een9::ClientRequest& req, een9::worker_id_t worker_id) -> std::string { - een9_ASSERT_pl(0 <= worker_id && worker_id < templaters_copies.size()); - nytl::Templater& templater = *templaters_copies[worker_id]; - een9::StaticAsset sa; - int ret; - // printf("%s", unsafe_client_request_stringification(req).c_str()); - // if (req.uri_path == "/output") { - // std::string text = unsafe_client_request_stringification(req); - // return een9::form_http_server_response_200("text/plain", text); - // } - auto rteee = [&](const std::string& el_name, bool pass_phr) -> std::string { - std::string page = templater.render(el_name, - pass_phr ? std::vector{&config_presentation} : std::vector{}); - return een9::form_http_server_response_200("text/html", page); - }; - if (req.uri_path == "/" || req.uri_path == "/list-rooms") { - return rteee("list-rooms", true); - } - if (req.uri_path == "/chat") { - return rteee("chat", false); - } - if (req.uri_path == "/profile") { - return rteee("profile", false); - } - if (req.uri_path == "/registration") { - return rteee("registration", false); - } - /* Trying to interpret request as asset lookup */ - ret = samI.get_asset(req.uri_path, sa); - if (ret >= 0) { - return een9::form_http_server_response_200(sa.type, sa.content); - } - return een9::form_http_server_response_404("text/html", "

Not found!

"); - }; - - params.ports_to_listen = {1025}; - params.slave_number = 8; - params.open_admin_listener = false; - - signal(SIGINT, sigterm_action); - signal(SIGTERM, sigterm_action); - - een9::electric_boogaloo(params, termination); + if (cmd == "initialize") { + const char* ROOT_PW = getenv("ROOT_PW"); + een9_ASSERT(ROOT_PW, "No root password specified." + "Assign desired root password value to environment variable ROOT_PW"); + std::string root_pw = ROOT_PW; + initialize_website(config, root_pw); + } else if (cmd == "run") { + run_website(config); + } else + een9_THROW("unknown action (known are 'run', 'initialize')"); } catch (std::exception& e) { printf("System failure\n%s\n", e.what()); } diff --git a/src/web_chat/run.cpp b/src/web_chat/run.cpp new file mode 100644 index 0000000..eb1a3a0 --- /dev/null +++ b/src/web_chat/run.cpp @@ -0,0 +1,103 @@ +#include "actions.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +bool termination = false; + +void sigterm_action(int) { + termination = true; +} + +std::string unsafe_client_request_stringification(const een9::ClientRequest& req) { + std::string text = "\n\nGot some cool stuff\n"; + text += (req.method + " " + req.uri_path + " " + req.http_version + "\n"); + for (auto& p: req.headers) { + text += p.first; text += ": "; text += p.second; text += "\n"; + } + text += "Body\n"; text += req.body; text += "\n"; + return text; +} + + +void run_website(const json::JSON& config) { + een9_ASSERT(config["assets"].g().isString(), "config[\"\assets\"] is not string"); + std::string assets_dir = config["assets"].g().asString(); + een9_ASSERT(een9::isDirectory(assets_dir), "\"" + assets_dir + "\" is not a directory"); + + een9::StaticAssetManagerSlaveModule samI; + samI.update({ + een9::StaticAssetManagerRule{assets_dir + "/css", "/assets/css", {{".css", "text/css"}} }, + een9::StaticAssetManagerRule{assets_dir + "/js", "/assets/js", {{".js", "text/js"}} }, + een9::StaticAssetManagerRule{assets_dir + "/img", "/assets/img", { + {".jpg", "image/jpg"}, {".png", "image/png"}, {".svg", "image/svg+xml"} + } }, + }); + + const json::JSON& config_presentation = config["presentation"].g(); + + /* Because templaters use libjsonincpp, they can't be READ by two thread simultaneously */ + std::vector> templaters_copies(8); + for (int i = 0; i < 8; i++) { + templaters_copies[i] = std::make_unique( + nytl::TemplaterSettings{nytl::TemplaterDetourRules{assets_dir + "/HypertextPages"}}); + templaters_copies[i]->update(); + } + + // printf("%s\n", templaters_copies[0]->render("list-rooms", {&config_presentation}).c_str()); + // return 0; + + een9::MainloopParameters params; + params.guest_core = [&samI, &templaters_copies, config_presentation] + (const een9::SlaveTask& task, const een9::ClientRequest& req, een9::worker_id_t worker_id) -> std::string { + een9_ASSERT_pl(0 <= worker_id && worker_id < templaters_copies.size()); + nytl::Templater& templater = *templaters_copies[worker_id]; + een9::StaticAsset sa; + int ret; + // printf("%s", unsafe_client_request_stringification(req).c_str()); + // if (req.uri_path == "/output") { + // std::string text = unsafe_client_request_stringification(req); + // return een9::form_http_server_response_200("text/plain", text); + // } + auto rteee = [&](const std::string& el_name, bool pass_phr) -> std::string { + std::string page = templater.render(el_name, + pass_phr ? std::vector{&config_presentation} : std::vector{}); + return een9::form_http_server_response_200("text/html", page); + }; + if (req.uri_path == "/" || req.uri_path == "/list-rooms") { + return rteee("list-rooms", true); + } + if (req.uri_path == "/chat") { + return rteee("chat", false); + } + if (req.uri_path == "/profile") { + return rteee("profile", false); + } + if (req.uri_path == "/registration") { + return rteee("registration", false); + } + /* Trying to interpret request as asset lookup */ + ret = samI.get_asset(req.uri_path, sa); + if (ret >= 0) { + return een9::form_http_server_response_200(sa.type, sa.content); + } + return een9::form_http_server_response_404("text/html", "

Not found!

"); + }; + + params.ports_to_listen = {1025}; + params.slave_number = 8; + params.open_admin_listener = false; + + signal(SIGINT, sigterm_action); + signal(SIGTERM, sigterm_action); + + een9::electric_boogaloo(params, termination); +} \ No newline at end of file