diff --git a/include/bank.h b/include/bank.h index ea8d975..5a67452 100644 --- a/include/bank.h +++ b/include/bank.h @@ -13,7 +13,7 @@ class Bank { #if MULTI_THREADED - phmap::parallel_flat_hash_map< + static phmap::parallel_flat_hash_map< std::string, User, xxHashStringGen, phmap::priv::hash_default_eq, @@ -22,50 +22,50 @@ class Bank std::mutex> users; #else - phmap::parallel_flat_hash_map users; + static phmap::parallel_flat_hash_map users; #endif private: #if CONSERVATIVE_DISK_SAVE #if MULTI_THREADED - ChangeFlag save_flag; + static ChangeFlag save_flag; #else - bool save_flag = false; + static bool save_flag = false; #endif #endif //must grab as shared if the operation is gonna modify "users"'s size or can be caught in a intermediary state such as SendFunds() //must grab as unique if the operation is gonna user iterators - std::shared_mutex iter_lock; + static std::shared_mutex iter_lock; public: - std::string admin_account; + static std::string admin_account; - size_t NumOfUsers() const noexcept; - size_t NumOfLogs() const noexcept; - size_t SumBal() const noexcept; + static size_t NumOfUsers() noexcept; + static size_t NumOfLogs() noexcept; + static size_t SumBal() noexcept; - BankResponse GetBal(const std::string &name) const noexcept; + static BankResponse GetBal(const std::string &name) noexcept; #if MAX_LOG_SIZE > 0 - BankResponse GetLogs(const std::string &name) noexcept; + static BankResponse GetLogs(const std::string &name) noexcept; #endif - BankResponse SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept; - bool VerifyPassword(const std::string &name, const std::string_view &attempt) const noexcept; + static BankResponse SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept; + static bool VerifyPassword(const std::string &name, const std::string_view &attempt) noexcept; - void ChangePassword(const std::string &name, const std::string &new_pass) noexcept; - BankResponse SetBal(const std::string &name, uint32_t amount) noexcept; - BankResponse ImpactBal(const std::string &name, int64_t amount) noexcept; - bool Contains(const std::string &name) const noexcept; + static void ChangePassword(const std::string &name, const std::string &new_pass) noexcept; + static BankResponse SetBal(const std::string &name, uint32_t amount) noexcept; + static BankResponse ImpactBal(const std::string &name, int64_t amount) noexcept; + static bool Contains(const std::string &name) noexcept; #if MAX_LOG_SIZE > 0 - BankResponse PruneUsers(time_t threshold_time, uint32_t threshold_bal) noexcept; + static BankResponse PruneUsers(time_t threshold_time, uint32_t threshold_bal) noexcept; #else - BankResponse PruneUsers(uint32_t threshold_bal) noexcept; + static BankResponse PruneUsers(uint32_t threshold_bal) noexcept; #endif - BankResponse AddUser(const std::string &name, uint32_t init_bal, const std::string &init_pass) noexcept; - BankResponse DelUser(const std::string &name) noexcept; - void DelSelf(const std::string &name) noexcept; + static BankResponse AddUser(const std::string &name, uint32_t init_bal, const std::string &init_pass) noexcept; + static BankResponse DelUser(const std::string &name) noexcept; + static void DelSelf(const std::string &name) noexcept; - const char *Save(); - void Load(); + static const char *Save(); + static void Load(); }; \ No newline at end of file diff --git a/include/bank_api.h b/include/bank_api.h index 1451ef5..c10dc93 100644 --- a/include/bank_api.h +++ b/include/bank_api.h @@ -10,10 +10,7 @@ using namespace drogon; class api : public HttpController { - Bank &bank; - public: - api(Bank &b) noexcept; void JsonCpp(req_args) const; void Json(req_args) const; diff --git a/include/json_filter.h b/include/json_filter.h index ffa9a05..6809975 100644 --- a/include/json_filter.h +++ b/include/json_filter.h @@ -8,8 +8,6 @@ template class JsonFilter : public HttpFilter, false> { public: - JsonFilter(); - virtual void doFilter(const HttpRequestPtr &, FilterCallback &&, FilterChainCallback &&) override; diff --git a/include/user_filter.h b/include/user_filter.h index 16ca9a0..9387071 100644 --- a/include/user_filter.h +++ b/include/user_filter.h @@ -9,12 +9,7 @@ using namespace drogon; template class UserFilter : public HttpFilter, false> { -private: - Bank &bank; - public: - UserFilter(Bank &b); - virtual void doFilter(const HttpRequestPtr &, FilterCallback &&, FilterChainCallback &&) override; diff --git a/src/bank.cpp b/src/bank.cpp index c60da37..1a654be 100644 --- a/src/bank.cpp +++ b/src/bank.cpp @@ -27,10 +27,10 @@ __attribute__((always_inline)) inline bool ValidUsername(const std::string &name } //NOT THREAD SAFE -size_t Bank::NumOfUsers() const noexcept { return users.size(); } +size_t Bank::NumOfUsers() noexcept { return Bank::users.size(); } //NOT THREAD SAFE -size_t Bank::NumOfLogs() const noexcept +size_t Bank::NumOfLogs() noexcept { #if MAX_LOG_SIZE > 0 size_t res = 0; @@ -45,7 +45,7 @@ size_t Bank::NumOfLogs() const noexcept } //NOT THREAD SAFE -size_t Bank::SumBal() const noexcept +size_t Bank::SumBal() noexcept { size_t res = 0; for (const auto &u : users) @@ -55,10 +55,11 @@ size_t Bank::SumBal() const noexcept return res; } -BankResponse Bank::GetBal(const std::string &name) const noexcept +BankResponse Bank::GetBal(const std::string &name) noexcept { uint32_t res = 0; - if (!ValidUsername(name) || !users.if_contains(name, [&res](const User &u) { res = u.balance; })) + if (!ValidUsername(name) || !Bank::users.if_contains(name, [&res](const User &u) + { res = u.balance; })) { return {k404NotFound, "\"User not found\""}; } @@ -71,7 +72,8 @@ BankResponse Bank::GetBal(const std::string &name) const noexcept BankResponse Bank::GetLogs(const std::string &name) noexcept { BankResponse res; - if (!users.modify_if(name, [&res](User &u) { res = {k200OK, u.log.GetLogs()}; })) + if (!Bank::users.modify_if(name, [&res](User &u) + { res = {k200OK, u.log.GetLogs()}; })) { return {k404NotFound, "\"User not found\""}; } @@ -100,57 +102,62 @@ BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_nam std::shared_lock lock{iter_lock}; #if MAX_LOG_SIZE > 0 time_t current_time = time(NULL); - if (!users.modify_if(a_name, [current_time, &a_name, &b_name, &res, amount](User &a) + if (!Bank::users.modify_if(a_name, [current_time, &a_name, &b_name, &res, amount](User &a) #else - if (!users.modify_if(a_name, [&a_name, &b_name, &res, amount](User &a) + if (!Bank::users.modify_if(a_name, [&a_name, &b_name, &res, amount](User &a) #endif - { - //if A can afford it - if (a.balance < amount) - { - res = {k400BadRequest, "\"Insufficient funds\""}; - } - else - { - a.balance -= amount; + { + //if A can afford it + if (a.balance < amount) + { + res = {k400BadRequest, "\"Insufficient funds\""}; + } + else + { + a.balance -= amount; #if MAX_LOG_SIZE > 0 - a.log.AddTrans(a_name, b_name, amount, current_time); + a.log.AddTrans(a_name, b_name, amount, current_time); #endif - res = {k200OK, std::to_string(a.balance)}; - } - })) + res = {k200OK, std::to_string(a.balance)}; + } + })) { return {k404NotFound, "\"Sender does not exist\""}; } if (res.first == k200OK) { #if MAX_LOG_SIZE > 0 - users.modify_if(b_name, [current_time, &a_name, &b_name, amount](User &b) { - b.balance += amount; - b.log.AddTrans(a_name, b_name, amount, current_time); - }); + Bank::users.modify_if(b_name, [current_time, &a_name, &b_name, amount](User &b) + { + b.balance += amount; + b.log.AddTrans(a_name, b_name, amount, current_time); + }); #else - users.modify_if(b_name, [amount](User &b) { b.balance += amount; }); + Bank::users.modify_if(b_name, [amount](User &b) + { b.balance += amount; }); #endif SET_CHANGES_ON; } return res; } -bool Bank::VerifyPassword(const std::string &name, const std::string_view &attempt) const noexcept +bool Bank::VerifyPassword(const std::string &name, const std::string_view &attempt) noexcept { bool res = false; - users.if_contains(name, [&res, &attempt](const User &u) { res = (u.password == xxHashStringGen{}(attempt)); }); + Bank::users.if_contains(name, [&res, &attempt](const User &u) + { res = (u.password == xxHashStringGen{}(attempt)); }); return res; } void Bank::ChangePassword(const std::string &name, const std::string &new_pass) noexcept { SET_CHANGES_ON; - users.modify_if(name, [&new_pass](User &u) { u.password = xxHashStringGen{}(new_pass); }); + Bank::users.modify_if(name, [&new_pass](User &u) + { u.password = xxHashStringGen{}(new_pass); }); } BankResponse Bank::SetBal(const std::string &name, uint32_t amount) noexcept { - if (ValidUsername(name) && users.modify_if(name, [amount](User &u) { u.balance = amount; })) + if (ValidUsername(name) && Bank::users.modify_if(name, [amount](User &u) + { u.balance = amount; })) { SET_CHANGES_ON; return {k204NoContent, std::nullopt}; //returns new balance @@ -167,7 +174,8 @@ BankResponse Bank::ImpactBal(const std::string &name, int64_t amount) noexcept return {k400BadRequest, "\"Amount cannot be 0\""}; } uint32_t balance; - if (ValidUsername(name) && users.modify_if(name, [&balance, amount](User &u) { balance = (u.balance < (amount * -1) ? u.balance = 0 : u.balance += amount); })) + if (ValidUsername(name) && Bank::users.modify_if(name, [&balance, amount](User &u) + { balance = (u.balance < (amount * -1) ? u.balance = 0 : u.balance += amount); })) { SET_CHANGES_ON; return {k200OK, std::to_string(balance)}; //may return new balance @@ -177,9 +185,9 @@ BankResponse Bank::ImpactBal(const std::string &name, int64_t amount) noexcept return {k404NotFound, "\"User not found\""}; } } -bool Bank::Contains(const std::string &name) const noexcept +bool Bank::Contains(const std::string &name) noexcept { - return ValidUsername(name) && users.contains(name); + return ValidUsername(name) && Bank::users.contains(name); } #if MAX_LOG_SIZE > 0 BankResponse Bank::PruneUsers(time_t threshold_time, uint32_t threshold_bal) noexcept @@ -193,17 +201,19 @@ BankResponse Bank::PruneUsers(uint32_t threshold_bal) noexcept for (const auto &u : users) { #if RETURN_ON_DEL - if (users.erase_if(u.first, [threshold_time, threshold_bal, &bal, &deleted_count](User &u) -> bool { - bal += u.balance; + if (Bank::users.erase_if(u.first, [threshold_time, threshold_bal, &bal, &deleted_count](User &u) -> bool + { + bal += u.balance; #else - if (users.erase_if(u.first, [threshold_time, threshold_bal, &deleted_count](User &u) -> bool { + if (Bank::users.erase_if(u.first, [threshold_time, threshold_bal, &deleted_count](User &u) -> bool + { #endif #if MAX_LOG_SIZE > 0 - return ((!u.log.data.size() || u.log.data.back().time < threshold_time) && u.balance < threshold_bal); + return ((!u.log.data.size() || u.log.data.back().time < threshold_time) && u.balance < threshold_bal); #else - return (u.balance < threshold_bal); + return (u.balance < threshold_bal); #endif - })) + })) { SET_CHANGES_ON; @@ -213,7 +223,8 @@ BankResponse Bank::PruneUsers(uint32_t threshold_bal) noexcept #if RETURN_ON_DEL if (bal) { - users.modify_if(return_account, [bal](User &u) { u.balance += bal; }); + Bank::users.modify_if(return_account, [bal](User &u) + { u.balance += bal; }); } #endif return {k200OK, std::to_string(deleted_count)}; @@ -226,7 +237,7 @@ BankResponse Bank::AddUser(const std::string &name, uint32_t init_bal, const std return {k400BadRequest, "\"Invalid Username\""}; } std::shared_lock lock{iter_lock}; - if (users.try_emplace_l( + if (Bank::users.try_emplace_l( name, [](User &) {}, init_bal, init_pass)) { SET_CHANGES_ON; @@ -242,13 +253,15 @@ BankResponse Bank::DelUser(const std::string &name) noexcept std::shared_lock lock{iter_lock}; #if RETURN_ON_DEL uint32_t bal; - if (users.if_contains(name, [&bal](const User &u) { bal = u.balance; }) && + if (Bank::users.if_contains(name, [&bal](const User &u) + { bal = u.balance; }) && bal) { - users.modify_if(return_account, [bal](User &u) { u.balance += bal; }); + Bank::users.modify_if(return_account, [bal](User &u) + { u.balance += bal; }); } #endif - if (ValidUsername(name) && users.erase(name)) + if (ValidUsername(name) && Bank::users.erase(name)) { SET_CHANGES_ON; return {k204NoContent, std::nullopt}; @@ -264,14 +277,16 @@ void Bank::DelSelf(const std::string &name) noexcept std::shared_lock lock{iter_lock}; #if RETURN_ON_DEL uint32_t bal; - if (users.if_contains(name, [&bal](const User &u) { bal = u.balance; }) && + if (Bank::users.if_contains(name, [&bal](const User &u) + { bal = u.balance; }) && bal) { - users.modify_if(return_account, [bal](User &u) { u.balance += bal; }); + Bank::users.modify_if(return_account, [bal](User &u) + { u.balance += bal; }); } #endif SET_CHANGES_ON; - users.erase(name); + Bank::users.erase(name); } //ONLY EVER BEING CALLED BY SAVE THREAD OR C-INTERUPT const char *Bank::Save() @@ -292,16 +307,17 @@ const char *Bank::Save() throw std::invalid_argument("Cannot access saving file\n"); } bank_dom::Global users_copy; - users_copy.users.reserve(users.size()); - users_copy.keys.reserve(users.size()); + users_copy.users.reserve(Bank::users.size()); + users_copy.keys.reserve(Bank::users.size()); { std::unique_lock lock{iter_lock}; for (const auto &u : users) { - users.if_contains(u.first, [&users_copy, &u](const User &u_val) { - users_copy.users.emplace_back(u_val.Encode()); - users_copy.keys.emplace_back(u.first); - }); + Bank::users.if_contains(u.first, [&users_copy, &u](const User &u_val) + { + users_copy.users.emplace_back(u_val.Encode()); + users_copy.keys.emplace_back(u.first); + }); } } FBE::bank_dom::GlobalFinalModel writer; @@ -356,6 +372,6 @@ void Bank::Load() for (size_t i = 0; i < users_global.users.size(); ++i) { - users.try_emplace(users_global.keys[i], users_global.users[i]); + Bank::users.try_emplace(users_global.keys[i], users_global.users[i]); } } diff --git a/src/bank_api.cpp b/src/bank_api.cpp index 0659ce7..f45e1fa 100644 --- a/src/bank_api.cpp +++ b/src/bank_api.cpp @@ -1,6 +1,28 @@ #include "bank_api.h" -//all my homies hate jsoncpp +#if MULTI_THREADED +phmap::parallel_flat_hash_map< + std::string, User, + xxHashStringGen, + phmap::priv::hash_default_eq, + phmap::priv::Allocator>, + 4UL, + std::mutex> + Bank::users; +#else +phmap::parallel_flat_hash_map Bank::users; +#endif + +#if CONSERVATIVE_DISK_SAVE +#if MULTI_THREADED +ChangeFlag Bank::save_flag; +#else +bool Bank::save_flag = false; +#endif +#endif + +std::shared_mutex Bank::iter_lock; +std::string Bank::admin_account; #define CACHE_FOREVER resp->setExpiredTime(0) @@ -24,21 +46,17 @@ static thread_local ondemand::parser parser; #define NAME_PARAM req->getParameter("name") -api::api(Bank &b) noexcept : bank(b) -{ -} - #if API_VERSION >= 1 //Usage void api::GetBal(req_args, const std::string &name) const { - RESPONSE_PARSE(bank.GetBal(name)); + RESPONSE_PARSE(Bank::GetBal(name)); } void api::GetLogs(req_args) { #if MAX_LOG_SIZE > 0 - RESPONSE_PARSE(bank.GetLogs(NAME_PARAM)); + RESPONSE_PARSE(Bank::GetLogs(NAME_PARAM)); #else static thread_local auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""}); CORS; @@ -65,7 +83,7 @@ void api::SendFunds(req_args) const else { StrFromSV_Wrapper name_val(name.value()); - res = bank.SendFunds(NAME_PARAM, name_val.str, amount.value()); + res = Bank::SendFunds(NAME_PARAM, name_val.str, amount.value()); } } RESPONSE_PARSE(std::move(res)); @@ -91,7 +109,7 @@ void api::ChangePassword(req_args) const else { StrFromSV_Wrapper pass_val(pass.value()); - bank.ChangePassword(NAME_PARAM, pass_val.str); + Bank::ChangePassword(NAME_PARAM, pass_val.str); res = BankResponse{k204NoContent, std::nullopt}; } } @@ -116,10 +134,10 @@ void api::AdminChangePassword(req_args) const else { StrFromSV_Wrapper name_val(name.value()); - if (bank.Contains(name_val.str)) + if (Bank::Contains(name_val.str)) { StrFromSV_Wrapper pass_val(pass.value()); - bank.ChangePassword(name_val.str, pass_val.str); + Bank::ChangePassword(name_val.str, pass_val.str); res = BankResponse{k204NoContent, std::nullopt}; } else @@ -149,7 +167,7 @@ void api::SetBal(req_args) const else { StrFromSV_Wrapper name_val(name.value()); - res = bank.SetBal(name_val.str, amount.value()); + res = Bank::SetBal(name_val.str, amount.value()); } } RESPONSE_PARSE(std::move(res)); @@ -173,7 +191,7 @@ void api::ImpactBal(req_args) const else { StrFromSV_Wrapper name_val(name.value()); - res = bank.ImpactBal(name_val.str, amount.value()); + res = Bank::ImpactBal(name_val.str, amount.value()); } } RESPONSE_PARSE(std::move(res)); @@ -188,14 +206,14 @@ void api::Help(req_args) const } void api::Close(req_args) const { - bank.Save(); + Bank::Save(); RESPOND_TRUE; //filter handles admin creds app().quit(); } void api::Contains(req_args, const std::string &name) const { BankResponse res; - if (bank.Contains(name)) + if (Bank::Contains(name)) { res = BankResponse{k204NoContent, std::nullopt}; } @@ -244,7 +262,7 @@ void api::PruneUsers(req_args) const } else { - res = bank.PruneUsers(time.value(), amount.value()); + res = Bank::PruneUsers(time.value(), amount.value()); } #else auto amount = doc.find_field("amount").get_uint64(); @@ -254,7 +272,7 @@ void api::PruneUsers(req_args) const } else { - res = bank.PruneUsers(amount.value()); + res = Bank::PruneUsers(amount.value()); } #endif } @@ -281,7 +299,7 @@ void api::AddUser(req_args) const { StrFromSV_Wrapper name_val(name.value()); StrFromSV_Wrapper pass_val(pass.value()); - res = bank.AddUser(name_val.str, 0, pass_val.str); + res = Bank::AddUser(name_val.str, 0, pass_val.str); } } RESPONSE_PARSE(std::move(res)); @@ -307,14 +325,14 @@ void api::AdminAddUser(req_args) const { StrFromSV_Wrapper name_val(name.value()); StrFromSV_Wrapper pass_val(pass.value()); - res = bank.AddUser(name_val.str, amount.value(), pass_val.str); + res = Bank::AddUser(name_val.str, amount.value(), pass_val.str); } } RESPONSE_PARSE(std::move(res)); } void api::DelSelf(req_args) const { - bank.DelSelf(NAME_PARAM); + Bank::DelSelf(NAME_PARAM); RESPOND_TRUE; } void api::AdminDelUser(req_args) const @@ -335,7 +353,7 @@ void api::AdminDelUser(req_args) const else { StrFromSV_Wrapper name_val(name.value()); - res = bank.DelUser(name_val.str); + res = Bank::DelUser(name_val.str); } } RESPONSE_PARSE(std::move(res)); diff --git a/src/json_filter.cpp b/src/json_filter.cpp index f3be487..9c363af 100644 --- a/src/json_filter.cpp +++ b/src/json_filter.cpp @@ -1,8 +1,5 @@ #include "json_filter.h" -template -JsonFilter::JsonFilter() {} - __attribute__((always_inline)) inline bool Contains(std::string_view str, const std::string &val) { return str.find(val) != std::string::npos; diff --git a/src/user_filter.cpp b/src/user_filter.cpp index 3508ce2..3d38090 100644 --- a/src/user_filter.cpp +++ b/src/user_filter.cpp @@ -16,9 +16,6 @@ __attribute__((always_inline)) inline bool ValidUsername(const std::string &name return true; } -template -UserFilter::UserFilter(Bank &b) : bank(b) {} - template void UserFilter::doFilter(const HttpRequestPtr &req, FilterCallback &&fcb, @@ -43,10 +40,10 @@ void UserFilter::doFilter(const HttpRequestPtr &re { if constexpr (require_admin) { - if (bank.admin_account == username.str) + if (Bank::admin_account == username.str) { StrFromSV_Wrapper password(results_view.substr(middle + 1)); - if (bank.VerifyPassword(username.str, password.str)) + if (Bank::VerifyPassword(username.str, password.str)) { fccb(); return; @@ -56,7 +53,7 @@ void UserFilter::doFilter(const HttpRequestPtr &re else { StrFromSV_Wrapper password(results_view.substr(middle + 1)); - if (bank.VerifyPassword(username.str, results_view.substr(middle + 1))) + if (Bank::VerifyPassword(username.str, results_view.substr(middle + 1))) { if constexpr (set_body_flag) {