From 2a50d937ea8fa9910d670df67f8de51649424f70 Mon Sep 17 00:00:00 2001 From: Ritchie Cunningham Date: Fri, 10 Oct 2025 20:17:20 +0100 Subject: [PATCH] [Refactor] Abstract database logic with Repository classes. --- common/src/db/database_manager.cpp | 65 ++++++++-------------------- common/src/db/database_manager.h | 21 ++++++--- common/src/db/machine_repository.cpp | 32 ++++++++++++++ common/src/db/machine_repository.h | 26 +++++++++++ common/src/db/player_repository.cpp | 34 +++++++++++++++ common/src/db/player_repository.h | 19 ++++++++ common/src/db/service_repository.cpp | 19 ++++++++ common/src/db/service_repository.h | 17 ++++++++ common/src/db/vfs_repository.cpp | 35 +++++++++++++++ common/src/db/vfs_repository.h | 20 +++++++++ common/src/machine_manager.cpp | 31 +++++-------- server/src/network_manager.cpp | 46 +++++++------------- 12 files changed, 260 insertions(+), 105 deletions(-) create mode 100644 common/src/db/machine_repository.cpp create mode 100644 common/src/db/machine_repository.h create mode 100644 common/src/db/player_repository.cpp create mode 100644 common/src/db/player_repository.h create mode 100644 common/src/db/service_repository.cpp create mode 100644 common/src/db/service_repository.h create mode 100644 common/src/db/vfs_repository.cpp create mode 100644 common/src/db/vfs_repository.h diff --git a/common/src/db/database_manager.cpp b/common/src/db/database_manager.cpp index 80158d2..f5c73b2 100644 --- a/common/src/db/database_manager.cpp +++ b/common/src/db/database_manager.cpp @@ -1,8 +1,13 @@ #include "database_manager.h" +#include #include "vfs.h" -DatabaseManager::DatabaseManager(const std::string& db_path) : _db(db_path) { - /* db is opened in the construtor's init list. */ +DatabaseManager::DatabaseManager(const std::string& db_path) : + _db(db_path) { + _player_repository = std::make_unique(_db); + _machine_repository = std::make_unique(_db); + _service_repository = std::make_unique(_db); + _vfs_repository = std::make_unique(_db); } DatabaseManager::~DatabaseManager(void) { @@ -49,51 +54,33 @@ bool DatabaseManager::create_player(const std::string& username, const std::stri try { _db << "BEGIN;"; - /* Create the player. */ - _db << "INSERT INTO players (username, password, hostname) VALUES (?, ?, ?);" - << username - << password - << hostname; - player_id = _db.last_insert_rowid(); + player_id = _player_repository->create(username, password, hostname); /* Create the home machine. */ /* TODO: Implement real IP allication. */ std::string ip_address = "192.168.1." + std::to_string(player_id); - _db << "INSERT INTO machines (owner_id, hostname, ip_address) VALUES (?, ?, ?);" - << player_id << hostname << ip_address; - machine_id = _db.last_insert_rowid(); + machine_id = _machine_repository->create(player_id, hostname, ip_address); - /* Link player to their new machine. */ - _db << "UPDATE players SET home_machine_id = ? WHERE id = ?;" - << machine_id << player_id; + _player_repository->set_home_machine_id(player_id, machine_id); /* Create the root dir for the new machine's VFS. */ - _db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type) VALUES(?, NULL, ?, 1);" - << machine_id << "/"; - long long root_id = _db.last_insert_rowid(); + long long root_id = _vfs_repository->create_node(machine_id, nullptr, "/", DIR_NODE); /* Create default subdirs. */ - _db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type) VALUES (?, ?, ?, 1);" - << machine_id << root_id << "home"; - _db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type) VALUES (?, ?, ?, 1);" - << machine_id << root_id << "etc"; + _vfs_repository->create_node(machine_id, &root_id, "home", DIR_NODE); + _vfs_repository->create_node(machine_id, &root_id, "etc", DIR_NODE); - /* Create /bing and get it's ID */ - _db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type) VALUES(?, ?, ?, 1);" - << machine_id << root_id << "bin"; - long long bin_id = _db.last_insert_rowid(); + /* Create /bin and get it's ID */ + long long bin_id = _vfs_repository->create_node(machine_id, &root_id, "bin", DIR_NODE); /* Copy scripts from template into new machine's /bin */ vfs_node* template_bin = vfs_template->children["bin"]; for(auto const& [name, node] : template_bin->children) { - _db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type, content) " - "VALUES (?, ?, ?, ?, ?);" - << machine_id << bin_id << name << FILE_NODE <content; + _vfs_repository->create_node(machine_id, &bin_id, name, FILE_NODE, node->content); } /* Add default SSH service. */ - _db << "INSERT INTO services (machine_id, port, name) VALUES (?, ?, ?);" - << machine_id << 22 << "SSH"; + _service_repository->create(machine_id, 22, "SSH"); _db << "COMMIT"; } catch(const std::exception& e) { @@ -102,21 +89,3 @@ bool DatabaseManager::create_player(const std::string& username, const std::stri } return true; } - -bool DatabaseManager::auth_player(const std::string& username, const std::string& password) { - bool authed = false; - _db << "SELECT id FROM players WHERE username = ? AND password = ?;" - << username - << password - >> [&](long long id) { authed = true; }; - - return authed; -} - -long long DatabaseManager::get_player_home_machine_id(const std::string& username) { - long long machine_id = -1; /* Return -1 if not found. */ - _db << "SELECT home_machine_id FROM players WHERE username = ?;" - << username - >> machine_id; - return machine_id; -} diff --git a/common/src/db/database_manager.h b/common/src/db/database_manager.h index 9961438..e483bff 100644 --- a/common/src/db/database_manager.h +++ b/common/src/db/database_manager.h @@ -1,9 +1,14 @@ #pragma once #include +#include +#include "service_repository.h" +#include "player_repository.h" +#include "machine_repository.h" +#include "vfs_repository.h" +#include "sqlite_modern_cpp.h" #include "vfs.h" -#include "db.h" class DatabaseManager { public: @@ -16,10 +21,16 @@ public: bool create_player(const std::string& username, const std::string& password, const std::string& hostname, vfs_node* vfs_template); - /* Return true if creds are valid. */ - bool auth_player(const std::string& username, const std::string& password); - - long long get_player_home_machine_id(const std::string& username); + PlayerRepository& players(void) { return *_player_repository; } + MachineRepository& machines(void) { return *_machine_repository; } + ServiceRepository& services(void) { return *_service_repository; } + VFSRepository& vfs(void) { return *_vfs_repository; } sqlite::database _db; + +private: + std::unique_ptr _player_repository; + std::unique_ptr _machine_repository; + std::unique_ptr _service_repository; + std::unique_ptr _vfs_repository; }; diff --git a/common/src/db/machine_repository.cpp b/common/src/db/machine_repository.cpp new file mode 100644 index 0000000..f504f99 --- /dev/null +++ b/common/src/db/machine_repository.cpp @@ -0,0 +1,32 @@ +#include "machine_repository.h" +#include "sqlite_modern_cpp.h" + +MachineRepository::MachineRepository(sqlite::database& db) : _db(db) {} + +long long MachineRepository::create(std::optional owner_id, + const std::string& hostname, + const std::string& ip_address) { + if(owner_id.has_value()) { + _db << "INSERT INTO machines (owner_id, hostname, ip_address) VALUES(?, ?, ?);" + << owner_id.value() << hostname << ip_address; + } else { + _db << "INSERT INTO machines (owner_id, hostname, ip_address) VALUES (NULL, ?, ?);" + << hostname << ip_address; + } + return _db.last_insert_rowid(); +} + +int MachineRepository::get_npc_count(void) { + int count = 0; + _db << "SELECT count(*) FROM machines WHERE owner_id IS NULL;" >> count; + return count; +} + +std::vector MachineRepository::get_all_npcs(void) { + std::vector machines; + _db << "SELECT id, ip_address FROM machines WHERE owner_id IS NULL;" + >> [&](long long id, std::string ip_address) { + machines.push_back({id, ip_address}); + }; + return machines; +} diff --git a/common/src/db/machine_repository.h b/common/src/db/machine_repository.h new file mode 100644 index 0000000..1303ee5 --- /dev/null +++ b/common/src/db/machine_repository.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include +#include "sqlite_modern_cpp.h" + +/* Struct to hold machine data. */ +struct MachineData { + long long id; + std::string ip_address; +}; + +class MachineRepository { +public: + MachineRepository(sqlite::database& db); + + long long create(std::optional owner_id, const std::string& hostname, + const std::string& ip_address); + int get_npc_count(void); + std::vector get_all_npcs(void); + +private: + sqlite::database& _db; +}; + diff --git a/common/src/db/player_repository.cpp b/common/src/db/player_repository.cpp new file mode 100644 index 0000000..6bb6dc0 --- /dev/null +++ b/common/src/db/player_repository.cpp @@ -0,0 +1,34 @@ +#include "player_repository.h" + +PlayerRepository::PlayerRepository(sqlite::database& db) : _db(db) {} + +long long PlayerRepository::create(const std::string& username, const std::string& password, + const std::string& hostname) { + _db << "INSERT INTO players (username, password, hostname) VALUES (?, ?, ?);" + << username + << password + << hostname; + return _db.last_insert_rowid(); +} + +bool PlayerRepository::authenticate(const std::string& username, const std::string& password) { + bool authed = false; + _db << "SELECT id FROM players WHERE username = ? AND password = ?;" + << username + << password + >> [&](long long id) {authed = true;}; + return authed; +} + +long long PlayerRepository::get_home_machine_id(const std::string& username) { + long long machine_id = -1; + _db << "SELECT home_machine_id FROM players WHERE username = ?;" + << username + >> machine_id; + return machine_id; +} + +void PlayerRepository::set_home_machine_id(long long player_id, long long machine_id) { + _db << "UPDATE players SET home_machine_id = ? WHERE id = ?;" + << machine_id << player_id; +} diff --git a/common/src/db/player_repository.h b/common/src/db/player_repository.h new file mode 100644 index 0000000..648599d --- /dev/null +++ b/common/src/db/player_repository.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include "sqlite_modern_cpp.h" + +class PlayerRepository { +public: + PlayerRepository(sqlite::database& db); + + long long create(const std::string& username, const std::string& password, + const std::string& hostname); + bool authenticate(const std::string& username, const std::string& password); + long long get_home_machine_id(const std::string& username); + void set_home_machine_id(long long player_id, long long machine_id); + +private: + sqlite::database& _db; +}; diff --git a/common/src/db/service_repository.cpp b/common/src/db/service_repository.cpp new file mode 100644 index 0000000..58a9ff1 --- /dev/null +++ b/common/src/db/service_repository.cpp @@ -0,0 +1,19 @@ +#include "service_repository.h" +#include "sqlite_modern_cpp.h" + +ServiceRepository::ServiceRepository(sqlite::database& db) : _db(db) {} + +void ServiceRepository::create(long long machine_id, int port, const std::string& name) { + _db << "INSERT INTO services (machine_id, port, name) VALUES (?, ?, ?);" + << machine_id << port << name; +} + +std::map ServiceRepository::get_for_machine(long long machine_id) { + std::map services; + _db << "SELECT port, name FROM services WHERE machine_id = ?;" + << machine_id + >> [&](int port, std::string name) { + services[port] = name; + }; + return services; +} diff --git a/common/src/db/service_repository.h b/common/src/db/service_repository.h new file mode 100644 index 0000000..d999adc --- /dev/null +++ b/common/src/db/service_repository.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +#include "sqlite_modern_cpp.h" + +class ServiceRepository { +public: + ServiceRepository(sqlite::database& db); + + void create(long long machine_id, int port, const std::string& name); + std::map get_for_machine(long long machine_id); + +private: + sqlite::database& _db; +}; diff --git a/common/src/db/vfs_repository.cpp b/common/src/db/vfs_repository.cpp new file mode 100644 index 0000000..7f90658 --- /dev/null +++ b/common/src/db/vfs_repository.cpp @@ -0,0 +1,35 @@ +#include "vfs_repository.h" + +VFSRepository::VFSRepository(sqlite::database& db) : _db(db) {} + +long long VFSRepository::create_node(long long machine_id, long long* parent_id, + const std::string& name, vfs_node_type type, + const std::string& content) { + if(parent_id) { + _db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type, content) " + "VALUES (?, ?, ?, ?, ?);" + << machine_id << *parent_id << name << type << content; + } else { + _db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type, content) " + "VALUES (?, NULL, ?, ?, ?);" + << machine_id << name << type << content; + } + return _db.last_insert_rowid(); +} + +std::vector VFSRepository::get_nodes_for_machine(long long machine_id) { + std::vector nodes; + _db << "SELECT id, parent_id, name, type, content FROM vfs_nodes WHERE machine_id = ?;" + << machine_id + >> [&](long long id, long long parent_id, std::string name, int type, std::string content) { + vfs_node* node = new vfs_node(); + node->id = id; + node->parent_id = parent_id; + node->name = name; + node->type = (vfs_node_type) type; + node->content = content; + + nodes.push_back(node); + }; + return nodes; +} diff --git a/common/src/db/vfs_repository.h b/common/src/db/vfs_repository.h new file mode 100644 index 0000000..2a80608 --- /dev/null +++ b/common/src/db/vfs_repository.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +#include "vfs.h" +#include "sqlite_modern_cpp.h" + +class VFSRepository { +public: + VFSRepository(sqlite::database& db); + + long long create_node(long long machine_id, long long* parent_id, + const std::string& name, vfs_node_type type, + const std::string& content = ""); + std::vector get_nodes_for_machine(long long machine_id); + +private: + sqlite::database& _db; +}; diff --git a/common/src/machine_manager.cpp b/common/src/machine_manager.cpp index 78f088a..e9db8c9 100644 --- a/common/src/machine_manager.cpp +++ b/common/src/machine_manager.cpp @@ -107,32 +107,21 @@ Machine* MachineManager::load_machine(long long machine_id, DatabaseManager* db_ Machine* machine = new Machine(machine_id, hostname); /* Load all VFS nodes for this machine from the database. */ - std::map nodes; + std::map node_map; vfs_node* root = nullptr; - db_manager->_db << "SELECT id, parent_id, name, type, content FROM vfs_nodes WHERE machine_id = ?;" - << machine_id - >> [&](long long id, long long parent_id, std::string name, int type, std::string content) { - vfs_node* node = new vfs_node(); - node->id = id; - node->parent_id = parent_id; /* Store temp id for tree building. */ - node->name = name; - node->type = (vfs_node_type)type; - node->content = content; - nodes[id] = node; - if(name == "/") { - root = node; - } - }; + auto nodes = db_manager->vfs().get_nodes_for_machine(machine_id); + for(vfs_node* node : nodes) { + node_map[node->id] = node; + if(node->name == "/") { + root = node; + } + } - db_manager->_db << "SELECT port, name FROM services WHERE machine_id = ?;" - << machine_id - >> [&](int port, std::string name) { - machine->services[port] = name; - }; + machine->services = _db_manager->services().get_for_machine(machine_id); if(root) { - build_tree(root, nodes); + build_tree(root, node_map); machine->vfs_root = root; } return machine; diff --git a/server/src/network_manager.cpp b/server/src/network_manager.cpp index 3156ee7..71e6944 100644 --- a/server/src/network_manager.cpp +++ b/server/src/network_manager.cpp @@ -23,10 +23,11 @@ NetworkManager::NetworkManager(const std::string& db_path) : _seed_npc_machines(); /* Load NPC machines from the database. */ - _db_manager->_db << "SELECT id, ip_address FROM machines WHERE owner_id IS NULL;" - >> [&](long long id, std::string ip_address) { - _world_machines[ip_address] = _machine_manager.load_machine(id, _db_manager.get()); - }; + auto npc_machines = _db_manager->machines().get_all_npcs(); + for(const auto& machine_data : npc_machines) { + _world_machines[machine_data.ip_address] = + _machine_manager.load_machine(machine_data.id, _db_manager.get()); + } fprintf(stderr, "Created world with %zu networks\n", _world_machines.size()); } @@ -133,7 +134,7 @@ void NetworkManager::on_message(std::shared_ptr connection, if(parts.size() == 3) { if(_db_manager->create_player(parts[0], parts[1], parts[2], _machine_manager.get_vfs_template())) { - long long machine_id = _db_manager->get_player_home_machine_id(parts[0]); + long long machine_id = _db_manager->players().get_home_machine_id(parts[0]); Machine* home_machine = _machine_manager.load_machine(machine_id, _db_manager.get()); delete player->cmd_processor; /* Delete old command processor. */ player->cmd_processor = new CommandProcessor(home_machine, _world_machines, @@ -152,8 +153,8 @@ void NetworkManager::on_message(std::shared_ptr connection, std::string payload = message.substr(7); auto parts = split_message(payload, "::"); if(parts.size() == 2) { - if(_db_manager->auth_player(parts[0], parts[1])) { - long long machine_id = _db_manager->get_player_home_machine_id(parts[0]); + if(_db_manager->players().authenticate(parts[0], parts[1])) { + long long machine_id = _db_manager->players().get_home_machine_id(parts[0]); printf("DEBUG: Loading machine %lld for player %s\n", machine_id, parts[0].c_str()); Machine* home_machine = _machine_manager.load_machine(machine_id, _db_manager.get()); delete player->cmd_processor; /* Delete old command processor. */ @@ -226,8 +227,7 @@ void NetworkManager::on_disconnect(std::shared_ptr connectio } void NetworkManager::_seed_npc_machines(void) { - int npc_count = 0; - _db_manager->_db << "SELECT count(*) FROM machines WHERE owner_id IS NULL;" >> npc_count; + int npc_count = _db_manager->machines().get_npc_count(); if(npc_count > 0) { return; /* NPC already in db. */ @@ -248,38 +248,22 @@ void NetworkManager::_seed_npc_machines(void) { try { for(const auto& def : npc_defs) { - _db_manager->_db << "INSERT INTO machines (hostname, ip_address) " - "VALUES(?, ?);" - << def.hostname << def.ip; - long long machine_id = _db_manager->_db.last_insert_rowid(); + long long machine_id = _db_manager->machines().create({}, def.hostname, def.ip); /* Create a basic VFS for the NPC machines. */ - _db_manager->_db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type) " - "VALUES (?, NULL, ?, 1);" - << machine_id << "/"; - long long root_id = _db_manager->_db.last_insert_rowid(); + long long root_id = _db_manager->vfs().create_node(machine_id, nullptr, "/", DIR_NODE); - _db_manager->_db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type) " - "VALUES (?, ?, ?, 1);" - << machine_id << root_id << "etc"; - long long etc_id = _db_manager->_db.last_insert_rowid(); + _db_manager->vfs().create_node(machine_id, &root_id, "etc", DIR_NODE); - _db_manager->_db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type) " - "VALUES (?, ?, ?, 1);" - << machine_id << root_id << "bin"; - long long bin_id = _db_manager->_db.last_insert_rowid(); + long long bin_id = _db_manager->vfs().create_node(machine_id, &root_id, "bin", DIR_NODE); vfs_node* template_bin = _machine_manager.get_vfs_template()->children["bin"]; for(auto const& [name, node] : template_bin->children) { - _db_manager->_db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type, content) " - "VALUES(?, ?, ?, ?, ?);" - << machine_id << bin_id << name << FILE_NODE << node->content; + _db_manager->vfs().create_node(machine_id, &bin_id, name, FILE_NODE, node->content); } for(const auto& service : def.services) { - _db_manager->_db << "INSERT INTO services (machine_id, port, name) " - "VALUES (?, ?, ?);" - << machine_id << service.first << service.second; + _db_manager->services().create(machine_id, service.first, service.second); } } } catch(const std::exception& e) {