Create hybrid authority model for command processing.

This commit is contained in:
Ritchie Cunningham 2025-09-21 00:22:04 +01:00
parent dbe6e437ad
commit a73aa4feaf
6 changed files with 94 additions and 23 deletions

View File

@ -5,54 +5,60 @@
#include <SDL3/SDL_events.h> #include <SDL3/SDL_events.h>
#include "client_network.h" #include "client_network.h"
#include "command_processor.h"
#include "gfx/txt_renderer.h" #include "gfx/txt_renderer.h"
#include "vfs_manager.h"
#include "vfs.h"
#include "terminal.h" #include "terminal.h"
Terminal::Terminal(void) { Terminal::Terminal(void) {
/* Placeholder welcome message to history. */ /* Placeholder welcome message to history. */
_history.push_back("Welcome to Bettola"); _history.push_back("Welcome to Bettola (local mode)");
_network = new ClientNetwork(); _network = nullptr; /* No network connection for now. */
if(_network->connect("localhost", 8080)) {
_history.push_back("Connection to server Success!"); /* Create local file system for the client. */
} else { _local_vfs = vfs_manager::create_root_system();
_history.push_back("Connection to server failed!"); _local_cmd_processor = new CommandProcessor(_local_vfs);
} _current_path = get_full_path(_local_cmd_processor->get_current_dir());
_current_path = "/";
_scroll_offset = 0; _scroll_offset = 0;
} }
Terminal::~Terminal(void) { Terminal::~Terminal(void) {
delete _network; if(_network) {
delete _network;
}
} }
void Terminal::_on_ret_press(void) { void Terminal::_on_ret_press(void) {
std::string command = _input_buffer;
/* Add the command to history. */ /* Add the command to history. */
_history.push_back("> " + _input_buffer); _history.push_back(_current_path + "> " + command);
/* For now, print the commmand clear buffer. std::string response;
* TODO: Parse and execute commands. /*
* All commands run locally for now.
* TODO: Remote commands.
*/ */
printf("Command entered: %s\n", _input_buffer.c_str()); if(command == "clear") {
_network->send_command(_input_buffer.c_str()); _history.clear();
std::string response = _network->receive_response(); } else {
response = _local_cmd_processor->process_command(command);
}
/* Check if the response is a new path for the prompt. */ /* Check if the response is a new path for the prompt. */
if(response.rfind("/", 0) == 0 && response.find('\n') == std::string::npos) { if(response.rfind("/", 0) == 0) {
_current_path = response; _current_path = response;
} else if(!response.empty()) { } else if(!response.empty()) {
/* Otherwise, it's command out. Split it by newline and add to history. */ /* Otherwise, it's command out. Split it by newline and add to history. */
std::stringstream ss(response); std::stringstream ss(response);
std::string line; std::string line;
while(std::getline(ss, line, '\n')) { while(std::getline(ss, line, '\n')) {
_history.push_back(line); if(!line.empty()) {
_history.push_back(line);
}
} }
} }
if(_input_buffer == "clear") {
_history.clear();
} else if(_input_buffer == "help") {
_history.push_back("Commands: help, clear");
}
_input_buffer.clear(); _input_buffer.clear();
/* TODO: Ugly hack. Refactor to pass window height /* TODO: Ugly hack. Refactor to pass window height
* We need the window height to know if we should * We need the window height to know if we should

View File

@ -5,6 +5,8 @@
#include "gfx/txt_renderer.h" #include "gfx/txt_renderer.h"
#include "client_network.h" #include "client_network.h"
#include "vfs_manager.h"
#include "command_processor.h"
class Terminal { class Terminal {
public: public:
@ -22,5 +24,7 @@ private:
std::vector<std::string> _history; std::vector<std::string> _history;
int _scroll_offset; int _scroll_offset;
std::string _current_path; std::string _current_path;
vfs_node* _local_vfs;
CommandProcessor* _local_cmd_processor;
ClientNetwork* _network; ClientNetwork* _network;
}; };

View File

@ -0,0 +1,45 @@
#include "command_processor.h"
#include "vfs.h"
CommandProcessor::CommandProcessor(vfs_node* starting_dir) {
_current_dir = starting_dir;
}
vfs_node* CommandProcessor::get_current_dir(void) {
return _current_dir;
}
std::string CommandProcessor::process_command(const std::string& command) {
if(command.rfind("cd ", 0) == 0) {
std::string target_dir_name = command.substr(3);
if(target_dir_name == "..") {
if(_current_dir->parent) {
_current_dir = _current_dir->parent;
}
} else if(_current_dir->children.count(target_dir_name)) {
vfs_node* target_node = _current_dir->children[target_dir_name];
if(target_node->type == DIR_NODE) {
_current_dir = target_node;
} else {
return "cd: not a directory\n";
}
} else {
return "cd: no such file or directory\n";
}
return get_full_path(_current_dir);
} else if(command == "ls") {
std::string response = "";
if(_current_dir && _current_dir->type == DIR_NODE) {
for(auto const& [name, node] : _current_dir->children) {
response += name;
if(node->type == DIR_NODE) {
response += "/";
}
response += " ";
}
}
return response;
}
return "Unknown command: " + command + "\n";
}

View File

@ -0,0 +1,16 @@
#pragma once
#include <string>
#include "vfs.h"
class CommandProcessor {
public:
CommandProcessor(vfs_node* starting_dir);
std::string process_command(const std::string& command);
vfs_node* get_current_dir(void);
private:
vfs_node* _current_dir;
};