New York Transit Line is finally usable at least a little. Integrated it with frontend

This commit is contained in:
Андреев Григорий 2024-08-14 21:16:56 +03:00
parent 393703b0b2
commit dd806a5633
11 changed files with 144 additions and 72 deletions

View File

@ -1,31 +1,32 @@
{% ELDEF main JSON pres %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ru"> <html lang="ru">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Список Чат-Комнат</title> <title>{% WRITE pres.phr.decl.list-of-chat-rooms %}</title>
<link rel="stylesheet" href="/assets/css/list-rooms.css"> <link rel="stylesheet" href="/assets/css/list-rooms.css">
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<h1 style="color: white;">Выберите Чат-Комнату</h1> <h1 style="color: white;">{% WRITE pres.phr.decl.select-chat-room %}</h1>
<ul class="room-list"> <ul class="room-list">
<!-- Здесь будет список комнат --> <!-- Здесь будет список комнат -->
</ul> </ul>
<button class="create-room-button" onclick="openCreateRoomModal()">Создать Комнату</button> <button class="create-room-button" onclick="openCreateRoomModal()">{% WRITE pres.phr.act.create-room %}</button>
</div> </div>
<div id="passwordModal" class="modal"> <div id="passwordModal" class="modal">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<span class="close" onclick="closeModal()">&times;</span> <span class="close" onclick="closeModal()">&times;</span>
<h2>Введите Пароль</h2> <h2>VVedite parol</h2> <!-- Nam ne nuzhen parol ot komnat -->
</div> </div>
<div class="modal-body"> <div class="modal-body">
<input type="password" id="roomPassword" placeholder="Пароль"> <input type="password" id="roomPassword" placeholder="Пароль">
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="join-button" onclick="validatePassword()">Подтвердить</button> <button class="join-button" onclick="validatePassword()">{% WRITE pres.phr.act.confirm %}</button>
</div> </div>
</div> </div>
</div> </div>
@ -35,14 +36,14 @@
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<span class="close" onclick="closeCreateRoomModal()">&times;</span> <span class="close" onclick="closeCreateRoomModal()">&times;</span>
<h2>Создать Комнату</h2> <h2>{% WRITE pres.phr.decl.create-room %}</h2>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<input type="text" id="newRoomName" placeholder="Название комнаты"> <input type="text" id="newRoomName" placeholder="{% WRITE pres.phr.decl.name-of-room %}">
<input type="password" id="newRoomPassword" placeholder="Пароль"> <input type="password" id="newRoomPassword" placeholder="Пароль"> <!-- Fedya, nam ne nuzhen parol -->
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="join-button" onclick="createRoom()">Создать</button> <button class="join-button" onclick="createRoom()">{% WRITE pres.phr.act.create %}</button>
</div> </div>
</div> </div>
</div> </div>
@ -50,3 +51,4 @@
<script src="/assets/js/list-rooms.js"></script> <script src="/assets/js/list-rooms.js"></script>
</body> </body>
</html> </html>
{% ENDELDEF %}

View File

@ -1,3 +1,32 @@
{ {
"name": "Web chat" "presentation": {
"instance-identity": {
"top-title": "Вэб чат ИУ9"
},
"phr": {
"decl": {
"list-of-chat-rooms": "Список Чат-Комнат",
"select-chat-room": "Выберете чат комнату",
"name-of-room": "Название комнаты",
"create-room": "Создать комнату"
},
"act": {
"create-room": "Создать комнату",
"confirm": "Подтвердить",
"create": "Создать"
}
}
},
"assets": "./assets",
"limits": {
"max-users": 100000,
"max-rooms": 100000,
"max-messages": 10000000000000,
"storage-size-limit": 100000000000
},
"server": {
"workers": 8,
"http-listen": ["127.0.0.1:1025"],
"command-listen": []
}
} }

View File

@ -82,10 +82,10 @@ namespace een9 {
struct WorkersEnv { struct WorkersEnv {
WorkersEnvCommon& wtec; WorkersEnvCommon& wtec;
int id; worker_id_t id;
ClientRequestParser_WorkerBuffers personal_parser_buffer; ClientRequestParser_WorkerBuffers personal_parser_buffer;
explicit WorkersEnv(WorkersEnvCommon& wtec, int id): wtec(wtec), id(id), personal_parser_buffer(wtec.parser_programs){} explicit WorkersEnv(WorkersEnvCommon& wtec, worker_id_t id): wtec(wtec), id(id), personal_parser_buffer(wtec.parser_programs){}
}; };
// todo: add timeout for multiple bytes, add more settings // todo: add timeout for multiple bytes, add more settings
@ -125,7 +125,7 @@ namespace een9 {
void process_connection(const SlaveTask& task, WorkersEnv& wte) { void process_connection(const SlaveTask& task, WorkersEnv& wte) {
ClientRequest client_request = process_connection_input(task.fd(), task.s_tips, wte); ClientRequest client_request = process_connection_input(task.fd(), task.s_tips, wte);
std::string server_response = wte.wtec.guest_core(task, client_request); std::string server_response = wte.wtec.guest_core(task, client_request, wte.id);
process_connection_output(task.fd(), server_response); process_connection_output(task.fd(), server_response);
} }
@ -149,6 +149,7 @@ namespace een9 {
} catch (const std::exception& e) { } catch (const std::exception& e) {
printf("Client request procession failure in worker\n"); printf("Client request procession failure in worker\n");
printf("%s\n", e.what()); printf("%s\n", e.what());
/* Under mysterious some circumstances, in this place destructor of string in SystemError causes segfault. I can't fix that */
} }
} }
printf("Worker finished\n"); printf("Worker finished\n");
@ -166,7 +167,7 @@ namespace een9 {
std::vector<pthread_t> workers(params.slave_number); std::vector<pthread_t> workers(params.slave_number);
std::vector<uptr<WorkersEnv>> wtes(params.slave_number); std::vector<uptr<WorkersEnv>> wtes(params.slave_number);
for (size_t i = 0; i < params.slave_number; i++) { for (size_t i = 0; i < params.slave_number; i++) {
wtes[i] = std::make_unique<WorkersEnv>(wtec, i); wtes[i] = std::make_unique<WorkersEnv>(wtec, (worker_id_t)i);
} }
for (size_t i = 0; i < params.slave_number; i++) { for (size_t i = 0; i < params.slave_number; i++) {
pthread_create(&workers[i], NULL, worker_func, wtes[i].get()); pthread_create(&workers[i], NULL, worker_func, wtes[i].get());

View File

@ -29,8 +29,10 @@ namespace een9 {
EEN9_ServerTips s_tips; EEN9_ServerTips s_tips;
}; };
typedef int worker_id_t;
/* guest_core function must not throw anything that is not derived from std::exception */ /* guest_core function must not throw anything that is not derived from std::exception */
typedef std::function<std::string(const SlaveTask&, const ClientRequest&)> guest_core_t; typedef std::function<std::string(const SlaveTask&, const ClientRequest&, worker_id_t worker_id)> guest_core_t;
struct ServersConfiguration { struct ServersConfiguration {
size_t critical_load_1 = 90; size_t critical_load_1 = 90;

View File

@ -447,27 +447,29 @@ namespace nytl {
mediocre_operator("str2code"); mediocre_operator("str2code");
goto ya_e_ya_h_i_ya_g_d_o;; goto ya_e_ya_h_i_ya_g_d_o;;
} }
auto prepare_to_depart_parts = [&]() {
assert(!result.parts.empty());
if (result.parts[0].type == ElementPart::p_code)
result.parts[0].when_code.lines = clement_lstrip(result.parts[0].when_code.lines);
if (result.parts.back().type == ElementPart::p_code)
rstrip(result.parts.back().when_code.lines);
size_t cut = 999999999999;
size_t N = result.parts.size();
for (size_t i = 0; i < N; i++) {
if (result.parts[i].type == ElementPart::p_code) {
one_part_update_min_start_wsp_non_empty(result.parts[i].when_code.lines, i, N, cut);
}
}
for (size_t i = 0; i < N; i++) {
if (result.parts[i].type == ElementPart::p_code) {
result.parts[i].when_code.lines = one_part_cut_excess_tab(result.parts[i].when_code.lines, i, N, cut);
}
}
};
if (op == "ENDELDEF") { if (op == "ENDELDEF") {
ASSERT(myself == gone_for_nothing, "Unexpected end of element"); ASSERT(myself == gone_for_nothing, "Unexpected end of element");
skip_magic_block_end(ctx, syntax); skip_magic_block_end(ctx, syntax);
if (!result.parts.empty()) { prepare_to_depart_parts();
if (result.parts[0].type == ElementPart::p_code)
result.parts[0].when_code.lines = clement_lstrip(result.parts[0].when_code.lines);
if (result.parts.back().type == ElementPart::p_code)
rstrip(result.parts.back().when_code.lines);
size_t cut = 999999999999;
size_t N = result.parts.size();
for (size_t i = 0; i < N; i++) {
if (result.parts[i].type == ElementPart::p_code) {
one_part_update_min_start_wsp_non_empty(result.parts[i].when_code.lines, i, N, cut);
}
}
for (size_t i = 0; i < N; i++) {
if (result.parts[i].type == ElementPart::p_code) {
result.parts[i].when_code.lines = one_part_cut_excess_tab(result.parts[i].when_code.lines, i, N, cut);
}
}
}
return NULL; return NULL;
} }
if (op == "ENDFOR") { if (op == "ENDFOR") {
@ -485,10 +487,13 @@ namespace nytl {
THROW("Expected LF, NOLF or end of magic block"); THROW("Expected LF, NOLF or end of magic block");
} }
skip_magic_block_end(ctx, syntax); skip_magic_block_end(ctx, syntax);
prepare_to_depart_parts();
return NULL; return NULL;
} }
if (op == "ENDREF") { if (op == "ENDREF") {
assert(myself == gone_for_ref);
skip_magic_block_end(ctx, syntax); skip_magic_block_end(ctx, syntax);
prepare_to_depart_parts();
return NULL; return NULL;
} }
THROW("Unknown operator. Expected FOR, REF, PUT, WRITE, ROUGHINSERT, ENDELDEF, ENDFOR, ENDREF"); THROW("Unknown operator. Expected FOR, REF, PUT, WRITE, ROUGHINSERT, ENDELDEF, ENDFOR, ENDREF");

View File

@ -9,22 +9,25 @@ namespace nytl {
std::string result; std::string result;
size_t cur_line_width = 0; size_t cur_line_width = 0;
/* Fix idea: get rid of newlined_somewhere */
void append(const std::string& text, size_t wsp_before_newlines, bool& newlined_somewhere) { void append(const std::string& text, size_t wsp_before_newlines, bool& newlined_somewhere) {
size_t n = result.size(); size_t n = result.size();
size_t m = text.size(); size_t m = text.size();
result.reserve(n + m); result.reserve(n + m);
for (size_t i = 0; i < m; i++) { for (size_t i = 0; i < m; i++) {
result += text[i];
if (text[i] == '\n') { if (text[i] == '\n') {
newlined_somewhere = true; // newlined_somewhere = true;
cur_line_width = 0;
result.resize(result.size() + wsp_before_newlines, ' ');
cur_line_width = wsp_before_newlines;
} else { } else {
if (cur_line_width == 0 && newlined_somewhere) { // if (cur_line_width == 0 && newlined_somewhere) {
result.resize(result.size() + wsp_before_newlines, ' '); // result.resize(result.size() + wsp_before_newlines, ' ');
cur_line_width = wsp_before_newlines; // cur_line_width = wsp_before_newlines;
} // }
cur_line_width++; cur_line_width++;
} }
result += text[i];
} }
} }
}; };
@ -88,7 +91,7 @@ namespace nytl {
RFrame_OverArray(const ElementPart::when_for_put_S& part, size_t multiline_put_start, const std::vector<LocalVarValue> &saved_args, RFrame_OverArray(const ElementPart::when_for_put_S& part, size_t multiline_put_start, const std::vector<LocalVarValue> &saved_args,
const std::vector<json::JSON> &arr): RFrame_OverJSON(part, multiline_put_start, saved_args), const std::vector<json::JSON> &arr): RFrame_OverJSON(part, multiline_put_start, saved_args),
arr(arr) { arr(arr) {
if (part.where_key_var < 0) if (part.where_key_var >= 0)
additional_json_wrapper = json::JSON(json::Integer(0l)); additional_json_wrapper = json::JSON(json::Integer(0l));
} }
@ -106,7 +109,7 @@ namespace nytl {
const std::map<std::string, json::JSON> &dict): RFrame_OverJSON(part, multiline_put_start, saved_args_plus_iter), const std::map<std::string, json::JSON> &dict): RFrame_OverJSON(part, multiline_put_start, saved_args_plus_iter),
dict(dict) { dict(dict) {
it = dict.begin(); it = dict.begin();
if (part.where_key_var < 0) if (part.where_key_var >= 0)
addition_json_wrapper = json::JSON(""); addition_json_wrapper = json::JSON("");
} }
@ -151,6 +154,8 @@ namespace nytl {
std::string escaped_json = escape(json::generate_str(*X, json::print_pretty)); std::string escaped_json = escape(json::generate_str(*X, json::print_pretty));
rstrip(escaped_json); rstrip(escaped_json);
append(escaped_json, result); append(escaped_json, result);
} else if (name == "jesccomp") {
append(escape(json::generate_str(*X, json::print_compact)), result);
} else if (name == "str2text") { } else if (name == "str2text") {
ASSERT(X->isString(), "str2text takes json string"); ASSERT(X->isString(), "str2text takes json string");
append(escape(X->asString()), result); append(escape(X->asString()), result);
@ -215,10 +220,10 @@ namespace nytl {
} }
uptr<RFrame> RFrame_OverDictionary::toMe(bool returned, RFrame_passed) { uptr<RFrame> RFrame_OverDictionary::toMe(bool returned, RFrame_passed) {
if (returned && part.line_feed)
append("\n", result);
if (it == dict.end()) if (it == dict.end())
return NULL; return NULL;
if (returned && part.line_feed)
append("\n", result);
if (part.where_key_var > -1) { if (part.where_key_var > -1) {
addition_json_wrapper.asString() = it->first; addition_json_wrapper.asString() = it->first;
saved_args_plus_iter[part.where_key_var] = {true, "", &addition_json_wrapper}; saved_args_plus_iter[part.where_key_var] = {true, "", &addition_json_wrapper};

View File

@ -112,7 +112,10 @@ namespace nytl {
void Templater::update() { void Templater::update() {
elements = { elements = {
{"jesc", Element{{json::JSON(true)}, true}}, {"jesc", Element{{json::JSON(true)}, true}},
{"jesccomp", Element{{json::JSON(true)}, true}},
/* str2text base element has a dedicated operator - WRITE */
{"str2text", Element{{json::JSON(true)}, true}}, {"str2text", Element{{json::JSON(true)}, true}},
/* str2code base element has a dedicated operator - ROUGHINSERT */
{"str2code", Element{{json::JSON(true)}, true}}, {"str2code", Element{{json::JSON(true)}, true}},
}; };
std::vector<InterestingFile> intersting_files = indexing_detour(settings.det); std::vector<InterestingFile> intersting_files = indexing_detour(settings.det);

View File

@ -0,0 +1,7 @@
{% ELDEF main %}
CCC
DDD
{% ENDELDEF %}

View File

@ -1,9 +1,9 @@
{% ELDEF foo JSON cba %}
BBBB
{% ENDELDEF %}
{% ELDEF main JSON cba %} {% ELDEF main JSON cba %}
AAAA AAA
{% PUT test.foo cba %} {% FOR _:val IN cba %}
{% PUT test.foo cba %} TUTUTUTUTUTUTUTUN {% PUT jesccomp val %}
{% ENDFOR %}
{% ENDELDEF %} {% ENDELDEF %}

View File

@ -14,6 +14,9 @@ int main(int argc, char** argv) {
nytl::debug_print_templater(templater); nytl::debug_print_templater(templater);
json::JSON cba; json::JSON cba;
cba["boba"] = json::JSON("<>"); cba["boba"] = json::JSON("<>");
cba["arr"][0] = json::JSON("zero");
cba["arr"][1] = json::JSON("one");
cba["arr"][2] = json::JSON("two");
// printf("DEBUG WAS: %p\n", &cba["boba"].g()); // printf("DEBUG WAS: %p\n", &cba["boba"].g());
// printf("%s\n", json::generate_str(cba["boba"].g(), json::print_compact).c_str()); // printf("%s\n", json::generate_str(cba["boba"].g(), json::print_compact).c_str());
// return 0; // return 0;

View File

@ -10,6 +10,8 @@
#include <engine_engine_number_9/form_data_structure/urlencoded_query.h> #include <engine_engine_number_9/form_data_structure/urlencoded_query.h>
#include <new_york_transit_line/templater.h> #include <new_york_transit_line/templater.h>
#include "../http_server/engine_engine_number_9/running_mainloop.h"
bool termination = false; bool termination = false;
void sigterm_action(int) { void sigterm_action(int) {
@ -17,7 +19,7 @@ void sigterm_action(int) {
} }
void usage(char** argv) { void usage(char** argv) {
printf("Usage: %s <file with settings> <assets folder>\n", argv[0]); printf("Usage: %s <file with settings>\n", argv[0]);
exit(1); exit(1);
} }
@ -32,30 +34,26 @@ std::string unsafe_client_request_stringification(const een9::ClientRequest& req
} }
int main(int argc, char** argv){ int main(int argc, char** argv){
printf("%s\n", regexis024::opcode_to_str(regexis024::opcode_t::DIE));
try { try {
een9_ASSERT_pl(argc > 0); een9_ASSERT_pl(argc > 0);
if (argc < 1 + 2) if (argc < 1 + 1)
usage(argv); usage(argv);
if (!een9::isRegularFile(argv[1]) || !een9::endsIn(argv[1], ".json")) { if (!een9::isRegularFile(argv[1]) || !een9::endsIn(argv[1], ".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 config_file = argv[1];
if (!een9::isDirectory(argv[2])) {
printf("\"%s\" is not a directory\n", argv[2]);
usage(argv);
}
std::string assets_dir = 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); json::JSON config = json::parse_str_flawless(config_text);
een9_ASSERT(config.isDictionary(), "config root is not dictionary"); 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; een9::StaticAssetManagerSlaveModule samI;
samI.update({ samI.update({
een9::StaticAssetManagerRule{assets_dir + "/HypertextPages", "/assets/html", {{".html", "text/html"}} },
een9::StaticAssetManagerRule{assets_dir + "/css", "/assets/css", {{".css", "text/css"}} }, een9::StaticAssetManagerRule{assets_dir + "/css", "/assets/css", {{".css", "text/css"}} },
een9::StaticAssetManagerRule{assets_dir + "/js", "/assets/js", {{".js", "text/js"}} }, een9::StaticAssetManagerRule{assets_dir + "/js", "/assets/js", {{".js", "text/js"}} },
een9::StaticAssetManagerRule{assets_dir + "/img", "/assets/img", { een9::StaticAssetManagerRule{assets_dir + "/img", "/assets/img", {
@ -63,31 +61,47 @@ int main(int argc, char** argv){
} }, } },
}); });
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; een9::MainloopParameters params;
params.guest_core = [&samI](const een9::SlaveTask& task, const een9::ClientRequest& req) -> std::string { 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; een9::StaticAsset sa;
int ret; int ret;
// printf("%s", unsafe_client_request_stringification(req).c_str()); // printf("%s", unsafe_client_request_stringification(req).c_str());
if (req.uri_path == "/output") { // if (req.uri_path == "/output") {
std::string text = unsafe_client_request_stringification(req); // std::string text = unsafe_client_request_stringification(req);
return een9::form_http_server_response_200("text/plain", text); // return een9::form_http_server_response_200("text/plain", text);
} // }
auto rteee = [&](const std::string& asset_path) -> std::string { auto rteee = [&](const std::string& el_name, bool pass_phr) -> std::string {
ret = samI.get_asset(asset_path, sa); std::string page = templater.render(el_name,
een9_ASSERT_pl(ret == 0); pass_phr ? std::vector<const json::JSON*>{&config_presentation} : std::vector<const json::JSON*>{});
return een9::form_http_server_response_200(sa.type, sa.content); return een9::form_http_server_response_200("text/html", page);
}; };
if (req.uri_path == "/" || req.uri_path == "/list-rooms") { if (req.uri_path == "/" || req.uri_path == "/list-rooms") {
return rteee("/assets/html/list-rooms.html"); return rteee("list-rooms", true);
} }
if (req.uri_path == "/chat") { if (req.uri_path == "/chat") {
return rteee("/assets/html/chat.html"); return rteee("chat", false);
} }
if (req.uri_path == "/profile") { if (req.uri_path == "/profile") {
return rteee("/assets/html/profile.html"); return rteee("profile", false);
} }
if (req.uri_path == "/registration") { if (req.uri_path == "/registration") {
return rteee("/assets/html/registration.html"); return rteee("registration", false);
} }
/* Trying to interpret request as asset lookup */ /* Trying to interpret request as asset lookup */
ret = samI.get_asset(req.uri_path, sa); ret = samI.get_asset(req.uri_path, sa);
@ -96,6 +110,7 @@ int main(int argc, char** argv){
} }
return een9::form_http_server_response_404("text/html", "<h1> Not found! </h1>"); return een9::form_http_server_response_404("text/html", "<h1> Not found! </h1>");
}; };
params.ports_to_listen = {1025}; params.ports_to_listen = {1025};
params.slave_number = 8; params.slave_number = 8;
params.open_admin_listener = false; params.open_admin_listener = false;