this is the greatest and best commit in the world ...

... tribute
This commit is contained in:
malloc 2018-11-15 16:29:03 -06:00
parent 6ed3adfb87
commit 28b4ace8b8
8 changed files with 112 additions and 87 deletions

1
.gitignore vendored
View file

@ -7,3 +7,4 @@ connectionStrings.config
.idea/ .idea/
cmake-build-*/ cmake-build-*/
*.db-journal *.db-journal
scape.db

View file

@ -1,7 +1,7 @@
[General] [General]
Run Master = true Run Master = true
Master Host = localhost Master Host = localhost
Master Port = 5050 Master Port = 5051
[Defaults] [Defaults]
; amount of threads to start with (never close) ; amount of threads to start with (never close)
@ -22,19 +22,19 @@ Max Total = -1
Tolerance = -1 Tolerance = -1
[Master to Client] [Master to Client]
Port = 5050 Port = 5051
[Master to Slave] [Master to Slave]
Port = 8008 Port = 8018
[Slave] [Slave]
Port = 9000 Port = 9010
Name = Test Server 1 Name = Test Server 1
[Slave] [Slave]
Port = 9001 Port = 9011
Name = Test Server 2 Name = Test Server 2
[Slave] [Slave]
Port = 9002 Port = 9012
Name = Test Server 3 Name = Test Server 3

View file

@ -3,7 +3,7 @@
#include <vector> #include <vector>
const char* _mem_db_sql = const std::vector<const char*> _mem_db_sql = {
"CREATE TABLE `SERVER_LIST` (" "CREATE TABLE `SERVER_LIST` ("
"`ID` INTEGER PRIMARY KEY AUTOINCREMENT," "`ID` INTEGER PRIMARY KEY AUTOINCREMENT,"
"`NAME` TEXT NOT NULL," "`NAME` TEXT NOT NULL,"
@ -12,33 +12,35 @@ const char* _mem_db_sql =
"`PORT` INTEGER NOT NULL," "`PORT` INTEGER NOT NULL,"
"`USERS` INTEGER NOT NULL DEFAULT 0," "`USERS` INTEGER NOT NULL DEFAULT 0,"
"`MAX_USERS` INTEGER NOT NULL DEFAULT 0" "`MAX_USERS` INTEGER NOT NULL DEFAULT 0"
");\n" ");",
"CREATE TABLE `USER_KEYS` (" "CREATE TABLE `USER_KEYS` ("
"`ID` INTEGER," "`ID` INTEGER,"
"`SECRET` BLOB NOT NULL UNIQUE," "`SECRET` BLOB NOT NULL UNIQUE,"
"PRIMARY KEY(`ID`)" "PRIMARY KEY(`ID`)"
");\n"; ");",
};
const char* _hard_db_init_migration_sql = const std::vector<const char*> _hard_db_init_migration_sql = {
"CREATE TABLE `MIGRATIONS` (" "CREATE TABLE `MIGRATIONS` ("
"`ID` INTEGER NOT NULL," "`ID` INTEGER NOT NULL,"
"`SQL_HASH` TEXT NOT NULL," "`SQL_HASH` TEXT NOT NULL,"
"`DATE_RAN` INTEGER NOT NULL," "`DATE_RAN` INTEGER NOT NULL,"
"PRIMARY KEY(`ID`)" "PRIMARY KEY(`ID`)"
") WITHOUT ROWID;\n"; ") WITHOUT ROWID;",
};
const std::vector<const char*> _hard_db_sql = { const std::vector<std::vector<const char*>> _hard_db_sql = {
/** START MIGRATION 0 **/ { /** START MIGRATION 0 **/
"CREATE TABLE `SERVER_LICENSES` (" "CREATE TABLE `SERVER_LICENSES` ("
"`KEY_ID` TEXT NOT NULL PRIMARY KEY AUTOINCREMENT," "`KEY_ID` INTEGER PRIMARY KEY AUTOINCREMENT,"
"`SECRET` BLOB NOT NULL," "`SECRET` BLOB NOT NULL,"
"`ALLOWANCE` INTEGER NOT NULL DEFAULT 0" "`ALLOWANCE` INTEGER NOT NULL DEFAULT 0"
");\n" ");",
"CREATE UNIQUE INDEX `UIX_SERVER_LICENSES` ON `SERVER_LICENSES` (" "CREATE UNIQUE INDEX `UIX_SERVER_LICENSES` ON `SERVER_LICENSES` ("
"`KEY_ID`, `SECRET`" "`KEY_ID`, `SECRET`"
");\n" ");",
"CREATE TABLE `USERS` (" "CREATE TABLE `USERS` ("
"`ID` INTEGER PRIMARY KEY AUTOINCREMENT," "`ID` INTEGER PRIMARY KEY AUTOINCREMENT,"
@ -47,15 +49,15 @@ const std::vector<const char*> _hard_db_sql = {
"`EMAIL` TEXT NOT NULL," "`EMAIL` TEXT NOT NULL,"
"`ACTIVATED` INTEGER NOT NULL DEFAULT 0," "`ACTIVATED` INTEGER NOT NULL DEFAULT 0,"
"`JOINED` INTEGER NOT NULL" "`JOINED` INTEGER NOT NULL"
");\n" ");",
"CREATE TABLE `ACTIVATION_CODES` (" "CREATE TABLE `ACTIVATION_CODES` ("
"`USER_ID` INTEGER NOT NULL UNIQUE," "`USER_ID` INTEGER NOT NULL UNIQUE,"
"`CODE` TEXT NOT NULL," "`CODE` TEXT NOT NULL,"
"`CREATED` INTEGER NOT NULL," "`CREATED` INTEGER NOT NULL,"
"PRIMARY KEY(`USER_ID`)" "PRIMARY KEY(`USER_ID`)"
") WITHOUT ROWID;\n", ") WITHOUT ROWID;",
/** END MIGRATION 0 **/ }, /** END MIGRATION 0 **/
}; };
#endif #endif

View file

@ -14,7 +14,8 @@ bool sosc::db::init_databases(std::string* error) {
_ctx.ready = true; _ctx.ready = true;
sqlite3_open(":memory:", &_ctx.mem_db); sqlite3_open(":memory:", &_ctx.mem_db);
sqlite3_exec(_ctx.mem_db, _mem_db_sql, nullptr, nullptr, nullptr); for(const auto& query : _mem_db_sql)
sqlite3_exec(_ctx.mem_db, query, nullptr, nullptr, nullptr);
sqlite3_open(SOSC_RESC("scape.db").c_str(), &_ctx.hard_db); sqlite3_open(SOSC_RESC("scape.db").c_str(), &_ctx.hard_db);
@ -22,7 +23,8 @@ bool sosc::db::init_databases(std::string* error) {
"SELECT COUNT(*) FROM SQLITE_MASTER WHERE TBL_NAME = 'MIGRATIONS'" "SELECT COUNT(*) FROM SQLITE_MASTER WHERE TBL_NAME = 'MIGRATIONS'"
); );
if(migrationsExist == 0) if(migrationsExist == 0)
db::Query::NonQuery(_hard_db_init_migration_sql); for(const auto& query : _hard_db_init_migration_sql)
db::Query::NonQuery(query);
int32_t lastMig = db::Query::ScalarInt32("SELECT MAX(ID) FROM MIGRATIONS"); int32_t lastMig = db::Query::ScalarInt32("SELECT MAX(ID) FROM MIGRATIONS");
if(lastMig > _hard_db_sql.size()) { if(lastMig > _hard_db_sql.size()) {
@ -39,9 +41,11 @@ bool sosc::db::init_databases(std::string* error) {
); );
Query getMigration("SELECT SQL_HASH FROM MIGRATIONS WHERE ID = ?"); Query getMigration("SELECT SQL_HASH FROM MIGRATIONS WHERE ID = ?");
for(id = 0; id < _hard_db_sql.size(); ++id) { for(id = 0; id < _hard_db_sql.size(); ++id) {
getMigration.BindInt32(id, 0); getMigration.Reset();
getMigration.BindInt32(id, 1);
std::string hash = getMigration.ScalarText(); std::string hash = getMigration.ScalarText();
std::string local_hash = "";
if(hash.empty()) { if(hash.empty()) {
if(id < lastMig) { if(id < lastMig) {
if(error != nullptr) if(error != nullptr)
@ -50,13 +54,20 @@ bool sosc::db::init_databases(std::string* error) {
return false; return false;
} }
Query::NonQuery(_hard_db_sql[id]); for(const auto& query : _hard_db_sql[id]) {
Query::NonQuery(query);
local_hash += cgc::sha1(query);
}
insertMigration.BindInt32(id, 0); insertMigration.Reset();
insertMigration.BindText(cgc::sha1(_hard_db_sql[id]), 1); insertMigration.BindInt32(id, 1);
insertMigration.BindText(cgc::sha1(local_hash), 2);
insertMigration.NonQuery(); insertMigration.NonQuery();
} else { } else {
if(hash != cgc::sha1(_hard_db_sql[id])) { for(const auto& query : _hard_db_sql[id])
local_hash += cgc::sha1(query);
if(hash != cgc::sha1(local_hash)) {
if(error != nullptr) if(error != nullptr)
*error = "HARD DB: MIGRATION SQL HASH MISMATCH"; *error = "HARD DB: MIGRATION SQL HASH MISMATCH";
_ctx.ready = false; _ctx.ready = false;
@ -338,7 +349,7 @@ bool sosc::db::ResultSet::Step() {
else if(result == SQLITE_DONE) else if(result == SQLITE_DONE)
return false; return false;
else else
throw std::string(sqlite3_errmsg(this->query->database)); throw std::runtime_error(sqlite3_errmsg(this->query->database));
} }
double sosc::db::ResultSet::GetDouble(int column) { double sosc::db::ResultSet::GetDouble(int column) {

View file

@ -42,19 +42,19 @@ void sosc::MasterClientPool::SetupQueries(db::Queries *queries) {
queries->push_back(new db::Query( queries->push_back(new db::Query(
"INSERT OR IGNORE INTO `USER_KEYS` " "INSERT OR IGNORE INTO `USER_KEYS` "
"(`ID`, `SECRET`) VALUES (?, RANDOMBLOB(128))" "(`ID`, `SECRET`) VALUES (?, RANDOMBLOB(128))"
)); , DB_USE_MEMORY));
#define QRY_USER_GET_KEY 6 #define QRY_USER_GET_KEY 6
queries->push_back(new db::Query( queries->push_back(new db::Query(
"SELECT `SECRET` FROM `USER_KEYS` " "SELECT `SECRET` FROM `USER_KEYS` "
"WHERE `ID` = ?" "WHERE `ID` = ?"
)); , DB_USE_MEMORY));
#define QRY_USER_CHECK_KEY 7 #define QRY_USER_CHECK_KEY 7
queries->push_back(new db::Query( queries->push_back(new db::Query(
"SELECT COUNT(*) FROM `USER_KEYS` " "SELECT COUNT(*) FROM `USER_KEYS` "
"WHERE `ID` = ? AND `SECRET` = ?" "WHERE `ID` = ? AND `SECRET` = ?"
)); , DB_USE_MEMORY));
} }
/** MASTERCLIENT CODE **/ /** MASTERCLIENT CODE **/
@ -99,13 +99,13 @@ bool sosc::MasterClient::ProcessLogin(Packet &pck) {
db::ResultSet* results = nullptr; db::ResultSet* results = nullptr;
db::Query* query = this->queries->at(QRY_USER_NAME_EXISTS); db::Query* query = this->queries->at(QRY_USER_NAME_EXISTS);
query->Reset(); query->Reset();
query->BindText(pck[0], 0); query->BindText(pck[0], 1);
if(query->ScalarInt32() == 0) if(query->ScalarInt32() == 0)
return LoginError(0x101); return LoginError(0x101);
query = this->queries->at(QRY_USER_GET_PWD_HASH); query = this->queries->at(QRY_USER_GET_PWD_HASH);
query->Reset(); query->Reset();
query->BindText(pck[0], 0); query->BindText(pck[0], 1);
results = query->GetResults(); results = query->GetResults();
results->Step(); results->Step();
@ -115,12 +115,12 @@ bool sosc::MasterClient::ProcessLogin(Packet &pck) {
query = this->queries->at(QRY_USER_GENERATE_KEY); query = this->queries->at(QRY_USER_GENERATE_KEY);
query->Reset(); query->Reset();
query->BindInt64(user_id, 0); query->BindInt64(user_id, 1);
query->NonQuery(); query->NonQuery();
query = this->queries->at(QRY_USER_GET_KEY); query = this->queries->at(QRY_USER_GET_KEY);
query->Reset(); query->Reset();
query->BindInt64(user_id, 0); query->BindInt64(user_id, 1);
auto secret = query->ScalarBlob(); auto secret = query->ScalarBlob();
this->sock.Send(Packet(kLoginResponse, {"\1", secret})); this->sock.Send(Packet(kLoginResponse, {"\1", secret}));
@ -148,21 +148,21 @@ bool sosc::MasterClient::ProcessRegistration(Packet &pck) {
db::Query* query = this->queries->at(QRY_USER_NAME_REG_CHECK); db::Query* query = this->queries->at(QRY_USER_NAME_REG_CHECK);
query->Reset(); query->Reset();
query->BindText(pck[0], 0); query->BindText(pck[0], 1);
if(query->ScalarInt32() > 0) if(query->ScalarInt32() > 0)
return RegistrationError(0x100); return RegistrationError(0x100);
query = this->queries->at(QRY_USER_MAIL_REG_CHECK); query = this->queries->at(QRY_USER_MAIL_REG_CHECK);
query->Reset(); query->Reset();
query->BindText(pck[2], 0); query->BindText(pck[2], 1);
if(query->ScalarInt32() > 0) if(query->ScalarInt32() > 0)
return RegistrationError(0x101); return RegistrationError(0x101);
query = this->queries->at(QRY_USER_REGISTER); query = this->queries->at(QRY_USER_REGISTER);
query->Reset(); query->Reset();
query->BindText(pck[0], 0); query->BindText(pck[0], 1);
query->BindText(cgc::bcrypt_hash(pck[1]), 1); query->BindText(cgc::bcrypt_hash(pck[1]), 2);
query->BindText(pck[2], 2); query->BindText(pck[2], 3);
query->NonQuery(); query->NonQuery();
this->sock.Send(Packet(kRegisterResponse, {"\1", 0x000})); this->sock.Send(Packet(kRegisterResponse, {"\1", 0x000}));

View file

@ -110,8 +110,8 @@ bool sosc::MasterIntra::Authentication(sosc::Packet& pck) {
db::Query* query = this->queries->at(QRY_LICENSE_CHECK); db::Query* query = this->queries->at(QRY_LICENSE_CHECK);
query->Reset(); query->Reset();
query->BindText(pck[2], 0); query->BindText(pck[2], 1);
query->BindBlob(pck[3], 1); query->BindBlob(pck[3], 2);
if(query->ScalarInt32() == 0) if(query->ScalarInt32() == 0)
return AuthenticationFailure(packetId, 0x101); return AuthenticationFailure(packetId, 0x101);
@ -120,11 +120,11 @@ bool sosc::MasterIntra::Authentication(sosc::Packet& pck) {
int limit; int limit;
query = this->queries->at(QRY_LICENSE_LIMIT); query = this->queries->at(QRY_LICENSE_LIMIT);
query->Reset(); query->Reset();
query->BindText(pck[2], 0); query->BindText(pck[2], 1);
if((limit = query->ScalarInt32()) != 0) { if((limit = query->ScalarInt32()) != 0) {
query = this->queries->at(QRY_LICENSE_ACTIVE_COUNT); query = this->queries->at(QRY_LICENSE_ACTIVE_COUNT);
query->Reset(); query->Reset();
query->BindText(pck[2], 0); query->BindText(pck[2], 1);
if(query->ScalarInt32() < limit) { if(query->ScalarInt32() < limit) {
_ctx.license_check_mtx.unlock(); _ctx.license_check_mtx.unlock();
return AuthenticationFailure(packetId, 0x102); return AuthenticationFailure(packetId, 0x102);
@ -133,10 +133,10 @@ bool sosc::MasterIntra::Authentication(sosc::Packet& pck) {
query = this->queries->at(QRY_SERVER_LIST_ADD); query = this->queries->at(QRY_SERVER_LIST_ADD);
query->Reset(); query->Reset();
query->BindText(pck[0], 0); query->BindText(pck[0], 1);
query->BindText(pck[2], 1); query->BindText(pck[2], 2);
query->BindText(this->sock.GetIpAddress(), 2); query->BindText(this->sock.GetIpAddress(), 3);
query->BindInt32(net::ntohv<uint16_t>(pck[1]), 3); query->BindInt32(net::ntohv<uint16_t>(pck[1]), 4);
query->NonQuery(); query->NonQuery();
query = this->queries->at(QRY_SERVER_LIST_GET_ID); query = this->queries->at(QRY_SERVER_LIST_GET_ID);
@ -179,7 +179,7 @@ bool sosc::MasterIntra::StatusUpdate(sosc::Packet &pck) {
db::Query* query = this->queries->at(QRY_LICENSE_VERIFY); db::Query* query = this->queries->at(QRY_LICENSE_VERIFY);
query->Reset(); query->Reset();
query->BindText(this->license, 0); query->BindText(this->license, 1);
if(query->ScalarInt32() == 0) if(query->ScalarInt32() == 0)
return this->NotAuthorized(packetId); return this->NotAuthorized(packetId);
@ -188,8 +188,8 @@ bool sosc::MasterIntra::StatusUpdate(sosc::Packet &pck) {
query = this->queries->at(QRY_SERVER_LIST_MODIFY); query = this->queries->at(QRY_SERVER_LIST_MODIFY);
query->Reset(); query->Reset();
query->BindInt32(net::ntohv<uint16_t>(pck[0]), 0); query->BindInt32(net::ntohv<uint16_t>(pck[0]), 1);
query->BindInt32(net::ntohv<uint16_t>(pck[1]), 1); query->BindInt32(net::ntohv<uint16_t>(pck[1]), 2);
query->BindInt32(this->server_id, 2); query->BindInt32(this->server_id, 2);
query->NonQuery(); query->NonQuery();
return true; return true;

View file

@ -96,7 +96,7 @@ int main(int argc, char **argv) {
}) })
}); });
} catch(const std::exception& e) { } catch(const std::exception& e) {
std::cout << e.what() << std::endl; std::cerr << e.what() << std::endl;
return -1; return -1;
} }
@ -107,27 +107,33 @@ int main(int argc, char **argv) {
if(!config->HasSection("master to client") || if(!config->HasSection("master to client") ||
!config->HasSection("master to slave")) !config->HasSection("master to slave"))
{ {
std::cout << "'MASTER TO CLIENT' and 'MASTER TO SLAVE' sections " std::cerr << "'MASTER TO CLIENT' and 'MASTER TO SLAVE' sections "
<< "must exist if 'RUN MASTER' is true." << std::endl; << "must exist if 'RUN MASTER' is true." << std::endl;
return -1; return -1;
} }
if(!db::init_databases(nullptr)) { if(!db::init_databases(nullptr)) {
std::cout << "Could not initialized master database."; std::cerr << "Could not initialized master database.";
return -1; return -1;
} }
configure_poolinfo(&info, (*config)["master to slave"][0]); configure_poolinfo(&info, (*config)["master to slave"][0]);
_ctx.master_intra = new master_intra_ctx; _ctx.master_intra = new master_intra_ctx;
master_intra_start( if(!master_intra_start(
(uint16_t)(*config)["master to slave"]["port"], info (uint16_t)(*config)["master to slave"]["port"], info))
); {
std::cerr << "Could not start master-slave server." << std::endl;
return -1;
}
configure_poolinfo(&info, (*config)["master to client"][0]); configure_poolinfo(&info, (*config)["master to client"][0]);
_ctx.master_client = new master_client_ctx; _ctx.master_client = new master_client_ctx;
master_client_start( if(!master_client_start(
(uint16_t)(*config)["master to client"]["port"], info (uint16_t)(*config)["master to client"]["port"], info))
); {
std::cerr << "Could not start master-client server." << std::endl;
return -1;
}
} }
if(config->HasSection("slave")) { if(config->HasSection("slave")) {
@ -136,10 +142,13 @@ int main(int argc, char **argv) {
for(int i = 0; i < _ctx.slave_count; ++i) { for(int i = 0; i < _ctx.slave_count; ++i) {
configure_poolinfo(&info, (*config)["slave"][i]); configure_poolinfo(&info, (*config)["slave"][i]);
slave_start( if(!slave_start(
(uint16_t)(*config)["slave"][i]["port"], (uint16_t)(*config)["slave"][i]["port"],
info, _ctx.slaves + i info, _ctx.slaves + i))
); {
std::cerr << "Could not start slave server." << std::endl;
return -1;
}
} }
} }
@ -158,6 +167,7 @@ int main(int argc, char **argv) {
master_intra_stop(); master_intra_stop();
for(int i = 0; i < _ctx.slave_count; ++i) for(int i = 0; i < _ctx.slave_count; ++i)
slave_stop(_ctx.slaves + i); slave_stop(_ctx.slaves + i);
delete[] _ctx.slaves;
return 0; return 0;
} }
@ -215,6 +225,7 @@ void master_intra_stop() {
return; return;
_ctx.master_intra->server.Close(); _ctx.master_intra->server.Close();
if(_ctx.master_intra->thread.joinable())
_ctx.master_intra->thread.join(); _ctx.master_intra->thread.join();
_ctx.master_intra->pool.Stop(); _ctx.master_intra->pool.Stop();
@ -227,6 +238,7 @@ void master_client_stop() {
return; return;
_ctx.master_client->server.Close(); _ctx.master_client->server.Close();
if(_ctx.master_client->thread.joinable())
_ctx.master_client->thread.join(); _ctx.master_client->thread.join();
_ctx.master_client->pool.Stop(); _ctx.master_client->pool.Stop();
@ -239,8 +251,7 @@ void slave_stop(slave_ctx* ctx) {
return; return;
ctx->server.Close(); ctx->server.Close();
if(ctx->thread.joinable())
ctx->thread.join(); ctx->thread.join();
ctx->pool.Stop(); ctx->pool.Stop();
delete ctx;
} }

View file

@ -185,7 +185,7 @@ function parse(data) {
} }
function conn_open() { function conn_open() {
ws = new WebSocket("wss://localhost:8008"); ws = new WebSocket("wss://localhost:5050");
ws.binaryType = "arraybuffer"; ws.binaryType = "arraybuffer";
ws.onopen = function (e) { ws.onopen = function (e) {