diff --git a/.gitignore b/.gitignore index a8aebb8..d640ac9 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ connectionStrings.config .idea/ cmake-build-*/ *.db-journal -scape.db \ No newline at end of file +scape.db +memory.db \ No newline at end of file diff --git a/PROTOCOL.md b/PROTOCOL.md index 3238b6c..6488a67 100644 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -240,15 +240,20 @@ Communication between the master server and clients will be done over a WebSocke Iterated over n (0 ≤ in - 1) - 2 + 2i + 2 + 3i Server Id Packed Unsigned Short - 3 + 2i + 3 + 3i + Server Name + Text + + 4 + 3i User Count Packed Unsigned Short + #### Client to Master [Encrypted] diff --git a/resources/server/config.ini b/resources/server/config.ini index 1b352a1..49eea95 100644 --- a/resources/server/config.ini +++ b/resources/server/config.ini @@ -3,7 +3,7 @@ Run Master = true Master Host = localhost Master Port = 8008 -[Defaults] +[Pool Defaults] ; amount of threads to start with (never close) Initial Count = 3 ; starting limit of clients per thread @@ -30,11 +30,14 @@ Port = 8008 [Slave] Port = 9000 Name = Test Server 1 +Max Users = 100 [Slave] Port = 9001 Name = Test Server 2 +Max Users = 100 [Slave] Port = 9002 -Name = Test Server 3 \ No newline at end of file +Name = Test Server 3 +Max Users = 100 \ No newline at end of file diff --git a/src/server/db/database.cpp b/src/server/db/database.cpp index 3b5f19b..88c4b5b 100644 --- a/src/server/db/database.cpp +++ b/src/server/db/database.cpp @@ -13,7 +13,11 @@ bool sosc::db::init_databases(std::string* error) { return true; _ctx.ready = true; +#ifdef SOSC_DEBUG + sqlite3_open(SOSC_RESC("memory.db").c_str(), &_ctx.mem_db); +#else sqlite3_open(":memory:", &_ctx.mem_db); +#endif for(const auto& query : _mem_db_sql) sqlite3_exec(_ctx.mem_db, query, nullptr, nullptr, nullptr); diff --git a/src/server/hosts/master_client.cpp b/src/server/hosts/master_client.cpp index 91f8651..cbc2af1 100644 --- a/src/server/hosts/master_client.cpp +++ b/src/server/hosts/master_client.cpp @@ -16,7 +16,7 @@ void sosc::MasterClientPool::SetupQueries(db::Queries *queries) { #define QRY_USER_MAIL_REG_CHECK 1 queries->push_back(new db::Query( "SELECT COUNT(*) FROM `USERS` " - "WHERE `USERNAME` = ?" + "WHERE `EMAIL` = ?" )); #define QRY_USER_REGISTER 2 @@ -171,7 +171,7 @@ bool sosc::MasterClient::ProcessRegistration(Packet &pck) { query->BindText(pck[2], 3); query->NonQuery(); - this->sock.Send(Packet(kRegisterResponse, {"\1", 0x000})); + this->sock.Send(Packet(kRegisterResponse, {"\1", HTONUS(0x000)})); return true; } diff --git a/src/server/hosts/slave.cpp b/src/server/hosts/slave.cpp index 5d4caa4..b95c3bb 100644 --- a/src/server/hosts/slave.cpp +++ b/src/server/hosts/slave.cpp @@ -1,5 +1,7 @@ #include "slave.hpp" +/** SLAVE -> CLIENT **/ + sosc::SlaveClient::SlaveClient(const ScapeConnection& client) { this->sock = client; } @@ -13,3 +15,6 @@ bool sosc::SlaveClient::Close(const Packet& message) { this->sock.Send(message); return this->Close(); } + +/** SLAVE -> MASTER **/ + diff --git a/src/server/hosts/slave.hpp b/src/server/hosts/slave.hpp index fbe15d0..aaaf592 100644 --- a/src/server/hosts/slave.hpp +++ b/src/server/hosts/slave.hpp @@ -1,6 +1,7 @@ #ifndef SOSC_HOST_SLAVE_H #define SOSC_HOST_SLAVE_H +#include "sock/intrasock.hpp" #include "sock/scapesock.hpp" #include "sock/pool.hpp" #include "ctx/slave.hpp" @@ -32,6 +33,20 @@ protected: return true; } }; + +/** SLAVE -> MASTER **/ + +class SlaveMaster { +public: + SlaveMaster(); + + + + bool Close(); + bool Close(const Packet& message); +private: + IntraClient sock; +}; } #endif diff --git a/src/server/main.cpp b/src/server/main.cpp index e564e29..b27015d 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -74,7 +74,7 @@ int main(int argc, char **argv) { ini::Field("master host", ini::Field::STRING), ini::Field("master port", ini::Field::UINT32), }), - ini::Rule("defaults", true, false, { + ini::Rule("pool defaults", true, false, { ini::Field("initial count", ini::Field::UINT32), ini::Field("initial size", ini::Field::UINT32), ini::Field("size growth", ini::Field::UINT32), @@ -93,6 +93,7 @@ int main(int argc, char **argv) { ini::Rule("slave", false, true, { ini::Field("port", ini::Field::UINT32), ini::Field("name", ini::Field::STRING), + ini::Field("max users", ini::Field::STRING), }) }); } catch(const std::exception& e) { @@ -101,7 +102,7 @@ int main(int argc, char **argv) { } poolinfo_t info; - configure_poolinfo(&_ctx.default_info, (*config)["defaults"][0]); + configure_poolinfo(&_ctx.default_info, (*config)["pool defaults"][0]); if((*config)["general"]["run master"]) { if(!config->HasSection("master to client") || @@ -152,7 +153,7 @@ int main(int argc, char **argv) { } } - std::cout << "Server threads started. Type STOP to cancel." << std::endl; + std::cout << "Server threads started. Type STOP to quit." << std::endl; std::string input; while(true) { @@ -181,7 +182,7 @@ bool master_intra_start(uint16_t port, const sosc::poolinfo_t& info) { _ctx.master_intra->thread = std::thread([&] { sosc::IntraClient client; - while (_ctx.master_intra->server.Accept(&client)) + while(_ctx.master_intra->server.Accept(&client)) _ctx.master_intra->pool.AddClient(new sosc::MasterIntra(client)); }); @@ -213,7 +214,7 @@ bool slave_start(uint16_t port, const sosc::poolinfo_t& info, slave_ctx* ctx) { ctx->thread = std::thread([&] { sosc::ScapeConnection client; - while (ctx->server.Accept(&client)) + while(ctx->server.Accept(&client)) ctx->pool.AddClient(new sosc::SlaveClient(client)); }); diff --git a/src/web/index.html b/src/web/index.html index e706606..a7bb032 100644 --- a/src/web/index.html +++ b/src/web/index.html @@ -46,8 +46,29 @@ + \ No newline at end of file diff --git a/src/web/script.js b/src/web/script.js index 20a48d5..ee2b9dd 100644 --- a/src/web/script.js +++ b/src/web/script.js @@ -1,5 +1,6 @@ let unloading = false; let sections = {}; +let key = null; let ws; const MAHOU = [0xB0, 0x0B]; @@ -28,21 +29,9 @@ function attempt_login() { x => ["submit", "button", "text", "password"].indexOf(x.type) !== -1 ); - for_each(lock_fields, x => x.disabled = true); - ws.send(pack( - kClientToMaster.LoginRequest, [ - document.getElementById("login-user").value, - document.getElementById("login-pwd").value - ] - )); - receive_callbacks[kMasterToClient.LoginResponse] = pck => { - console.log(pck.regions); - if(pck.regions[0][0] === 0x0) { - console.log(pck.regions[1].unpackUint16()); - - let error_text = "Login failed"; + let error_text = "Login failed."; switch(pck.regions[1].unpackUint16()) { case 0x100: error_text = "Too many attempts. Try again later."; @@ -58,11 +47,20 @@ function attempt_login() { error.innerHTML = error_text; error.classList.remove("hidden"); } else { - //show_section() + key = pck.regions[1]; + show_section("servers"); } for_each(lock_fields, x => x.disabled = false); }; + + for_each(lock_fields, x => x.disabled = true); + ws.send(pack( + kClientToMaster.LoginRequest, [ + document.getElementById("login-user").value, + document.getElementById("login-pwd").value + ] + )); } function attempt_register() { @@ -82,19 +80,100 @@ function attempt_register() { }); if(fields["pwd"] !== fields["conf-pwd"]) { - error.innerHTML = ""; + error.innerHTML = "Confirmation password does not match password."; + error.classList.remove("hidden"); + return; } + receive_callbacks[kMasterToClient.RegisterResponse] = pck => { + if(pck.regions[0][0] === 0x0) { + let error_text = "Registration failed."; + switch(pck.regions[1].unpackUint16()) { + case 0x100: + error_text = "Username is taken."; + break; + case 0x101: + error_text = "Username is illegal."; + break; + case 0x110: + error_text = "Email is taken."; + break; + case 0x111: + error_text = "Email isn't properly formed."; + break; + case 0x120: + error_text = "Password is too weak, just like you."; + break; + } + + error.innerHTML = error_text; + error.classList.remove("hidden"); + } else { + alert("Registration was successful."); + show_section("servers"); + refresh_list(); + } + + for_each(lock_fields, x => x.disabled = false); + }; for_each(lock_fields, x => x.disabled = true); ws.send(pack( - kClientToMaster.LoginRequest, [ - document.getElementById("login-user").value, - document.getElementById("login-pwd").value + kClientToMaster.RegisterRequest, [ + fields["user"], + fields["pwd"], + fields["email"] ] )); } +function refresh_list() { + if(key === null) + return; + + let table = document.getElementById("servers-list"); + let button = document.getElementById("servers-refresh"); + + button.disabled = true; + while(table.rows.length > 1) + table.deleteRow(-1); + + receive_callbacks[kMasterToClient.ServerList] = pck => { + let count = pck[0].unpackUint16(); + for(let i = 0; i < count; ++i) { + let id = pck[2 + 3*i].unpackUint16(); + let row = table.insertRow(); + + let cell = row.insertCell(); + let link = document.createElement("a"); + link.setAttribute("href", "javascript: void(0);"); + link.text = "Join"; + link.tag = id; + link.onclick = e => join_server(id); + cell.appendChild(cell); + + cell = row.insertCell(); + cell.innerText = id; + cell = row.insertCell(); + cell.innerText = pck[3 + 3*i]; + cell = row.insertCell(); + cell.innerText = pck[4 + 3*i]; + } + + button.disabled = false; + }; + + ws.send(pack(kClientToMaster.ServerListRequest, [])); +} + +function log_out() { + +} + +function join_server(id) { + +} + function show_section(id) { clear_inputs(); clear_errors(); diff --git a/src/web/style.css b/src/web/style.css index c764d4e..c0a355b 100644 --- a/src/web/style.css +++ b/src/web/style.css @@ -1,11 +1,21 @@ +:root { + /**/ + --foreground-color: #000; + --background-color: #fff; + /**/ + + /* + --foreground-color: #fff; + --background-color: #000; + /**/ +} + body { padding-top: 36px; font-family: monospace; text-align: center; - /*background: #000; - color: #fff;*/ - background: #fff; - color: #000; + background: var(--background-color); + color: var(--foreground-color); } .hidden { @@ -28,3 +38,13 @@ body { font-size: 1.1em; max-width: 250px; } + +.section > table { + font-size: 1.1em; + margin: 15px auto; + border-collapse: collapse; +} + +.section > table td, .section > table th { + border: 1px solid var(--foreground-color); +} \ No newline at end of file