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/
cmake-build-*/
*.db-journal
scape.db

View file

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

View file

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

View file

@ -14,7 +14,8 @@ bool sosc::db::init_databases(std::string* error) {
_ctx.ready = true;
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);
@ -22,7 +23,8 @@ bool sosc::db::init_databases(std::string* error) {
"SELECT COUNT(*) FROM SQLITE_MASTER WHERE TBL_NAME = 'MIGRATIONS'"
);
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");
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 = ?");
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 local_hash = "";
if(hash.empty()) {
if(id < lastMig) {
if(error != nullptr)
@ -50,13 +54,20 @@ bool sosc::db::init_databases(std::string* error) {
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.BindText(cgc::sha1(_hard_db_sql[id]), 1);
insertMigration.Reset();
insertMigration.BindInt32(id, 1);
insertMigration.BindText(cgc::sha1(local_hash), 2);
insertMigration.NonQuery();
} 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)
*error = "HARD DB: MIGRATION SQL HASH MISMATCH";
_ctx.ready = false;
@ -338,7 +349,7 @@ bool sosc::db::ResultSet::Step() {
else if(result == SQLITE_DONE)
return false;
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) {

View file

@ -42,19 +42,19 @@ void sosc::MasterClientPool::SetupQueries(db::Queries *queries) {
queries->push_back(new db::Query(
"INSERT OR IGNORE INTO `USER_KEYS` "
"(`ID`, `SECRET`) VALUES (?, RANDOMBLOB(128))"
));
, DB_USE_MEMORY));
#define QRY_USER_GET_KEY 6
queries->push_back(new db::Query(
"SELECT `SECRET` FROM `USER_KEYS` "
"WHERE `ID` = ?"
));
, DB_USE_MEMORY));
#define QRY_USER_CHECK_KEY 7
queries->push_back(new db::Query(
"SELECT COUNT(*) FROM `USER_KEYS` "
"WHERE `ID` = ? AND `SECRET` = ?"
));
, DB_USE_MEMORY));
}
/** MASTERCLIENT CODE **/
@ -99,13 +99,13 @@ bool sosc::MasterClient::ProcessLogin(Packet &pck) {
db::ResultSet* results = nullptr;
db::Query* query = this->queries->at(QRY_USER_NAME_EXISTS);
query->Reset();
query->BindText(pck[0], 0);
query->BindText(pck[0], 1);
if(query->ScalarInt32() == 0)
return LoginError(0x101);
query = this->queries->at(QRY_USER_GET_PWD_HASH);
query->Reset();
query->BindText(pck[0], 0);
query->BindText(pck[0], 1);
results = query->GetResults();
results->Step();
@ -115,12 +115,12 @@ bool sosc::MasterClient::ProcessLogin(Packet &pck) {
query = this->queries->at(QRY_USER_GENERATE_KEY);
query->Reset();
query->BindInt64(user_id, 0);
query->BindInt64(user_id, 1);
query->NonQuery();
query = this->queries->at(QRY_USER_GET_KEY);
query->Reset();
query->BindInt64(user_id, 0);
query->BindInt64(user_id, 1);
auto secret = query->ScalarBlob();
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);
query->Reset();
query->BindText(pck[0], 0);
query->BindText(pck[0], 1);
if(query->ScalarInt32() > 0)
return RegistrationError(0x100);
query = this->queries->at(QRY_USER_MAIL_REG_CHECK);
query->Reset();
query->BindText(pck[2], 0);
query->BindText(pck[2], 1);
if(query->ScalarInt32() > 0)
return RegistrationError(0x101);
query = this->queries->at(QRY_USER_REGISTER);
query->Reset();
query->BindText(pck[0], 0);
query->BindText(cgc::bcrypt_hash(pck[1]), 1);
query->BindText(pck[2], 2);
query->BindText(pck[0], 1);
query->BindText(cgc::bcrypt_hash(pck[1]), 2);
query->BindText(pck[2], 3);
query->NonQuery();
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);
query->Reset();
query->BindText(pck[2], 0);
query->BindBlob(pck[3], 1);
query->BindText(pck[2], 1);
query->BindBlob(pck[3], 2);
if(query->ScalarInt32() == 0)
return AuthenticationFailure(packetId, 0x101);
@ -120,11 +120,11 @@ bool sosc::MasterIntra::Authentication(sosc::Packet& pck) {
int limit;
query = this->queries->at(QRY_LICENSE_LIMIT);
query->Reset();
query->BindText(pck[2], 0);
query->BindText(pck[2], 1);
if((limit = query->ScalarInt32()) != 0) {
query = this->queries->at(QRY_LICENSE_ACTIVE_COUNT);
query->Reset();
query->BindText(pck[2], 0);
query->BindText(pck[2], 1);
if(query->ScalarInt32() < limit) {
_ctx.license_check_mtx.unlock();
return AuthenticationFailure(packetId, 0x102);
@ -133,10 +133,10 @@ bool sosc::MasterIntra::Authentication(sosc::Packet& pck) {
query = this->queries->at(QRY_SERVER_LIST_ADD);
query->Reset();
query->BindText(pck[0], 0);
query->BindText(pck[2], 1);
query->BindText(this->sock.GetIpAddress(), 2);
query->BindInt32(net::ntohv<uint16_t>(pck[1]), 3);
query->BindText(pck[0], 1);
query->BindText(pck[2], 2);
query->BindText(this->sock.GetIpAddress(), 3);
query->BindInt32(net::ntohv<uint16_t>(pck[1]), 4);
query->NonQuery();
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);
query->Reset();
query->BindText(this->license, 0);
query->BindText(this->license, 1);
if(query->ScalarInt32() == 0)
return this->NotAuthorized(packetId);
@ -188,8 +188,8 @@ bool sosc::MasterIntra::StatusUpdate(sosc::Packet &pck) {
query = this->queries->at(QRY_SERVER_LIST_MODIFY);
query->Reset();
query->BindInt32(net::ntohv<uint16_t>(pck[0]), 0);
query->BindInt32(net::ntohv<uint16_t>(pck[1]), 1);
query->BindInt32(net::ntohv<uint16_t>(pck[0]), 1);
query->BindInt32(net::ntohv<uint16_t>(pck[1]), 2);
query->BindInt32(this->server_id, 2);
query->NonQuery();
return true;

View file

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

View file

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