mirror of
https://github.com/Expand-sys/CCash
synced 2025-12-17 00:22:14 +11:00
✨ finished Endpoint/Internal rewrite
This commit is contained in:
parent
0c34bc3689
commit
0e62dbe9ef
8 changed files with 130 additions and 169 deletions
|
|
@ -15,7 +15,6 @@ using BankResponse = std::pair<drogon::HttpStatusCode, Json::Value>;
|
|||
|
||||
class Bank
|
||||
{
|
||||
private:
|
||||
phmap::parallel_flat_hash_map<
|
||||
std::string, User,
|
||||
phmap::priv::hash_default_hash<std::string>,
|
||||
|
|
@ -25,6 +24,7 @@ private:
|
|||
std::mutex>
|
||||
users;
|
||||
|
||||
private:
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
ChangeFlag save_flag;
|
||||
#endif
|
||||
|
|
@ -53,16 +53,14 @@ public:
|
|||
|
||||
void ChangePassword(const std::string &name, std::string &&new_pass) noexcept;
|
||||
BankResponse SetBal(const std::string &name, uint32_t amount) noexcept;
|
||||
|
||||
int_fast8_t AddUser(const std::string &name, const std::string &init_pass) noexcept;
|
||||
int_fast8_t AdminAddUser(const std::string &attempt, std::string &&name, uint32_t init_bal, std::string &&init_pass) noexcept;
|
||||
|
||||
int_fast8_t DelUser(const std::string &name, const std::string &attempt) noexcept;
|
||||
int_fast8_t AdminDelUser(const std::string &name, const std::string &attempt) noexcept;
|
||||
|
||||
bool Contains(const std::string &name) const noexcept;
|
||||
bool AdminVerifyPass(const std::string &attempt) noexcept;
|
||||
|
||||
BankResponse AddUser(const std::string &name, std::string &&init_pass) noexcept;
|
||||
BankResponse AdminAddUser(std::string &&name, uint32_t init_bal, std::string &&init_pass) noexcept;
|
||||
|
||||
BankResponse DelUser(const std::string &name) noexcept;
|
||||
|
||||
void Save();
|
||||
void Load();
|
||||
};
|
||||
|
|
@ -25,9 +25,9 @@ public:
|
|||
void Help(req_args) const;
|
||||
void Ping(req_args) const;
|
||||
void Close(req_args) const;
|
||||
void AddUser(req_args, const std::string &name) const;
|
||||
void AdminAddUser(req_args, std::string &&name, uint32_t init_bal) const;
|
||||
void DelUser(req_args, const std::string &name) const;
|
||||
void AddUser(req_args) const;
|
||||
void AdminAddUser(req_args) const;
|
||||
void DelUser(req_args) const;
|
||||
void AdminDelUser(req_args, const std::string &name) const;
|
||||
void Contains(req_args, const std::string &name) const;
|
||||
void AdminVerifyPass(req_args);
|
||||
|
|
@ -37,7 +37,7 @@ public:
|
|||
//Usage
|
||||
METHOD_ADD(api::GetBal, "/v1/user/bal?name={name}", Get, Options); //done
|
||||
METHOD_ADD(api::GetLog, "/v1/user/log", Get, Options, "UserFilter"); //done (could be optimized further)
|
||||
METHOD_ADD(api::SendFunds, "/v1/user/transfer", Post, Options, "UserFilter"); //responses incomplete
|
||||
METHOD_ADD(api::SendFunds, "/v1/user/transfer", Post, Options, "UserFilter"); //done
|
||||
METHOD_ADD(api::VerifyPassword, "/v1/user/verify_password", Get, Options, "UserFilter"); //done
|
||||
|
||||
//Meta Usage
|
||||
|
|
@ -45,17 +45,17 @@ public:
|
|||
METHOD_ADD(api::SetBal, "/v1/admin/bal", Patch, Options, "AdminFilter"); //done
|
||||
|
||||
//System Usage
|
||||
METHOD_ADD(api::Help, "/help", Get, Options);
|
||||
METHOD_ADD(api::Ping, "/ping", Get, Options);
|
||||
METHOD_ADD(api::Close, "/admin/close", Post, Options);
|
||||
METHOD_ADD(api::Contains, "/contains/{name}", Get, Options);
|
||||
METHOD_ADD(api::AdminVerifyPass, "/admin/verify", Get, Options);
|
||||
METHOD_ADD(api::Help, "/v1/help", Get, Options); //done
|
||||
METHOD_ADD(api::Ping, "/v1/ping", Get, Options); //done
|
||||
METHOD_ADD(api::Close, "/v1/admin/shutdown", Post, Options, "AdminFilter"); //done
|
||||
METHOD_ADD(api::Contains, "/v1/user/exists?name={name}", Get, Options); //done
|
||||
METHOD_ADD(api::AdminVerifyPass, "/v1/admin/verify_password", Get, Options, "AdminFilter"); //done
|
||||
|
||||
//User Managment
|
||||
METHOD_ADD(api::AddUser, "/user/{name}", Post, Options);
|
||||
METHOD_ADD(api::AdminAddUser, "/admin/user/{name}?init_bal={init_bal}", Post, Options);
|
||||
METHOD_ADD(api::DelUser, "/user/{name}", Delete, Options);
|
||||
METHOD_ADD(api::AdminDelUser, "/admin/user/{name}", Delete, Options);
|
||||
METHOD_ADD(api::AddUser, "/v1/user/register", Post, Options); //done
|
||||
METHOD_ADD(api::AdminAddUser, "/v1/admin/user/register", Post, Options, "AdminFilter"); //done
|
||||
METHOD_ADD(api::DelUser, "/v1/delete", Delete, Options, "UserFilter"); //done
|
||||
METHOD_ADD(api::AdminDelUser, "/v1/admin/delete", Delete, Options, "AdminFilter"); //done
|
||||
|
||||
METHOD_LIST_END
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
#define MAX_LOG_SIZE 100
|
||||
#define PRE_LOG_SIZE 10
|
||||
|
||||
constexpr unsigned max_name_size = 50;
|
||||
constexpr unsigned min_name_size = 3;
|
||||
constexpr unsigned max_name_size = 16;
|
||||
|
||||
constexpr const char *users_location = "../users.json";
|
||||
constexpr const char *config_location = "../config.json";
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ enum ErrorResponse
|
|||
UserNotFound = -1, //404
|
||||
WrongPassword = -2, //401
|
||||
InvalidRequest = -3, //400
|
||||
NameTooLong = -4, //400?
|
||||
NameTooLong = -4, //400
|
||||
UserAlreadyExists = -5, //409
|
||||
InsufficientFunds = -6, //402?
|
||||
InsufficientFunds = -6, //400
|
||||
};
|
||||
|
|
@ -12,11 +12,11 @@ struct User
|
|||
Log log;
|
||||
#endif
|
||||
|
||||
User(const std::string &init_pass);
|
||||
User(uint32_t init_bal, const std::string &init_pass);
|
||||
User(uint32_t init_bal, uint64_t init_pass);
|
||||
User(std::string &&init_pass) noexcept;
|
||||
User(uint32_t init_bal, std::string &&init_pass) noexcept;
|
||||
User(uint32_t init_bal, uint64_t init_pass) noexcept;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
User(uint32_t init_bal, uint64_t init_pass, const Json::Value &log_j);
|
||||
User(uint32_t init_bal, uint64_t init_pass, const Json::Value &log_j) noexcept;
|
||||
#endif
|
||||
|
||||
Json::Value Serialize() const; //to be removed later
|
||||
|
|
|
|||
175
src/bank.cpp
175
src/bank.cpp
|
|
@ -1,5 +1,21 @@
|
|||
#include "bank.h"
|
||||
|
||||
__attribute__((always_inline)) inline bool ValidUsrname(const std::string &name) noexcept
|
||||
{
|
||||
if (name.size() < min_name_size || name.size() > max_name_size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (const char &c : name)
|
||||
{
|
||||
if (!(std::isalpha(c) || std::isdigit(c) || c == '_'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
using namespace drogon;
|
||||
|
||||
bool Bank::GetChangeState() const noexcept { return save_flag.GetChangeState(); }
|
||||
|
|
@ -46,7 +62,7 @@ BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_nam
|
|||
}
|
||||
|
||||
BankResponse state;
|
||||
std::shared_lock<std::shared_mutex> lock{send_funds_l};
|
||||
std::shared_lock<std::shared_mutex> lock{send_funds_l}; //about 10% of this function's cost
|
||||
#if MAX_LOG_SIZE > 0
|
||||
Transaction temp(a_name, b_name, amount);
|
||||
if (!users.modify_if(a_name, [&temp, &state, amount](User &a) {
|
||||
|
|
@ -56,13 +72,13 @@ BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_nam
|
|||
//if A can afford it
|
||||
if (a.balance < amount)
|
||||
{
|
||||
state = {k402PaymentRequired, "Sender has insufficient funds"};
|
||||
state = {k400BadRequest, "Sender has insufficient funds"};
|
||||
}
|
||||
else
|
||||
{
|
||||
a.balance -= amount;
|
||||
#if MAX_LOG_SIZE > 0
|
||||
a.log.AddTrans(Transaction(temp));
|
||||
a.log.AddTrans(Transaction(temp)); //about 40% of this function's cost
|
||||
#endif
|
||||
state = {k200OK, "Transfer successful!"};
|
||||
}
|
||||
|
|
@ -75,13 +91,13 @@ BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_nam
|
|||
#if MAX_LOG_SIZE > 0
|
||||
users.modify_if(b_name, [&temp, amount](User &b) {
|
||||
b.balance += amount;
|
||||
b.log.AddTrans(std::move(temp)); });
|
||||
b.log.AddTrans(std::move(temp)); }); //about 40% of this function's cost
|
||||
#else
|
||||
users.modify_if(b_name, [amount](User &b) { b.balance += amount; });
|
||||
#endif
|
||||
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
save_flag.SetChangesOn();
|
||||
save_flag.SetChangesOn(); //about 5% of this function's cost
|
||||
#endif
|
||||
}
|
||||
return state;
|
||||
|
|
@ -120,107 +136,6 @@ BankResponse Bank::SetBal(const std::string &name, uint32_t amount) noexcept
|
|||
return BankResponse(k404NotFound, "User not found");
|
||||
}
|
||||
}
|
||||
|
||||
int_fast8_t Bank::AddUser(const std::string &name, const std::string &init_pass) noexcept
|
||||
{
|
||||
if (name.size() > max_name_size)
|
||||
{
|
||||
return ErrorResponse::NameTooLong;
|
||||
}
|
||||
if (name.find(' ') != std::string::npos)
|
||||
{
|
||||
return ErrorResponse::InvalidRequest;
|
||||
}
|
||||
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
return (users.try_emplace_l(
|
||||
name, [](User &) {}, init_pass))
|
||||
? true
|
||||
: ErrorResponse::UserAlreadyExists;
|
||||
}
|
||||
int_fast8_t Bank::AdminAddUser(const std::string &attempt, std::string &&name, uint32_t init_bal, std::string &&init_pass) noexcept
|
||||
{
|
||||
if (name.size() > max_name_size)
|
||||
{
|
||||
return ErrorResponse::NameTooLong;
|
||||
}
|
||||
if (admin_pass != attempt)
|
||||
{
|
||||
return ErrorResponse::WrongPassword;
|
||||
}
|
||||
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
return (users.try_emplace_l(
|
||||
name, [](User &) {}, init_bal, std::move(init_pass)))
|
||||
? true
|
||||
: ErrorResponse::UserAlreadyExists;
|
||||
}
|
||||
int_fast8_t Bank::DelUser(const std::string &name, const std::string &attempt) noexcept
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
bool state = false;
|
||||
#if RETURN_ON_DEL
|
||||
uint32_t bal;
|
||||
if (users.erase_if(name, [this, &bal, &name, &state, &attempt](User &u) {
|
||||
bal = u.balance;
|
||||
#else
|
||||
if (!users.erase_if(name, [this, &name, &state, &attempt](User &u) {
|
||||
#endif
|
||||
return state = (XXH3_64bits(attempt.data(), attempt.size()) == u.password);
|
||||
}))
|
||||
{
|
||||
return ErrorResponse::UserNotFound;
|
||||
}
|
||||
#if RETURN_ON_DEL
|
||||
if (state) //if the password matches
|
||||
{
|
||||
users.modify_if(return_account, [&bal](User &u) {
|
||||
u.balance += bal;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ErrorResponse::WrongPassword;
|
||||
}
|
||||
#else
|
||||
return (state) ? true : ErrorResponse::WrongPassword;
|
||||
#endif
|
||||
}
|
||||
int_fast8_t Bank::AdminDelUser(const std::string &name, const std::string &attempt) noexcept
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
bool state = false;
|
||||
#if RETURN_ON_DEL
|
||||
uint32_t bal;
|
||||
if (users.erase_if(name, [this, &bal, &name, &state, &attempt](User &u) {
|
||||
bal = u.balance;
|
||||
#else
|
||||
if (users.erase_if(name, [this, &name, &state, &attempt](User &u) {
|
||||
#endif
|
||||
return state = (XXH3_64bits(attempt.data(), attempt.size()) == u.password);
|
||||
}))
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
#if RETURN_ON_DEL
|
||||
users.modify_if(return_account, [&bal](User &u) {
|
||||
u.balance += bal;
|
||||
});
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ErrorResponse::WrongPassword;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ErrorResponse::UserNotFound;
|
||||
}
|
||||
}
|
||||
|
||||
bool Bank::Contains(const std::string &name) const noexcept
|
||||
{
|
||||
return users.contains(name);
|
||||
|
|
@ -230,6 +145,54 @@ bool Bank::AdminVerifyPass(const std::string &attempt) noexcept
|
|||
return (admin_pass == attempt);
|
||||
}
|
||||
|
||||
BankResponse Bank::AddUser(const std::string &name, std::string &&init_pass) noexcept
|
||||
{
|
||||
if (!ValidUsrname(name))
|
||||
{
|
||||
return BankResponse(k400BadRequest, "Invalid Name, breaks size and/or character restrictions");
|
||||
}
|
||||
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
return (users.try_emplace_l(
|
||||
name, [](User &) {}, std::move(init_pass)))
|
||||
? BankResponse(k200OK, "User added!")
|
||||
: BankResponse(k409Conflict, "User already exists");
|
||||
}
|
||||
BankResponse Bank::AdminAddUser(std::string &&name, uint32_t init_bal, std::string &&init_pass) noexcept
|
||||
{
|
||||
if (!ValidUsrname(name))
|
||||
{
|
||||
return BankResponse(k400BadRequest, "Invalid Name, breaks size and/or character restrictions");
|
||||
}
|
||||
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
return (users.try_emplace_l(
|
||||
name, [](User &) {}, init_bal, std::move(init_pass)))
|
||||
? BankResponse(k200OK, "User added!")
|
||||
: BankResponse(k409Conflict, "User already exists");
|
||||
}
|
||||
BankResponse Bank::DelUser(const std::string &name) noexcept
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
#if RETURN_ON_DEL
|
||||
uint32_t bal;
|
||||
if (users.erase_if(name, [this, &bal, &name](User &u) {
|
||||
bal = u.balance;
|
||||
return true;
|
||||
}))
|
||||
#else
|
||||
if (!users.erase(name))
|
||||
#endif
|
||||
{
|
||||
return BankResponse(k404NotFound, "User not found");
|
||||
}
|
||||
#if RETURN_ON_DEL
|
||||
users.modify_if(return_account, [&bal](User &u) {
|
||||
u.balance += bal;
|
||||
});
|
||||
#endif
|
||||
return BankResponse(k200OK, "User deleted!");
|
||||
}
|
||||
void Bank::Save()
|
||||
{
|
||||
#if CONSERVATIVE_DISK_SAVE
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ api::api(Bank &b) : bank(b)
|
|||
|
||||
#if API_VERSION == 1
|
||||
|
||||
//Usage
|
||||
void api::GetBal(req_args, const std::string &name) const
|
||||
{
|
||||
RESPONSE_PARSE(bank.GetBal(name));
|
||||
|
|
@ -76,6 +77,7 @@ void api::VerifyPassword(req_args) const
|
|||
RESPOND_TRUE //as we know the user exists and is verified
|
||||
}
|
||||
|
||||
//Meta Usage
|
||||
void api::ChangePassword(req_args) const
|
||||
{
|
||||
GEN_BODY
|
||||
|
|
@ -88,6 +90,7 @@ void api::SetBal(req_args) const
|
|||
RESPONSE_PARSE(bank.SetBal(NAME_PARAM, body["amount"].asUInt()));
|
||||
}
|
||||
|
||||
//System Usage
|
||||
void api::Help(req_args) const
|
||||
{
|
||||
auto resp = HttpResponse::newHttpResponse();
|
||||
|
|
@ -104,42 +107,38 @@ void api::Ping(req_args) const
|
|||
}
|
||||
void api::Close(req_args) const
|
||||
{
|
||||
bool res;
|
||||
if (PASS_HEADER == bank.admin_pass)
|
||||
{
|
||||
bank.Save();
|
||||
|
||||
res = true;
|
||||
app().quit();
|
||||
}
|
||||
else
|
||||
{
|
||||
res = false;
|
||||
}
|
||||
JSON(res);
|
||||
}
|
||||
void api::AddUser(req_args, const std::string &name) const
|
||||
{
|
||||
JSON(bank.AddUser(std::move(name), PASS_HEADER));
|
||||
}
|
||||
void api::AdminAddUser(req_args, std::string &&name, uint32_t init_bal) const
|
||||
{
|
||||
JSON(bank.AdminAddUser(PASS_HEADER, std::move(name), init_bal, std::string(req->getBody())));
|
||||
}
|
||||
void api::DelUser(req_args, const std::string &name) const
|
||||
{
|
||||
JSON(bank.DelUser(name, PASS_HEADER));
|
||||
}
|
||||
void api::AdminDelUser(req_args, const std::string &name) const
|
||||
{
|
||||
JSON(bank.AdminDelUser(name, PASS_HEADER));
|
||||
bank.Save();
|
||||
app().quit();
|
||||
RESPOND_TRUE //filter handles admin creds
|
||||
}
|
||||
void api::Contains(req_args, const std::string &name) const
|
||||
{
|
||||
JSON(bank.Contains(name));
|
||||
auto resp = HttpResponse::newHttpJsonResponse(JsonCast(bank.Contains(name)));
|
||||
resp->setStatusCode(k200OK);
|
||||
callback(resp);
|
||||
}
|
||||
void api::AdminVerifyPass(req_args)
|
||||
{
|
||||
JSON(bank.AdminVerifyPass(PASS_HEADER));
|
||||
RESPOND_TRUE //filter handles admin creds
|
||||
}
|
||||
|
||||
void api::AddUser(req_args) const
|
||||
{
|
||||
GEN_BODY
|
||||
RESPONSE_PARSE(bank.AddUser(body["name"].asCString(), body["pass"].asCString()))
|
||||
}
|
||||
void api::AdminAddUser(req_args) const
|
||||
{
|
||||
GEN_BODY
|
||||
RESPONSE_PARSE(bank.AdminAddUser(body["name"].asCString(), body["balance"].asUInt(), body["pass"].asCString()))
|
||||
}
|
||||
void api::DelUser(req_args) const
|
||||
{
|
||||
RESPONSE_PARSE(bank.DelUser(NAME_PARAM))
|
||||
}
|
||||
void api::AdminDelUser(req_args) const
|
||||
{
|
||||
GEN_BODY
|
||||
RESPONSE_PARSE(bank.DelUser(body["name"].asCString()))
|
||||
}
|
||||
#endif
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* @param init_pass initial password
|
||||
*/
|
||||
User::User(const std::string &init_pass) : password(XXH3_64bits(init_pass.data(), init_pass.size())) {}
|
||||
User::User(std::string &&init_pass) noexcept : password(XXH3_64bits(init_pass.data(), init_pass.size())) {}
|
||||
|
||||
/**
|
||||
* @brief User Constructor for admins
|
||||
|
|
@ -13,7 +13,7 @@ User::User(const std::string &init_pass) : password(XXH3_64bits(init_pass.data()
|
|||
* @param init_bal initial balance
|
||||
* @param init_pass initial password
|
||||
*/
|
||||
User::User(uint32_t init_bal, const std::string &init_pass) : balance(init_bal), password(XXH3_64bits(init_pass.data(), init_pass.size())) {}
|
||||
User::User(uint32_t init_bal, std::string &&init_pass) noexcept : balance(init_bal), password(XXH3_64bits(init_pass.data(), init_pass.size())) {}
|
||||
|
||||
/**
|
||||
* @brief User Constructor for loading
|
||||
|
|
@ -21,9 +21,9 @@ User::User(uint32_t init_bal, const std::string &init_pass) : balance(init_bal),
|
|||
* @param init_bal
|
||||
* @param init_pass
|
||||
*/
|
||||
User::User(uint32_t init_bal, uint64_t init_pass) : balance(init_bal), password(init_pass) {}
|
||||
User::User(uint32_t init_bal, uint64_t init_pass) noexcept : balance(init_bal), password(init_pass) {}
|
||||
#if MAX_LOG_SIZE > 0
|
||||
User::User(uint32_t init_bal, uint64_t init_pass, const Json::Value &log_j) : balance(init_bal), password(init_pass)
|
||||
User::User(uint32_t init_bal, uint64_t init_pass, const Json::Value &log_j) noexcept : balance(init_bal), password(init_pass)
|
||||
{
|
||||
if (log_j.size())
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue