149 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include <sol/types.hpp>
 | 
						|
#include <sstream>
 | 
						|
 | 
						|
#include "command_processor.h"
 | 
						|
#include "db/database_manager.h"
 | 
						|
#include "vfs.h"
 | 
						|
#include "lua_api.h"
 | 
						|
#include "lua_processor.h"
 | 
						|
#include "machine_manager.h"
 | 
						|
#include "machine.h"
 | 
						|
 | 
						|
 | 
						|
vfs_node* find_node_by_id(vfs_node* root, long long id) {
 | 
						|
  if(root->id == id) {
 | 
						|
    return root;
 | 
						|
  }
 | 
						|
  for(auto const& [name, child] : root->children) {
 | 
						|
    vfs_node* found = find_node_by_id(child, id);
 | 
						|
    if(found) {
 | 
						|
      return found;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
CommandProcessor::CommandProcessor(Machine* home_machine,
 | 
						|
                                   std::map<std::string, Machine*>& world_machines,
 | 
						|
                                   DatabaseManager* db_manager,
 | 
						|
                                   MachineManager* machine_manager) :
 | 
						|
    _machine_manager(machine_manager),
 | 
						|
    _db_manager(db_manager),
 | 
						|
    _home_machine(home_machine),
 | 
						|
    _session_machine(home_machine),
 | 
						|
    _world_machines(world_machines) {
 | 
						|
  _lua = new LuaProcessor();
 | 
						|
  _current_dir = _session_machine->vfs_root;
 | 
						|
}
 | 
						|
 | 
						|
CommandProcessor::~CommandProcessor(void) {
 | 
						|
  delete _lua;
 | 
						|
}
 | 
						|
 | 
						|
vfs_node* CommandProcessor::get_current_dir(void) {
 | 
						|
  return _current_dir;
 | 
						|
}
 | 
						|
 | 
						|
Machine* CommandProcessor::get_home_machine(void)     { return _home_machine; }
 | 
						|
Machine* CommandProcessor::get_session_machine(void)  { return _session_machine; }
 | 
						|
 | 
						|
std::map<std::string, Machine*>&
 | 
						|
CommandProcessor::get_world_machines(void) {
 | 
						|
  return _world_machines;
 | 
						|
}
 | 
						|
 | 
						|
DatabaseManager* CommandProcessor::get_db_manager(void) {
 | 
						|
  return _db_manager;
 | 
						|
}
 | 
						|
 | 
						|
MachineManager* CommandProcessor::get_machine_manager(void) {
 | 
						|
  return _machine_manager;
 | 
						|
}
 | 
						|
 | 
						|
void CommandProcessor::set_current_dir(vfs_node* node) {
 | 
						|
  _current_dir = node;
 | 
						|
}
 | 
						|
 | 
						|
void CommandProcessor::set_session_machine(Machine* machine) {
 | 
						|
  _session_machine = machine;
 | 
						|
  if(_session_machine) {
 | 
						|
    _current_dir = _session_machine->vfs_root;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
std::string CommandProcessor::process_command(const std::string& command) {
 | 
						|
  /* Trim trailing whitespace. */
 | 
						|
  std::string cmd = command;
 | 
						|
  size_t end = cmd.find_last_not_of(" \t\n\r");
 | 
						|
  cmd = (end == std::string::npos) ? "" : cmd.substr(0, end+1);
 | 
						|
 | 
						|
  /* === Generic script executer. === */
 | 
						|
  /* Parse the command and it's arguments. */
 | 
						|
  std::stringstream ss(cmd);
 | 
						|
  std::string command_name;
 | 
						|
  ss >> command_name;
 | 
						|
 | 
						|
  std::vector<std::string> args;
 | 
						|
  std::string arg;
 | 
						|
  while(ss >> arg) {
 | 
						|
    args.push_back(arg);
 | 
						|
  }
 | 
						|
 | 
						|
  /* Search for script in the /bin directory of the current session machine. */
 | 
						|
  std::string script_filename = command_name + ".lua";
 | 
						|
  long long script_id = 0;
 | 
						|
  std::string script_content;
 | 
						|
  _db_manager->_db << "SELECT T2.id, T2.content FROM vfs_nodes AS T1 JOIN vfs_nodes AS T2 "
 | 
						|
                      "ON T1.id = T2.parent_id WHERE T1.name = 'bin' AND T2.name = ? "
 | 
						|
                      "AND t1.machine_id = ?;"
 | 
						|
                   << script_filename << _session_machine->id
 | 
						|
                   >> [&](long long id, std::string content) {
 | 
						|
                        script_id = id;
 | 
						|
                        script_content = content;
 | 
						|
                      };
 | 
						|
 | 
						|
  if(script_id > 0) {
 | 
						|
    bool is_remote = (_session_machine != _home_machine);
 | 
						|
    sol::object result = _lua->execute(script_content, *this, args, is_remote);
 | 
						|
    return result.is<std::string>() ? result.as<std::string>() : "[Script returned an unexpected type]";
 | 
						|
  }
 | 
						|
  return "Unknown command: " + command_name + "\n";
 | 
						|
}
 | 
						|
 | 
						|
std::string CommandProcessor::write_file(const std::string& path, const std::string& content) {
 | 
						|
  return api::write_file(*this, path, content);
 | 
						|
}
 | 
						|
 | 
						|
/* Find a VFS node by it's absolute path. */
 | 
						|
vfs_node* find_node_by_path(vfs_node* root, const std::string& path) {
 | 
						|
  if(path == "/") {
 | 
						|
    return root;
 | 
						|
  }
 | 
						|
  vfs_node* current = root;
 | 
						|
  std::stringstream ss(path);
 | 
						|
  std::string segment;
 | 
						|
 | 
						|
  /* Discard the first empty segment that comes form the leading '/'. */
 | 
						|
  if(path[0] == '/') {
 | 
						|
    std::getline(ss, segment, '/');
 | 
						|
  }
 | 
						|
 | 
						|
  while(std::getline(ss, segment, '/')) {
 | 
						|
    if(current->type == DIR_NODE && current->children.count(segment)) {
 | 
						|
      current = current->children[segment];
 | 
						|
    } else {
 | 
						|
      return nullptr; /* Path segmenet not found. */
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return current;
 | 
						|
}
 | 
						|
 | 
						|
std::string CommandProcessor::read_file(const std::string& path) {
 | 
						|
  vfs_node* root = get_session_machine()->vfs_root;
 | 
						|
  vfs_node* node = find_node_by_path(root, path);
 | 
						|
  if(node && node->type == FILE_NODE) {
 | 
						|
    return node->content;
 | 
						|
  }
 | 
						|
  return "Error: file not found.";
 | 
						|
}
 |