🐎🔥 made Bank static

This commit is contained in:
EntireTwix 2021-07-23 22:38:51 -07:00
parent 8abee602b7
commit 4086a1d324
8 changed files with 136 additions and 118 deletions

View file

@ -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<std::string>,
@ -22,50 +22,50 @@ class Bank
std::mutex>
users;
#else
phmap::parallel_flat_hash_map<std::string, User, xxHashStringGen> users;
static phmap::parallel_flat_hash_map<std::string, User, xxHashStringGen> users;
#endif
private:
#if CONSERVATIVE_DISK_SAVE
#if MULTI_THREADED
ChangeFlag<false> save_flag;
static ChangeFlag<false> 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();
};

View file

@ -10,10 +10,7 @@ using namespace drogon;
class api : public HttpController<api, false>
{
Bank &bank;
public:
api(Bank &b) noexcept;
void JsonCpp(req_args) const;
void Json(req_args) const;

View file

@ -8,8 +8,6 @@ template <bool check_content_type>
class JsonFilter : public HttpFilter<JsonFilter<check_content_type>, false>
{
public:
JsonFilter();
virtual void doFilter(const HttpRequestPtr &,
FilterCallback &&,
FilterChainCallback &&) override;

View file

@ -9,12 +9,7 @@ using namespace drogon;
template <bool set_body_flag, bool require_admin>
class UserFilter : public HttpFilter<UserFilter<set_body_flag, require_admin>, false>
{
private:
Bank &bank;
public:
UserFilter(Bank &b);
virtual void doFilter(const HttpRequestPtr &,
FilterCallback &&,
FilterChainCallback &&) override;

View file

@ -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<std::shared_mutex> 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<std::shared_mutex> 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<std::shared_mutex> 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<std::shared_mutex> 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<std::shared_mutex> 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]);
}
}

View file

@ -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<std::string>,
phmap::priv::Allocator<phmap::priv::Pair<const std::string, User>>,
4UL,
std::mutex>
Bank::users;
#else
phmap::parallel_flat_hash_map<std::string, User, xxHashStringGen> Bank::users;
#endif
#if CONSERVATIVE_DISK_SAVE
#if MULTI_THREADED
ChangeFlag<false> 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));

View file

@ -1,8 +1,5 @@
#include "json_filter.h"
template <bool check_content_type>
JsonFilter<check_content_type>::JsonFilter() {}
__attribute__((always_inline)) inline bool Contains(std::string_view str, const std::string &val)
{
return str.find(val) != std::string::npos;

View file

@ -16,9 +16,6 @@ __attribute__((always_inline)) inline bool ValidUsername(const std::string &name
return true;
}
template <bool set_body_flag, bool require_admin>
UserFilter<set_body_flag, require_admin>::UserFilter(Bank &b) : bank(b) {}
template <bool set_body_flag, bool require_admin>
void UserFilter<set_body_flag, require_admin>::doFilter(const HttpRequestPtr &req,
FilterCallback &&fcb,
@ -43,10 +40,10 @@ void UserFilter<set_body_flag, require_admin>::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<set_body_flag, require_admin>::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)
{