[Add] Completed the persistance layer.
This commit is contained in:
parent
fce3b3aad6
commit
44ca427c0e
@ -2,6 +2,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "command_processor.h"
|
#include "command_processor.h"
|
||||||
|
#include "db/database_manager.h"
|
||||||
#include "vfs.h"
|
#include "vfs.h"
|
||||||
#include "lua_api.h"
|
#include "lua_api.h"
|
||||||
#include "lua_processor.h"
|
#include "lua_processor.h"
|
||||||
@ -9,7 +10,9 @@
|
|||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
|
|
||||||
CommandProcessor::CommandProcessor(Machine* home_machine,
|
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),
|
_home_machine(home_machine),
|
||||||
_session_machine(home_machine),
|
_session_machine(home_machine),
|
||||||
_world_machines(world_machines) {
|
_world_machines(world_machines) {
|
||||||
|
|||||||
@ -4,12 +4,14 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include "db/database_manager.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
#include "vfs.h"
|
#include "vfs.h"
|
||||||
|
|
||||||
class CommandProcessor {
|
class CommandProcessor {
|
||||||
public:
|
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);
|
~CommandProcessor(void);
|
||||||
|
|
||||||
std::string process_command(const std::string& command);
|
std::string process_command(const std::string& command);
|
||||||
@ -28,6 +30,7 @@ public:
|
|||||||
void ensure_vfs_is_writable(void);
|
void ensure_vfs_is_writable(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
DatabaseManager* _db_manager;
|
||||||
Machine* _home_machine;
|
Machine* _home_machine;
|
||||||
Machine* _session_machine;
|
Machine* _session_machine;
|
||||||
vfs_node* _current_dir;
|
vfs_node* _current_dir;
|
||||||
|
|||||||
@ -13,19 +13,69 @@ void DatabaseManager::init(void) {
|
|||||||
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||||
"username TEXT NOT NULL UNIQUE,"
|
"username TEXT NOT NULL UNIQUE,"
|
||||||
"password TEXT NOT NULL,"
|
"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,
|
bool DatabaseManager::create_player(const std::string& username, const std::string& password,
|
||||||
const std::string& hostname) {
|
const std::string& hostname) {
|
||||||
|
long long player_id = 0;
|
||||||
|
long long machine_id = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
_db << "BEGIN;";
|
||||||
|
|
||||||
|
/* Create the player. */
|
||||||
_db << "INSERT INTO players (username, password, hostname) VALUES (?, ?, ?);"
|
_db << "INSERT INTO players (username, password, hostname) VALUES (?, ?, ?);"
|
||||||
<< username
|
<< username
|
||||||
<< password
|
<< password
|
||||||
<< hostname;
|
<< 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) {
|
} catch(const std::exception& e) {
|
||||||
/* Fail if the username exists. */
|
_db << "ROLLBACK;"; /* Ensure atomicity. */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -40,3 +90,11 @@ bool DatabaseManager::auth_player(const std::string& username, const std::string
|
|||||||
|
|
||||||
return authed;
|
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. */
|
/* Return true if creds are valid. */
|
||||||
bool auth_player(const std::string& username, const std::string& password);
|
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;
|
sqlite::database _db;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "db/database_manager.h"
|
||||||
#include "machine_manager.h"
|
#include "machine_manager.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
#include "vfs.h"
|
#include "vfs.h"
|
||||||
@ -90,3 +92,53 @@ Machine* MachineManager::create_machine(uint32_t id, const std::string& hostname
|
|||||||
|
|
||||||
return new_machine;
|
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,
|
Machine* create_machine(uint32_t id, const std::string& hostname,
|
||||||
const std::string& system_type);
|
const std::string& system_type);
|
||||||
|
Machine* load_machine(long long machine_id);
|
||||||
private:
|
private:
|
||||||
vfs_node* _vfs_template_root;
|
vfs_node* _vfs_template_root;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -14,6 +14,8 @@ enum vfs_node_type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct vfs_node {
|
struct vfs_node {
|
||||||
|
long long id;
|
||||||
|
long long parent_id; /* Used durin DB loading only. */
|
||||||
std::string name;
|
std::string name;
|
||||||
vfs_node_type type;
|
vfs_node_type type;
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
#include <exception>
|
#include <exception>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include "network_manager.h"
|
#include "network_manager.h"
|
||||||
#include "db/database_manager.h"
|
#include "db/database_manager.h"
|
||||||
@ -78,7 +77,8 @@ void NetworkManager::start_accept(void) {
|
|||||||
uint32_t player_id = _next_player_id++;
|
uint32_t player_id = _next_player_id++;
|
||||||
Machine* player_machine = _machine_manager.create_machine(player_id, "player.home",
|
Machine* player_machine = _machine_manager.create_machine(player_id, "player.home",
|
||||||
"player");
|
"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();
|
Player* new_player_ptr = new_player.get();
|
||||||
_players[player_id] = std::move(new_player);
|
_players[player_id] = std::move(new_player);
|
||||||
new_connection->set_id(player_id);
|
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, "::");
|
auto parts = split_message(payload, "::");
|
||||||
if(parts.size() == 3) {
|
if(parts.size() == 3) {
|
||||||
if(_db_manager->create_player(parts[0], parts[1], parts[2])) {
|
if(_db_manager->create_player(parts[0], parts[1], parts[2])) {
|
||||||
/*
|
long long machine_id = _db_manager->get_player_home_machine_id(parts[0]);
|
||||||
* TODO: When creating a player, also create their machine and save it.
|
Machine* home_machine = _machine_manager.load_machine(machine_id);
|
||||||
* for now, they will juse use a temp machine on auth.
|
delete player->cmd_processor; /* Delete old command processor. */
|
||||||
*/
|
player->cmd_processor = new CommandProcessor(home_machine, _world_machines,
|
||||||
|
_db_manager.get());
|
||||||
player->state = PlayerState::ACTIVE;
|
player->state = PlayerState::ACTIVE;
|
||||||
connection->send("C_ACC_SUCCESS");
|
connection->send("C_ACC_SUCCESS");
|
||||||
/* send initial prompt. */
|
/* send initial prompt. */
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "command_processor.h"
|
#include "command_processor.h"
|
||||||
|
#include "db/database_manager.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
|
|
||||||
Player::Player(uint32_t new_id, Machine* home_machine,
|
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),
|
id(new_id),
|
||||||
state(PlayerState::AUTHENTICATING) {
|
state(PlayerState::AUTHENTICATING) {
|
||||||
|
|
||||||
cmd_processor = new CommandProcessor(home_machine, world_machines);
|
cmd_processor = new CommandProcessor(home_machine, world_machines, db_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
Player::~Player(void) {
|
Player::~Player(void) {
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "db/database_manager.h"
|
||||||
#include "command_processor.h"
|
#include "command_processor.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
|
|
||||||
@ -14,7 +15,8 @@ enum class PlayerState {
|
|||||||
|
|
||||||
class Player {
|
class Player {
|
||||||
public:
|
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);
|
~Player(void);
|
||||||
|
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user