diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8b3297a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+# Never use CMAKE in production
+CMakeLists.txt
+cmake-build-debug/
+# Output of build system
+built/
+# This is a compilated build system script
+building/main
+building/*.png
+building/*.svg
+
+.idea/
diff --git a/README.md b/README.md
index ae0e360..6c9997f 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-# Collarbone Anihilation
+# ИУ9-21Б Вэб-чат C.A
-Веб-чат
+Сделан на летней практике 5-ю первокурсниками ИУ9
# Список участников
diff --git a/assets/css/test.css b/assets/css/test.css
new file mode 100644
index 0000000..75b73f1
--- /dev/null
+++ b/assets/css/test.css
@@ -0,0 +1,9 @@
+.aaa {font-size: 50px}
+
+.ccc .aaa {
+ color: yellow;
+}
+
+.ccc #bbb {
+ color: green;
+}
\ No newline at end of file
diff --git a/assets/html/test.html b/assets/html/test.html
new file mode 100644
index 0000000..a4ed2b7
--- /dev/null
+++ b/assets/html/test.html
@@ -0,0 +1,16 @@
+
+
+
+
+ This is a test
+
+
+
+ Test Test Test
+ Test Test asdasdsa Test
+
+
Inside aaaa
+
Iside bbbb
+
+
+
\ No newline at end of file
diff --git a/building/build_build_system.sh b/building/build_build_system.sh
new file mode 100755
index 0000000..6cc3b46
--- /dev/null
+++ b/building/build_build_system.sh
@@ -0,0 +1,10 @@
+#!/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
\ No newline at end of file
diff --git a/building/main.cpp b/building/main.cpp
new file mode 100644
index 0000000..e2f33c5
--- /dev/null
+++ b/building/main.cpp
@@ -0,0 +1,139 @@
+#include
+
+#include "regexis024_build_system.h"
+
+std::vector getFromPkgConfig(const std::string& req, const std::string& name){
+ std::string pc_stdout, pc_stderr;
+ CommandReturnCode rc = executeCommand_and_save_output({"pkg-config", "--" + req, name}, pc_stdout, pc_stderr);
+ ASSERT(rc.isOk(), "failed to use pkg-config beacause of:\n" + pc_stderr);
+ // todo: learn how pkg-config actually stores these options
+ std::vector result;
+ for (char ch: pc_stdout) {
+ if (result.empty())
+ result.emplace_back();
+ if (ch == ' ')
+ result.emplace_back();
+ else
+ result.back() += ch;
+ }
+ return result;
+}
+
+ExternalLibraryTarget formExternalLibraryTargetWithNativeName(const std::string& name) {
+ return {name, {getFromPkgConfig("cflags", name), getFromPkgConfig("libs", name)}};
+}
+
+struct CAWebChat {
+ /* Building runlevel */
+ BuildUnitsArray runlevel_1;
+ /* Installation runlevel */
+ BuildUnitsArray runlevel_2;
+
+ std::string build_type;
+
+ std::vector warning_flags = {"-Wall", "-Wno-unused-variable", "-Werror=return-type","-pedantic",
+ "-Wno-unused-but-set-variable", "-Wno-reorder"};
+ std::vector version_flags = {"--std", "c++14", "-D", "_POSIX_C_SOURCE=200809L"};
+ std::vector debug_defines_release = {"_GLIBCXX_DEBUG"};
+ std::vector debug_defines_debug = {"_GLIBCXX_DEBUG", "DEBUG_ALLOW_LOUD"};
+ std::vector opt_flags_release = {"-g", "-O2"};
+ std::vector opt_flags_debug = {"-g", "-ggdb", "-O0"};
+
+ std::vector getSomeRadFlags() const {
+ std::vector my_flag_collection;
+ gxx_add_cli_options(my_flag_collection, warning_flags);
+ gxx_add_cli_options(my_flag_collection, version_flags);
+ if (build_type == "release") {
+ gxx_add_cli_defines(my_flag_collection, debug_defines_release);
+ gxx_add_cli_options(my_flag_collection, opt_flags_release);
+ } else if (build_type == "debug") {
+ gxx_add_cli_defines(my_flag_collection, debug_defines_debug);
+ gxx_add_cli_options(my_flag_collection, opt_flags_debug);
+ }
+ return my_flag_collection;
+ }
+
+ CAWebChat(std::string _build_type, const NormalCBuildSystemCommandMeaning& cmd)
+ : build_type(std::move(_build_type))
+ {
+ ASSERT(build_type == "release" || build_type == "debug", "Unknown build type");
+
+ std::vector ext_targets = {
+ formExternalLibraryTargetWithNativeName("libjsonincpp"),
+ formExternalLibraryTargetWithNativeName("sqlite3"),
+ };
+
+ std::vector my_targets;
+
+ { CTarget T("engine_engine_number_9", "shared_library");
+ T.additional_compilation_flags = getSomeRadFlags();
+ T.proj_deps = {};
+ T.units = {
+ "baza.cpp",
+ "thread_synchronization.cpp",
+ "os_utils.cpp",
+ "http_structures/client_request_parse.cpp",
+ "http_structures/response_gen.cpp",
+ "connecting_assets/static_asset_manager.cpp",
+ "running_mainloop.cpp",
+ };
+ for (std::string& u: T.units)
+ u = "http_server/engine_engine_number_9/" + u;
+ T.include_pr = "http_server";
+ T.include_ir = "";
+ T.exported_headers = {
+ "baza.h",
+ "baza_throw.h",
+ "thread_synchronization.h",
+ "os_utils.h",
+ "connecting_assets/static_asset_manager.h",
+ "http_structures/client_request.h",
+ "http_structures/response_gen.h",
+ "running_mainloop.h",
+ };
+ for (std::string& u: T.exported_headers)
+ u = "engine_engine_number_9/" + u;
+
+ T.installation_dir = "";
+ my_targets.push_back(T);
+ }
+ { CTarget T("iu9-ca-web-chat", "executable");
+ T.additional_compilation_flags = getSomeRadFlags();
+ T.proj_deps = {CTargetDependenceOnProjectsLibrary("engine_engine_number_9")};
+ T.units = {"main.cpp"};
+ for (std::string& u: T.units)
+ u = "web_chat/" + u;
+ T.include_pr = "web_chat";
+ T.installation_dir = "";
+ my_targets.push_back(T);
+ }
+ regular_ctargets_to_2bus_conversion(ext_targets, my_targets, runlevel_1, runlevel_2,
+ cmd.project_root, cmd.installation_root);
+ }
+};
+
+int main(int argc, char** argv) {
+ try {
+ ASSERT_pl(argc > 0);
+ assert(argc > 0);
+ std::vector args(argc - 1);
+ for (int i = 0; i + 1 < argc; i++) {
+ args[i] = argv[i + 1];
+ }
+ NormalCBuildSystemCommandMeaning cmd;
+ regular_bs_cli_cmd_interpret(args, cmd);
+ CAWebChat bs("debug", cmd);
+ // std::string map = "Runlevel 1\n";
+ // draw_bu_arr_in_dot(bs.runlevel_1, map);
+ // map += "Runlevel 2\n";
+ // draw_bu_arr_in_dot(bs.runlevel_2, map);
+ // printf("%s", map.c_str());
+ if (cmd.need_to_build)
+ complete_tasks_of_build_units(bs.runlevel_1);
+ umask(~0755);
+ if (cmd.need_to_install)
+ complete_tasks_of_build_units(bs.runlevel_2);
+ } catch (const buildSystemFailure& e) {
+ printf("Build system failure\n""%s\n", e.toString().c_str());
+ }
+}
\ No newline at end of file
diff --git a/src/http_server/engine_engine_number_9/baza.cpp b/src/http_server/engine_engine_number_9/baza.cpp
new file mode 100644
index 0000000..d41b0ed
--- /dev/null
+++ b/src/http_server/engine_engine_number_9/baza.cpp
@@ -0,0 +1,41 @@
+#include "baza.h"
+
+#include
+#include
+
+namespace een9 {
+ ServerError::ServerError(const std::string &err, const std::string &file, const std::string &func, int line): err(err),
+ FILE(file),
+ func(func),
+ LINE(line) {
+ char buf[4096];
+ snprintf(buf, 4096, "Error occured in function %s (line %d of %s)\n"
+ "Error: %s",
+ func.c_str(), LINE, FILE.c_str(), err.c_str());
+ WHAT = buf;
+ }
+
+ const char * ServerError::what() const noexcept {
+ return WHAT.c_str();
+ }
+
+ std::string prettyprint_errno(const std::string &pref) {
+ const char* d = strerrorname_np(errno);
+ return pref.empty() ? std::string(d) : std::string(pref) + ": " + d;
+ }
+
+ /* This function is VITAL */
+ bool strIn(const std::string &str, const char *arr[]) {
+ for (const char** elPtr = arr; *elPtr != NULL; elPtr += 1) {
+ if (str == (*elPtr))
+ return true;
+ }
+ return false;
+ }
+
+ bool endsIn(const std::string &a, const std::string &b) {
+ if (b.size() > a.size())
+ return false;
+ return std::equal(a.end() - (ssize_t)b.size(), a.end(), b.begin());
+ }
+}
diff --git a/src/http_server/engine_engine_number_9/baza.h b/src/http_server/engine_engine_number_9/baza.h
new file mode 100644
index 0000000..221272c
--- /dev/null
+++ b/src/http_server/engine_engine_number_9/baza.h
@@ -0,0 +1,27 @@
+#ifndef ENGINE_ENGINE_NUMBER_9_BAZA_H
+#define ENGINE_ENGINE_NUMBER_9_BAZA_H
+
+#include
+
+namespace een9 {
+ class ServerError : public std::exception{
+ std::string err;
+ std::string FILE;
+ std::string func;
+ int LINE;
+ std::string WHAT;
+
+ public:
+ ServerError(const std::string &err, const std::string &file, const std::string &func, int line);
+
+ const char *what() const noexcept override;
+ };
+
+ std::string prettyprint_errno(const std::string& pref);
+
+ bool strIn(const std::string& str, const char* arr[]);
+
+ bool endsIn(const std::string& a, const std::string& b);
+}
+
+#endif
diff --git a/src/http_server/engine_engine_number_9/baza_inter.h b/src/http_server/engine_engine_number_9/baza_inter.h
new file mode 100644
index 0000000..c7987ea
--- /dev/null
+++ b/src/http_server/engine_engine_number_9/baza_inter.h
@@ -0,0 +1,16 @@
+#ifndef ENGINE_ENGINE_NUMBER_9_BAZA_INTER_H
+#define ENGINE_ENGINE_NUMBER_9_BAZA_INTER_H
+
+/* Do not export this file */
+
+#include "baza.h"
+
+#define THROW(err) throw ServerError(err, __FILE__, __func__, __LINE__)
+#define THROW_on_errno(err) THROW(prettyprint_errno(err))
+#define THROW_on_errno_pl() THROW(prettyprint_errno(""))
+#define ASSERT(cond, err) do { if (!(cond)) { THROW(err); } } while (0);
+#define ASSERT_pl(cond) ASSERT(cond, "Failed assertion `" #cond "`")
+#define ASSERT_on_iret(iret, err) ASSERT((iret) >= 0, prettyprint_errno(err));
+#define ASSERT_on_iret_pl(iret) ASSERT(iret >= 0, prettyprint_errno(""));
+
+#endif
diff --git a/src/http_server/engine_engine_number_9/baza_throw.h b/src/http_server/engine_engine_number_9/baza_throw.h
new file mode 100644
index 0000000..03c31ef
--- /dev/null
+++ b/src/http_server/engine_engine_number_9/baza_throw.h
@@ -0,0 +1,15 @@
+#ifndef ENGINE_ENGINE_NUMBER_9_BAZA_THROW_H
+#define ENGINE_ENGINE_NUMBER_9_BAZA_THROW_H
+
+#include "baza.h"
+
+#define een9_THROW(err) throw een9::ServerError(err, __FILE__, __func__, __LINE__)
+#define een9_THROW_on_errno(err) een9_THROW(een9::prettyprint_errno(err))
+#define een9_THROW_on_errno_pl() een9_THROW(een9::prettyprint_errno(""))
+#define een9_ASSERT(cond, err) do { if (!(cond)) { een9_THROW(err); } } while (0);
+#define een9_ASSERT_pl(cond) een9_ASSERT(cond, "Failed assertion `" #cond "`")
+#define een9_ASSERT_on_iret(iret, err) een9_ASSERT((iret) >= 0, een9::prettyprint_errno(err));
+#define een9_ASSERT_on_iret_pl(iret) een9_ASSERT(iret >= 0, een9::prettyprint_errno(""));
+
+
+#endif
diff --git a/src/http_server/engine_engine_number_9/connecting_assets/static_asset_manager.cpp b/src/http_server/engine_engine_number_9/connecting_assets/static_asset_manager.cpp
new file mode 100644
index 0000000..4688b3e
--- /dev/null
+++ b/src/http_server/engine_engine_number_9/connecting_assets/static_asset_manager.cpp
@@ -0,0 +1,86 @@
+#include "static_asset_manager.h"
+#include "../os_utils.h"
+#include "../baza_inter.h"
+#include
+#include
+#include
+#include
+#include
+
+namespace een9 {
+ std::vector detour_over_regular_folder(const std::string& path) {
+ std::vector result;
+ int ret;
+
+ std::vector todo;
+ todo.emplace_back();
+ while (!todo.empty()) {
+ std::string cur = std::move(todo.back());
+ todo.pop_back();
+ std::string path_to_cur_ent = path + "/" + cur;
+ struct stat info;
+ ret = stat(path_to_cur_ent.c_str(), &info);
+ ASSERT_on_iret(ret, "stat(\"" + cur + "\")");
+ if (S_ISDIR(info.st_mode)) {
+ DIR* D = opendir(path_to_cur_ent.c_str());
+ cur += "/";
+ ASSERT(D != NULL, prettyprint_errno("opendir(\"" + cur +"\")"));
+ struct Guard1{ DIR*& D; ~Guard1(){ closedir(D); } } g1{D};
+ while (true) {
+ errno = 0;
+ struct dirent* Dent = readdir(D);
+ if (Dent == NULL) {
+ if (errno == 0)
+ break;
+ THROW_on_errno("dirent in \"" + cur + "\"");
+ }
+ std::string child_entry = Dent->d_name;
+ if (child_entry != "." && child_entry != "..")
+ todo.push_back(cur + child_entry);
+ }
+ } else if (S_ISREG(info.st_mode)) {
+ result.push_back(cur);
+ } else {
+ THROW("unknown fs entry type \"" + cur + "\"");
+ }
+ }
+ return result;
+ }
+
+ void updateStaticAssetManager(StaticAssetManager& sam) {
+ sam.url_to_asset.clear();
+ for (const StaticAssetManagerRule& dir_rule: sam.rules) {
+ std::vector c_files = detour_over_regular_folder(dir_rule.directory);
+ for (const std::string& file: c_files) {
+ for (const StaticAssetManagerRulePostfixFilter& ext: dir_rule.postfix_rules_type_assign) {
+ if (endsIn(file, ext.required_postfix)) {
+ /* Found it! */
+ StaticAsset etot{ext.assigned_type, };
+ readFile(dir_rule.directory + "/" + file, etot.content);
+ sam.url_to_asset[dir_rule.url_prefix + file] = etot;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ int StaticAssetManagerSlaveModule::get_asset(const std::string& url, StaticAsset& ret) {
+ RwlockReadGuard lg(mut);
+ if (sam.url_to_asset.count(url) == 0)
+ return -1;
+ ret = sam.url_to_asset[url];
+ return 0;
+ }
+
+ void StaticAssetManagerSlaveModule::update() {
+ RwlockWriteGuard lg(mut);
+ updateStaticAssetManager(sam);
+ }
+
+ void StaticAssetManagerSlaveModule::update(std::vector new_rules) {
+ RwlockWriteGuard lg(mut);
+ sam.rules = std::move(new_rules);
+ updateStaticAssetManager(sam);
+ }
+}
diff --git a/src/http_server/engine_engine_number_9/connecting_assets/static_asset_manager.h b/src/http_server/engine_engine_number_9/connecting_assets/static_asset_manager.h
new file mode 100644
index 0000000..2776e36
--- /dev/null
+++ b/src/http_server/engine_engine_number_9/connecting_assets/static_asset_manager.h
@@ -0,0 +1,50 @@
+#ifndef ENGINE_ENGINE_NUMBER_9_CONNECTING_ASSETS_STATIC_ASSET_MANAGER_H
+#define ENGINE_ENGINE_NUMBER_9_CONNECTING_ASSETS_STATIC_ASSET_MANAGER_H
+
+#include
+#include
+#include