Compare commits
3 Commits
7a1bfd81f3
...
06d5a33495
Author | SHA1 | Date | |
---|---|---|---|
06d5a33495 | |||
ef4a6dec24 | |||
ef3af2ec45 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -11,3 +11,5 @@ building/*.svg
|
|||||||
.idea/
|
.idea/
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
local.sh
|
local.sh
|
||||||
|
|
||||||
|
iu9-ca-web-chat.db
|
||||||
|
69
README.md
69
README.md
@ -1,6 +1,61 @@
|
|||||||
# ИУ9-21Б Вэб-чат C.A
|
# IU9 C.A. WEB CHAT
|
||||||
|
|
||||||
Сделан на летней практике 5-ю первокурсниками ИУ9
|
C.A. stands for Collarbone Annihilation.
|
||||||
|
|
||||||
|
# About
|
||||||
|
|
||||||
|
Сделан на летней практике 5-ю первокурсниками из ИУ9-21Б.
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
|
||||||
|
iu9-ca-web-chat использует
|
||||||
|
- GCC
|
||||||
|
- [regexis024-build-system](
|
||||||
|
https://gitlab.yyyi.ru/collarbone-annihilation/regexis024-build-system
|
||||||
|
)
|
||||||
|
- [libregexis024](
|
||||||
|
https://gitlab.yyyi.ru/kme-devline/libregexis024
|
||||||
|
)
|
||||||
|
- [libjsonincpp](
|
||||||
|
https://gitlab.yyyi.ru/collarbone-annihilation/libjsonincpp
|
||||||
|
)
|
||||||
|
- [sqlite3](
|
||||||
|
https://www.sqlite.org
|
||||||
|
)
|
||||||
|
|
||||||
|
Сервис так же использует библиотеки engine_engine_number_9 и new_york_transit_line,
|
||||||
|
размещённые прямо в репозитории.
|
||||||
|
|
||||||
|
Работает только на unix системах.
|
||||||
|
|
||||||
|
# Compilation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
regexis024_build_system.sh
|
||||||
|
./building/main bi ./ "absolute/path/to/installation/root"
|
||||||
|
```
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
Помимо самого бинарника нужен файл с настройками сервиса. Формат настроек: JSON.
|
||||||
|
Комментарии не поддерживаются. Пример такого файла находится в example/config.json.
|
||||||
|
Вместе с бинарным фалом так же распространяются ассеты, необъходимые для работы сайта.
|
||||||
|
Их можно найти в папке assets. В настроках (поле `["assets"]`) указывается путь до
|
||||||
|
папки с ассетами. Путь может быть как абсолютным, так и относительным к рабочей директории.
|
||||||
|
Поле настроек `["database"]` указывает как соединиться с базой данных.
|
||||||
|
Поддерживается только база данных sqlite. Поддерживается только хранение в файле.
|
||||||
|
Поле `["database"]["file"]` указывает путь где хранится sqlite база данных.
|
||||||
|
|
||||||
|
Перед тем как использовать сервис нужно его проинициализировать (а точнее проинициализировать
|
||||||
|
базу данных):
|
||||||
|
|
||||||
|
`ROOT_PW="<your desired root password>" 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 +65,13 @@
|
|||||||
4. [Каримов Адель](https://gitflic.ru/user/ra1n)
|
4. [Каримов Адель](https://gitflic.ru/user/ra1n)
|
||||||
5. [Яковлев Антон](https://gitflic.ru/user/yakovlevanton)
|
5. [Яковлев Антон](https://gitflic.ru/user/yakovlevanton)
|
||||||
|
|
||||||
|
# Комментарии (для разработчиков)
|
||||||
|
|
||||||
|
Зачем писать комментарии в коде, если можно их вынести в отдельные пдф-ки?
|
||||||
|
|
||||||
|
- [API сервиса](
|
||||||
|
https://gitlab.yyyi.ru/collarbone-annihilation/iu9-ca-chat-api)
|
||||||
|
- [Доки New York Transit Line](
|
||||||
|
https://gitlab.yyyi.ru/collarbone-annihilation/new_york_transit_line_documentation_rus)
|
||||||
|
|
||||||
|
О том как работает всё остальное можно только догадываться.
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
BUILDING_DIR="./building"
|
|
||||||
[ -d "$BUILDING_DIR" ] || exit 1
|
|
||||||
MAIN_FILE="$BUILDING_DIR/main.cpp"
|
|
||||||
[ -f "$MAIN_FILE" ] || exit 1
|
|
||||||
|
|
||||||
COOL_FLAGS="$(pkg-config --cflags regexis024-build-system)"
|
|
||||||
|
|
||||||
g++ $COOL_FLAGS -o "$BUILDING_DIR/main" "$MAIN_FILE" || exit 1
|
|
@ -1,30 +1,21 @@
|
|||||||
|
#include "regexis024_build_system.h"
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "regexis024_build_system.h"
|
std::string make_uppercase(const std::string &source) {
|
||||||
|
std::string result(source);
|
||||||
std::vector<std::string> getFromPkgConfig(const std::string& req, const std::string& name){
|
for (size_t i = 0; i < source.size(); i++) {
|
||||||
std::string pc_stdout, pc_stderr;
|
char ch = source[i];
|
||||||
CommandReturnCode rc = executeCommand_and_save_output({"pkg-config", "--" + req, name}, pc_stdout, pc_stderr);
|
if ('a' <= ch && ch <= 'z')
|
||||||
ASSERT(rc.isOk(), "failed to use pkg-config beacause of:\n" + pc_stderr);
|
result[i] = (char)(ch - 'a' + 'A');
|
||||||
// todo: learn how pkg-config actually stores these options
|
|
||||||
std::vector<std::string> result;
|
|
||||||
for (char ch: pc_stdout) {
|
|
||||||
if (result.empty())
|
|
||||||
result.emplace_back();
|
|
||||||
if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') {
|
|
||||||
if (!result.back().empty())
|
|
||||||
result.emplace_back();
|
|
||||||
} else {
|
|
||||||
result.back() += ch;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!result.empty() && result.back().empty())
|
|
||||||
result.pop_back();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalLibraryTarget formExternalLibraryTargetWithNativeName(const std::string& name) {
|
ExternalLibraryTarget formExternalLibraryTargetWithNonNativeName(const std::string& name) {
|
||||||
return {name, {getFromPkgConfig("cflags", name), getFromPkgConfig("libs", name)}};
|
std::string ev_name = "BSCRIPT_DEP_" + make_uppercase(name);
|
||||||
|
const char* ev = getenv(ev_name.c_str());
|
||||||
|
ASSERT(ev, "No environmaent variable " + ev_name);
|
||||||
|
return {name, parse_passed_forward_str(ev)};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CAWebChat {
|
struct CAWebChat {
|
||||||
@ -64,9 +55,9 @@ struct CAWebChat {
|
|||||||
ASSERT(build_type == "release" || build_type == "debug", "Unknown build type");
|
ASSERT(build_type == "release" || build_type == "debug", "Unknown build type");
|
||||||
|
|
||||||
std::vector<ExternalLibraryTarget> ext_targets = {
|
std::vector<ExternalLibraryTarget> ext_targets = {
|
||||||
formExternalLibraryTargetWithNativeName("libjsonincpp"),
|
formExternalLibraryTargetWithNonNativeName("libjsonincpp"),
|
||||||
formExternalLibraryTargetWithNativeName("sqlite3"),
|
formExternalLibraryTargetWithNonNativeName("sqlite3"),
|
||||||
formExternalLibraryTargetWithNativeName("libregexis024"),
|
formExternalLibraryTargetWithNonNativeName("libregexis024"),
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<CTarget> my_targets;
|
std::vector<CTarget> my_targets;
|
||||||
@ -141,7 +132,13 @@ struct CAWebChat {
|
|||||||
T.external_deps = {
|
T.external_deps = {
|
||||||
CTargetDependenceOnExternalLibrary{"sqlite3"}
|
CTargetDependenceOnExternalLibrary{"sqlite3"}
|
||||||
};
|
};
|
||||||
T.units = {"main.cpp"};
|
T.units = {
|
||||||
|
"main.cpp",
|
||||||
|
"initialize.cpp",
|
||||||
|
"run.cpp",
|
||||||
|
"str_fields_check.cpp",
|
||||||
|
"find_db.cpp",
|
||||||
|
};
|
||||||
for (std::string& u: T.units)
|
for (std::string& u: T.units)
|
||||||
u = "web_chat/" + u;
|
u = "web_chat/" + u;
|
||||||
T.include_pr = "web_chat";
|
T.include_pr = "web_chat";
|
||||||
|
9
src/web_chat/actions.h
Normal file
9
src/web_chat/actions.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef IU9_CA_WEB_CHAT_ACTIONS_H
|
||||||
|
#define IU9_CA_WEB_CHAT_ACTIONS_H
|
||||||
|
|
||||||
|
#include <jsonincpp/jsonobj.h>
|
||||||
|
|
||||||
|
void run_website(const json::JSON& config);
|
||||||
|
void initialize_website(const json::JSON& config, const std::string& root_pw);
|
||||||
|
|
||||||
|
#endif
|
14
src/web_chat/find_db.cpp
Normal file
14
src/web_chat/find_db.cpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include "find_db.h"
|
||||||
|
|
||||||
|
int find_db_sqlite_file_path(const json::JSON& config, std::string& res_path) {
|
||||||
|
const json::JSON& type = config["database"]["type"].g();
|
||||||
|
if (!type.isString() && type.asString() == "sqlite3")
|
||||||
|
return -1;
|
||||||
|
const json::JSON& path = config["database"]["file"].g();
|
||||||
|
if (!path.isString())
|
||||||
|
return -1;
|
||||||
|
if (path.asString().empty() || path.asString()[0] == ':')
|
||||||
|
return -1;
|
||||||
|
res_path = path.asString();
|
||||||
|
return 0;
|
||||||
|
}
|
8
src/web_chat/find_db.h
Normal file
8
src/web_chat/find_db.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef IU9_CA_WEB_CHAT_SRC_WEB_CHAT_FIND_DB_H
|
||||||
|
#define IU9_CA_WEB_CHAT_SRC_WEB_CHAT_FIND_DB_H
|
||||||
|
|
||||||
|
#include <jsonincpp/jsonobj.h>
|
||||||
|
|
||||||
|
int find_db_sqlite_file_path(const json::JSON& config, std::string& res_path);
|
||||||
|
|
||||||
|
#endif
|
59
src/web_chat/initialize.cpp
Normal file
59
src/web_chat/initialize.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include "actions.h"
|
||||||
|
#include <engine_engine_number_9/baza_throw.h>
|
||||||
|
#include "str_fields_check.h"
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#include <engine_engine_number_9/os_utils.h>
|
||||||
|
#include <find_db.h>
|
||||||
|
|
||||||
|
void sqlite_single_statement(sqlite3* db_hand, const std::string& req_statement) {
|
||||||
|
sqlite3_stmt* stmt_obj = NULL;
|
||||||
|
int ret = sqlite3_prepare16_v2(db_hand, req_statement.c_str(), -1, &stmt_obj, NULL);
|
||||||
|
een9_ASSERT(ret == 0, "Can't compile request expression");
|
||||||
|
struct Guard1{sqlite3_stmt*& r; ~Guard1(){if (sqlite3_finalize(r) != 0) {abort();}}} guard1{stmt_obj};
|
||||||
|
while (true) {
|
||||||
|
ret = sqlite3_step(stmt_obj);
|
||||||
|
if (ret == SQLITE_DONE)
|
||||||
|
break;
|
||||||
|
if (ret != SQLITE_ROW) {
|
||||||
|
printf("sqlite_row error!!!\n");
|
||||||
|
printf("%s\n", sqlite3_errmsg(db_hand));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int cc = sqlite3_column_count(stmt_obj);
|
||||||
|
std::vector<int> types(cc);
|
||||||
|
for (int i = 0; i < cc; i++) {
|
||||||
|
types[i] = sqlite3_column_type(stmt_obj, i);
|
||||||
|
}
|
||||||
|
printf("Column: |");
|
||||||
|
for (int i = 0; i < cc; i++) {
|
||||||
|
switch (types[i]) {
|
||||||
|
#define ccase(tname) case SQLITE_ ## tname: printf(" " #tname " |"); break;
|
||||||
|
ccase(INTEGER)
|
||||||
|
ccase(FLOAT)
|
||||||
|
ccase(BLOB)
|
||||||
|
ccase(NULL)
|
||||||
|
case SQLITE3_TEXT:
|
||||||
|
printf(" TEXT |"); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
printf("Request steps are done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialize_website(const json::JSON& config, const std::string& root_pw) {
|
||||||
|
printf("Initialization...\n");
|
||||||
|
een9_ASSERT(check_password(root_pw), "Bad root password");
|
||||||
|
std::string db_path;
|
||||||
|
int ret;
|
||||||
|
ret = find_db_sqlite_file_path(config, db_path);
|
||||||
|
een9_ASSERT(ret == 0, "Invalid settings[\"database\"] field");
|
||||||
|
een9_ASSERT(!een9::isRegularFile(db_path), "Database file exists prior to initialization. "
|
||||||
|
"Can't preceed withut harming existing data");
|
||||||
|
// sqlite3* db_hand = NULL;
|
||||||
|
// ret = sqlite3_open(db_path.c_str(), &db_hand);
|
||||||
|
// een9_ASSERT(ret == 0, "Can't open database");
|
||||||
|
// struct Guard1{sqlite3*& dhp; ~Guard1(){if (sqlite3_close(dhp) != 0) {abort();}}} guard1{db_hand};
|
||||||
|
// sqlite_single_statement(db_hand, "CREATE TABLE tb(a INT, b INT);");
|
||||||
|
// todo: actually write something
|
||||||
|
}
|
@ -1,122 +1,40 @@
|
|||||||
#include <engine_engine_number_9/baza_throw.h>
|
#include <engine_engine_number_9/baza_throw.h>
|
||||||
#include <engine_engine_number_9/running_mainloop.h>
|
#include <engine_engine_number_9/os_utils.h>
|
||||||
#include <engine_engine_number_9/http_structures/response_gen.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <engine_engine_number_9/connecting_assets/static_asset_manager.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sqlite3.h>
|
|
||||||
#include <jsonincpp/string_representation.h>
|
#include <jsonincpp/string_representation.h>
|
||||||
#include <libregexis024vm/vm_opcodes.h>
|
#include "actions.h"
|
||||||
#include <engine_engine_number_9/form_data_structure/urlencoded_query.h>
|
#include <stdexcept>
|
||||||
#include <new_york_transit_line/templater.h>
|
|
||||||
|
|
||||||
bool termination = false;
|
|
||||||
|
|
||||||
void sigterm_action(int) {
|
|
||||||
termination = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void usage(char** argv) {
|
void usage(char** argv) {
|
||||||
printf("Usage: %s <file with settings>\n", argv[0]);
|
printf("Usage: %s <file with settings> <run|initialize>\n", argv[0]);
|
||||||
exit(1);
|
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){
|
int main(int argc, char** argv){
|
||||||
try {
|
try {
|
||||||
een9_ASSERT_pl(argc > 0);
|
een9_ASSERT_pl(argc > 0);
|
||||||
if (argc < 1 + 1)
|
if (argc != 1 + 2)
|
||||||
usage(argv);
|
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]);
|
printf("\"%s\" is not a json file\n", argv[1]);
|
||||||
usage(argv);
|
usage(argv);
|
||||||
}
|
}
|
||||||
std::string config_file = argv[1];
|
std::string cmd = argv[2];
|
||||||
|
|
||||||
std::string config_text;
|
std::string config_text;
|
||||||
een9::readFile(config_file, config_text);
|
een9::readFile(config_file, config_text);
|
||||||
json::JSON config = json::parse_str_flawless(config_text);
|
const 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");
|
|
||||||
|
|
||||||
een9::StaticAssetManagerSlaveModule samI;
|
if (cmd == "initialize") {
|
||||||
samI.update({
|
const char* ROOT_PW = getenv("ROOT_PW");
|
||||||
een9::StaticAssetManagerRule{assets_dir + "/css", "/assets/css", {{".css", "text/css"}} },
|
een9_ASSERT(ROOT_PW, "No root password specified."
|
||||||
een9::StaticAssetManagerRule{assets_dir + "/js", "/assets/js", {{".js", "text/js"}} },
|
"Assign desired root password value to environment variable ROOT_PW");
|
||||||
een9::StaticAssetManagerRule{assets_dir + "/img", "/assets/img", {
|
std::string root_pw = ROOT_PW;
|
||||||
{".jpg", "image/jpg"}, {".png", "image/png"}, {".svg", "image/svg+xml"}
|
initialize_website(config, root_pw);
|
||||||
} },
|
} else if (cmd == "run") {
|
||||||
});
|
run_website(config);
|
||||||
|
} else
|
||||||
json::JSON& config_presentation = config["presentation"].g();
|
een9_THROW("unknown action (known are 'run', 'initialize')");
|
||||||
|
|
||||||
/* Because templaters use libjsonincpp, they can't be READ by two thread simultaneously */
|
|
||||||
std::vector<std::unique_ptr<nytl::Templater>> templaters_copies(8);
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
templaters_copies[i] = std::make_unique<nytl::Templater>(
|
|
||||||
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<const json::JSON*>{&config_presentation} : std::vector<const json::JSON*>{});
|
|
||||||
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", "<h1> Not found! </h1>");
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
} catch (std::exception& e) {
|
} catch (std::exception& e) {
|
||||||
printf("System failure\n%s\n", e.what());
|
printf("System failure\n%s\n", e.what());
|
||||||
}
|
}
|
||||||
|
103
src/web_chat/run.cpp
Normal file
103
src/web_chat/run.cpp
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#include "actions.h"
|
||||||
|
|
||||||
|
#include <engine_engine_number_9/baza_throw.h>
|
||||||
|
#include <engine_engine_number_9/running_mainloop.h>
|
||||||
|
#include <engine_engine_number_9/http_structures/response_gen.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <engine_engine_number_9/connecting_assets/static_asset_manager.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <engine_engine_number_9/form_data_structure/urlencoded_query.h>
|
||||||
|
#include <new_york_transit_line/templater.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
|
||||||
|
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<std::unique_ptr<nytl::Templater>> templaters_copies(8);
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
templaters_copies[i] = std::make_unique<nytl::Templater>(
|
||||||
|
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<const json::JSON*>{&config_presentation} : std::vector<const json::JSON*>{});
|
||||||
|
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", "<h1> Not found! </h1>");
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
37
src/web_chat/str_fields_check.cpp
Normal file
37
src/web_chat/str_fields_check.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "str_fields_check.h"
|
||||||
|
#include <jsonincpp/utf8.h>
|
||||||
|
|
||||||
|
bool isALPHA(char ch) {
|
||||||
|
return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNUM(char ch) {
|
||||||
|
return '0' <= ch && ch <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isUNCHAR(char ch) {
|
||||||
|
return isALPHA(ch) || isNUM(ch) || ch == '-' || ch == '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSPACE(char ch) {
|
||||||
|
return ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool check_password(const std::string &pwd) {
|
||||||
|
return isUtf8String(pwd) && pwd.size() >= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_name(const std::string &name) {
|
||||||
|
return isUtf8String(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_nickname(const std::string &nickname) {
|
||||||
|
if (nickname.empty())
|
||||||
|
return false;
|
||||||
|
for (char ch: nickname) {
|
||||||
|
if (!isUNCHAR(ch))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
10
src/web_chat/str_fields_check.h
Normal file
10
src/web_chat/str_fields_check.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef IU9_CA_WEB_CHAT_SRC_WEB_CHAT_STR_FIELDS_CHECK_H
|
||||||
|
#define IU9_CA_WEB_CHAT_SRC_WEB_CHAT_STR_FIELDS_CHECK_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
bool check_password(const std::string& pwd);
|
||||||
|
bool check_name(const std::string& name);
|
||||||
|
bool check_nickname(const std::string& nickname);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user