[Add] Completed the persistance layer.
This commit is contained in:
parent
fce3b3aad6
commit
44ca427c0e
@ -2,6 +2,7 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "command_processor.h"
|
||||
#include "db/database_manager.h"
|
||||
#include "vfs.h"
|
||||
#include "lua_api.h"
|
||||
#include "lua_processor.h"
|
||||
@ -9,7 +10,9 @@
|
||||
#include "machine.h"
|
||||
|
||||
CommandProcessor::CommandProcessor(Machine* home_machine,
|
||||
std::map<std::string, Machine*>& world_machines) :
|
||||
std::map<std::string, Machine*>& world_machines,
|
||||
DatabaseManager* db_manager) :
|
||||
_db_manager(db_manager),
|
||||
_home_machine(home_machine),
|
||||
_session_machine(home_machine),
|
||||
_world_machines(world_machines) {
|
||||
|
||||
@ -4,12 +4,14 @@
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "db/database_manager.h"
|
||||
#include "machine.h"
|
||||
#include "vfs.h"
|
||||
|
||||
class CommandProcessor {
|
||||
public:
|
||||
CommandProcessor(Machine* home_machine, std::map<std::string, Machine*>& world_machines);
|
||||
CommandProcessor(Machine* home_machine, std::map<std::string, Machine*>& world_machines,
|
||||
DatabaseManager* db_manager);
|
||||
~CommandProcessor(void);
|
||||
|
||||
std::string process_command(const std::string& command);
|
||||
@ -28,6 +30,7 @@ public:
|
||||
void ensure_vfs_is_writable(void);
|
||||
|
||||
private:
|
||||
DatabaseManager* _db_manager;
|
||||
Machine* _home_machine;
|
||||
Machine* _session_machine;
|
||||
vfs_node* _current_dir;
|
||||
|
||||
@ -13,19 +13,69 @@ void DatabaseManager::init(void) {
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||
"username TEXT NOT NULL UNIQUE,"
|
||||
"password TEXT NOT NULL,"
|
||||
"hostname TEXT NOT NULL"
|
||||
"hostname TEXT NOT NULL,"
|
||||
"home_machine_id INTEGER"
|
||||
");";
|
||||
|
||||
_db << "CREATE TABLE IF NOT EXISTS machines ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||
"owner_id INTEGER,"
|
||||
"hostname TEXT NOT NULL,"
|
||||
"ip_address TEXT NOT NULL UNIQUE"
|
||||
");";
|
||||
|
||||
_db << "CREATE TABLE IF NOT EXISTS vfs_nodes ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||
"machine_id INTEGER NOT NULL,"
|
||||
"parent_id INTEGER,"
|
||||
"name TEXT NOT NULL,"
|
||||
"type INTEGER NOT NULL,"
|
||||
"content TEXT"
|
||||
");";
|
||||
}
|
||||
|
||||
bool DatabaseManager::create_player(const std::string& username, const std::string& password,
|
||||
const std::string& hostname) {
|
||||
long long player_id = 0;
|
||||
long long machine_id = 0;
|
||||
|
||||
try {
|
||||
_db << "BEGIN;";
|
||||
|
||||
/* Create the player. */
|
||||
_db << "INSERT INTO players (username, password, hostname) VALUES (?, ?, ?);"
|
||||
<< username
|
||||
<< password
|
||||
<< hostname;
|
||||
player_id = _db.last_insert_rowid();
|
||||
|
||||
/* 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();
|
||||
|
||||
/* Link player to their new machine. */
|
||||
_db << "UPDATE players SET home_machine_id = ? WHERE id = ?;"
|
||||
<< machine_id << player_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();
|
||||
|
||||
/* Create default subdirs. */
|
||||
_db << "INSERT INTO vfs_nodes (machine_id, parent_id, name, type) VALUES (?, ?, ?, 1);"
|
||||
<< machine_id << root_id << "bin";
|
||||
_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";
|
||||
|
||||
_db << "COMMIT";
|
||||
} catch(const std::exception& e) {
|
||||
/* Fail if the username exists. */
|
||||
_db << "ROLLBACK;"; /* Ensure atomicity. */
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -40,3 +90,11 @@ bool DatabaseManager::auth_player(const std::string& username, const std::string
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ public:
|
||||
/* Return true if creds are valid. */
|
||||
bool auth_player(const std::string& username, const std::string& password);
|
||||
|
||||
private:
|
||||
long long get_player_home_machine_id(const std::string& username);
|
||||
|
||||
sqlite::database _db;
|
||||
};
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#include "db/database_manager.h"
|
||||
#include "machine_manager.h"
|
||||
#include "machine.h"
|
||||
#include "vfs.h"
|
||||
@ -90,3 +92,53 @@ Machine* MachineManager::create_machine(uint32_t id, const std::string& hostname
|
||||
|
||||
return new_machine;
|
||||
}
|
||||
|
||||
/* Recursively build the VFS tree from database nodes. */
|
||||
void build_tree(vfs_node* parent, const std::map<long long, vfs_node*>& nodes) {
|
||||
for(auto const& [id, node] : nodes) {
|
||||
/* Inefficient but safe. Would be better to group nodes by parent_id. */
|
||||
if(node->parent_id == parent->id) {
|
||||
parent->children[node->name] = node;
|
||||
node->parent = parent;
|
||||
if(node->type == DIR_NODE) {
|
||||
build_tree(node, nodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Machine* MachineManager::load_machine(long long machine_id) {
|
||||
DatabaseManager db("bettola.db"); /* Assumes multiplayer for now. */
|
||||
|
||||
std::string hostname;
|
||||
|
||||
db._db << "SELECT hostname FROM machines WHERE id = ?;"
|
||||
<< machine_id
|
||||
>> hostname;
|
||||
|
||||
Machine* machine = new Machine(machine_id, hostname);
|
||||
|
||||
/* Load all VFS nodes for this machine from the database. */
|
||||
std::map<long long, vfs_node*> nodes;
|
||||
vfs_node* root = nullptr;
|
||||
|
||||
db._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_node(name, (vfs_node_type)type, nullptr);
|
||||
node->id = id;
|
||||
node->parent_id = parent_id; /* Store temp id for tree building. */
|
||||
node->content = content;
|
||||
nodes[id] = node;
|
||||
if(name == "/") {
|
||||
root = node;
|
||||
}
|
||||
};
|
||||
|
||||
if(root) {
|
||||
build_tree(root, nodes);
|
||||
machine->vfs_root = root;
|
||||
}
|
||||
return machine;
|
||||
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@ public:
|
||||
|
||||
Machine* create_machine(uint32_t id, const std::string& hostname,
|
||||
const std::string& system_type);
|
||||
Machine* load_machine(long long machine_id);
|
||||
private:
|
||||
vfs_node* _vfs_template_root;
|
||||
};
|
||||
|
||||
@ -14,6 +14,8 @@ enum vfs_node_type {
|
||||
};
|
||||
|
||||
struct vfs_node {
|
||||
long long id;
|
||||
long long parent_id; /* Used durin DB loading only. */
|
||||
std::string name;
|
||||
vfs_node_type type;
|
||||
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include "network_manager.h"
|
||||
#include "db/database_manager.h"
|
||||
@ -78,7 +77,8 @@ void NetworkManager::start_accept(void) {
|
||||
uint32_t player_id = _next_player_id++;
|
||||
Machine* player_machine = _machine_manager.create_machine(player_id, "player.home",
|
||||
"player");
|
||||
auto new_player = std::make_unique<Player>(player_id, player_machine, _world_machines);
|
||||
auto new_player = std::make_unique<Player>(player_id, player_machine,
|
||||
_world_machines, _db_manager.get());
|
||||
Player* new_player_ptr = new_player.get();
|
||||
_players[player_id] = std::move(new_player);
|
||||
new_connection->set_id(player_id);
|
||||
@ -130,10 +130,11 @@ void NetworkManager::on_message(std::shared_ptr<net::TcpConnection> connection,
|
||||
auto parts = split_message(payload, "::");
|
||||
if(parts.size() == 3) {
|
||||
if(_db_manager->create_player(parts[0], parts[1], parts[2])) {
|
||||
/*
|
||||
* TODO: When creating a player, also create their machine and save it.
|
||||
* for now, they will juse use a temp machine on auth.
|
||||
*/
|
||||
long long machine_id = _db_manager->get_player_home_machine_id(parts[0]);
|
||||
Machine* home_machine = _machine_manager.load_machine(machine_id);
|
||||
delete player->cmd_processor; /* Delete old command processor. */
|
||||
player->cmd_processor = new CommandProcessor(home_machine, _world_machines,
|
||||
_db_manager.get());
|
||||
player->state = PlayerState::ACTIVE;
|
||||
connection->send("C_ACC_SUCCESS");
|
||||
/* send initial prompt. */
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
#include "player.h"
|
||||
#include "command_processor.h"
|
||||
#include "db/database_manager.h"
|
||||
#include "machine.h"
|
||||
|
||||
Player::Player(uint32_t new_id, Machine* home_machine,
|
||||
std::map<std::string, Machine*>& world_machines) :
|
||||
std::map<std::string, Machine*>& world_machines, DatabaseManager* db_manager) :
|
||||
id(new_id),
|
||||
state(PlayerState::AUTHENTICATING) {
|
||||
|
||||
cmd_processor = new CommandProcessor(home_machine, world_machines);
|
||||
cmd_processor = new CommandProcessor(home_machine, world_machines, db_manager);
|
||||
}
|
||||
|
||||
Player::~Player(void) {
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "db/database_manager.h"
|
||||
#include "command_processor.h"
|
||||
#include "machine.h"
|
||||
|
||||
@ -14,7 +15,8 @@ enum class PlayerState {
|
||||
|
||||
class Player {
|
||||
public:
|
||||
Player(uint32_t id, Machine* home_machine, std::map<std::string, Machine*>& world_machines);
|
||||
Player(uint32_t id, Machine* home_machine, std::map<std::string,
|
||||
Machine*>& world_machines, DatabaseManager* db_manager);
|
||||
~Player(void);
|
||||
|
||||
uint32_t id;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user