[Add] Implement remote sessions and server exit.
This commit is contained in:
parent
c7e8d97c63
commit
bb17cf3473
7
assets/scripts/bin/cd.lua
Normal file
7
assets/scripts/bin/cd.lua
Normal file
@ -0,0 +1,7 @@
|
||||
-- /bin/cd - Change Directory.
|
||||
local target = arg[1]
|
||||
if not target then
|
||||
return "" -- No argument, just return to prompt.
|
||||
end
|
||||
|
||||
return { action = "cd", target = target }
|
||||
6
assets/scripts/bin/exit.lua
Normal file
6
assets/scripts/bin/exit.lua
Normal file
@ -0,0 +1,6 @@
|
||||
-- /bin/exit - Disconnects from a remote session or cloes terminal window.
|
||||
if is_remote_session then
|
||||
return { action = "disconnect" }
|
||||
else
|
||||
return { action = "close_terminal" }
|
||||
end
|
||||
@ -52,6 +52,17 @@ bool ClientNetwork::connect(const std::string& host, uint16_t port) {
|
||||
}
|
||||
|
||||
void ClientNetwork::disconnect(void) {
|
||||
/* Stop the context, should cause the io_context.run() call in the
|
||||
* background thread to return.
|
||||
*/
|
||||
_io_context.stop();
|
||||
|
||||
/* Wait for the background thread to finish. */
|
||||
if(_context_thread.joinable()) {
|
||||
_context_thread.join();
|
||||
}
|
||||
|
||||
/* Should be safe to close the socket no that thread is stoped <questionmark> */
|
||||
if(is_connected()) {
|
||||
/* Close the socket. Causes outstanding async operations
|
||||
* in TcpConnection to compete with an error, which in return
|
||||
|
||||
@ -32,6 +32,11 @@ Terminal::~Terminal(void) {}
|
||||
void Terminal::update(void) {
|
||||
std::string server_msg;
|
||||
while(_network->poll_message(server_msg)) {
|
||||
if(server_msg == "__CLOSE_CONNECTION__") {
|
||||
_history.push_back("Connection closed by server.");
|
||||
_should_close = true;
|
||||
return;
|
||||
}
|
||||
/* Server will send "output\nprompt". Split them. */
|
||||
size_t last_newline = server_msg.find_last_of('\n');
|
||||
if(last_newline != std::string::npos) {
|
||||
@ -59,13 +64,7 @@ void Terminal::_on_ret_press(void) {
|
||||
/* Add the command to history. */
|
||||
_history.push_back(_prompt + "> " + command);
|
||||
|
||||
if(command == "exit") {
|
||||
_should_close = true;
|
||||
/* TODO: Window will close, and the OS will close the socket.
|
||||
* server will detect the disconnection.
|
||||
*/
|
||||
return;
|
||||
} else if(command == "clear"){
|
||||
if(command == "clear") {
|
||||
_history.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
#include "command_processor.h"
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
|
||||
#include "vfs.h"
|
||||
#include "lua_processor.h"
|
||||
#include "vfs_manager.h"
|
||||
|
||||
CommandProcessor::CommandProcessor(vfs_node* starting_dir,
|
||||
CommandProcessor::CommandProcessor(vfs_node* home_vfs,
|
||||
std::map<std::string, vfs_node*>& world_vfs) :
|
||||
_world_vfs(world_vfs) {
|
||||
_current_dir = starting_dir;
|
||||
_lua = new LuaProcessor();
|
||||
home_vfs_root = home_vfs;
|
||||
session_vfs_root = home_vfs_root;
|
||||
_current_dir = session_vfs_root;
|
||||
}
|
||||
|
||||
CommandProcessor::~CommandProcessor(void) {
|
||||
@ -46,7 +48,8 @@ std::string CommandProcessor::process_command(const std::string& command) {
|
||||
}
|
||||
if(root->children.count("bin") && root->children["bin"]->children.count(script_filename)) {
|
||||
vfs_node* script_node = root->children["bin"]->children[script_filename];
|
||||
sol::object result = _lua->execute(script_node->content, _current_dir, args);
|
||||
bool is_remote = (session_vfs_root != home_vfs_root);
|
||||
sol::object result = _lua->execute(script_node->content, _current_dir, args, is_remote);
|
||||
if(result.is<std::string>()) {
|
||||
return result.as<std::string>();
|
||||
} else if(result.is<sol::table>()) {
|
||||
@ -54,29 +57,7 @@ std::string CommandProcessor::process_command(const std::string& command) {
|
||||
}
|
||||
return "[Script returned an unexpected type]";
|
||||
}
|
||||
|
||||
|
||||
/* === Tmp fallback for built-in C++ commands. */
|
||||
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);
|
||||
}
|
||||
|
||||
return "Unknown command: " + command + "\n";
|
||||
return "Unknown command: " + command_name + "\n";
|
||||
}
|
||||
|
||||
std::string CommandProcessor::_handle_vfs_action(sol::table action) {
|
||||
@ -130,10 +111,34 @@ std::string CommandProcessor::_handle_vfs_action(sol::table action) {
|
||||
} else if(action_name == "ssh") {
|
||||
std::string target_ip = action["target"].get_or<std::string>("");
|
||||
if(_world_vfs.count(target_ip)) {
|
||||
_current_dir = _world_vfs[target_ip];
|
||||
session_vfs_root = _world_vfs[target_ip];
|
||||
_current_dir = session_vfs_root;
|
||||
return "Connected to " + target_ip;
|
||||
}
|
||||
return "ssh: Could not resolve hostname " + target_ip + ": Name or service not known";
|
||||
} else if(action_name == "cd") {
|
||||
std::string target_dir_name = action["target"].get_or<std::string>("");
|
||||
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 std::string("cd: not a directory: ") + target_dir_name;
|
||||
}
|
||||
} else {
|
||||
return std::string("cd: no such file or directory: ") + target_dir_name;
|
||||
}
|
||||
return ""; /* Success. */
|
||||
} else if(action_name == "disconnect") {
|
||||
session_vfs_root = home_vfs_root;
|
||||
_current_dir = home_vfs_root;
|
||||
return "Connection closed.";
|
||||
} else if(action_name == "close_terminal") {
|
||||
return "__CLOSE_CONNECTION__";
|
||||
}
|
||||
return "Error: Unknown VFS action '" + action_name + "'";
|
||||
}
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <lua_processor.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "vfs.h"
|
||||
#include <lua_processor.h>
|
||||
|
||||
class CommandProcessor {
|
||||
public:
|
||||
CommandProcessor(vfs_node* starting_dir, std::map<std::string, vfs_node*>& world_vfs);
|
||||
CommandProcessor(vfs_node* home_vfs, std::map<std::string, vfs_node*>& world_vfs);
|
||||
~CommandProcessor(void);
|
||||
|
||||
std::string process_command(const std::string& command);
|
||||
@ -16,6 +16,8 @@ public:
|
||||
|
||||
private:
|
||||
std::string _handle_vfs_action(sol::table action);
|
||||
vfs_node* home_vfs_root;
|
||||
vfs_node* session_vfs_root;
|
||||
vfs_node* _current_dir;
|
||||
std::map<std::string, vfs_node*>& _world_vfs;
|
||||
LuaProcessor* _lua;
|
||||
|
||||
@ -17,9 +17,10 @@ LuaProcessor::LuaProcessor(void) {
|
||||
LuaProcessor::~LuaProcessor(void) {}
|
||||
|
||||
sol::object LuaProcessor::execute(const std::string& script, vfs_node* current_dir,
|
||||
const std::vector<std::string>& args) {
|
||||
const std::vector<std::string>& args, bool is_remote) {
|
||||
try {
|
||||
/* Pass C++ objects/points into the Lua env. */
|
||||
_lua["is_remote_session"] = is_remote;
|
||||
_lua["current_dir"] = current_dir;
|
||||
|
||||
/* Create and populate the 'arg' table for the script. */
|
||||
|
||||
@ -12,7 +12,7 @@ public:
|
||||
|
||||
/* Executes a string of lua code and returns result as a string. */
|
||||
sol::object execute(const std::string& script, vfs_node* current_dir,
|
||||
const std::vector<std::string>& args);
|
||||
const std::vector<std::string>& args, bool is_remote);
|
||||
private:
|
||||
sol::state _lua;
|
||||
};
|
||||
|
||||
@ -78,7 +78,9 @@ void TcpConnection::async_read_header(void) {
|
||||
/* Wait for next message. */
|
||||
async_read_header();
|
||||
} else {
|
||||
_socket.close();
|
||||
if(_socket.is_open()) {
|
||||
_socket.close();
|
||||
}
|
||||
if(_on_disconnect) _on_disconnect();
|
||||
}
|
||||
});
|
||||
@ -92,7 +94,9 @@ void TcpConnection::async_read_header(void) {
|
||||
/* Peer disconnected cleanly? */
|
||||
if(ec != asio::error::eof) {
|
||||
}
|
||||
_socket.close();
|
||||
if(_socket.is_open()) {
|
||||
_socket.close();
|
||||
}
|
||||
if(_on_disconnect) _on_disconnect();
|
||||
}
|
||||
});
|
||||
@ -110,7 +114,9 @@ void TcpConnection::async_write_header() {
|
||||
async_write_header();
|
||||
}
|
||||
} else {
|
||||
_socket.close();
|
||||
if(_socket.is_open()) {
|
||||
_socket.close();
|
||||
}
|
||||
if(_on_disconnect) _on_disconnect();
|
||||
}
|
||||
});
|
||||
|
||||
@ -97,6 +97,13 @@ void NetworkManager::on_message(std::shared_ptr<net::TcpConnection> connection,
|
||||
fprintf(stderr, "[Player %u] Command: '%s'\n", player->id, message.c_str());
|
||||
|
||||
std::string response = player->cmd_processor->process_command(message);
|
||||
|
||||
if(response == "__CLOSE_CONNECTION__") {
|
||||
connection->send(response);
|
||||
/* Just let me close the f.cking terminal? */
|
||||
return;
|
||||
}
|
||||
|
||||
std::string new_prompt = get_full_path(player->cmd_processor->get_current_dir());
|
||||
response += "\n" + new_prompt;
|
||||
|
||||
|
||||
@ -3,14 +3,15 @@
|
||||
|
||||
Player::Player(uint32_t new_id, VFSManager& vfs_manager,
|
||||
std::map<std::string, vfs_node*>& world_vfs) :
|
||||
id(new_id),
|
||||
vfs_root(vfs_manager.create_vfs("player")),
|
||||
cmd_processor(new CommandProcessor(vfs_root, world_vfs)) {}
|
||||
id(new_id) {
|
||||
vfs_node* player_vfs = vfs_manager.create_vfs("player");
|
||||
cmd_processor = new CommandProcessor(player_vfs, world_vfs);
|
||||
}
|
||||
|
||||
Player::~Player(void) {
|
||||
if(cmd_processor) {
|
||||
delete cmd_processor;
|
||||
}
|
||||
|
||||
/* TODO: The VFSManager should handle deleting the vfs_root. */
|
||||
/* TODO: The VFSManager should handle deleting the player_vfs_root. */
|
||||
}
|
||||
|
||||
@ -2,9 +2,11 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "command_processor.h"
|
||||
#include "vfs.h"
|
||||
#include "vfs_manager.h"
|
||||
#include "command_processor.h"
|
||||
|
||||
class CommandProcessor;
|
||||
|
||||
class Player {
|
||||
public:
|
||||
@ -12,6 +14,5 @@ public:
|
||||
~Player(void);
|
||||
|
||||
uint32_t id;
|
||||
vfs_node* vfs_root;
|
||||
CommandProcessor* cmd_processor; /* Manages the VFS state for the remote session. */
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user