this is the greatest and best commit in the world ...
... tribute
This commit is contained in:
parent
6ed3adfb87
commit
28b4ace8b8
8 changed files with 112 additions and 87 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -6,4 +6,5 @@ connectionStrings.config
|
|||
.kdev4/
|
||||
.idea/
|
||||
cmake-build-*/
|
||||
*.db-journal
|
||||
*.db-journal
|
||||
scape.db
|
|
@ -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
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
|
@ -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}));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue