diff --git a/source/src/commands/disable.cpp b/source/src/commands/disable.cpp new file mode 100644 index 0000000..d99daea --- /dev/null +++ b/source/src/commands/disable.cpp @@ -0,0 +1,74 @@ +#include "command_registry.hpp" +#include "config.hpp" +#include "servers.hpp" +#include "utils/output.hpp" +#include "shared_commands.hpp" + +namespace dropshell +{ + int disable_handler(const CommandContext &ctx); + + static std::vector disable_name_list = {"disable"}; + + // Static registration + struct DisableCommandRegister + { + DisableCommandRegister() + { + CommandRegistry::instance().register_command({disable_name_list, + disable_handler, + shared_commands::std_autocomplete, + false, // hidden + true, // requires_config + false, // requires_install + 1, // min_args + 1, // max_args + "disable SERVERNAME", + "Disable interaction with a server while keeping all data intact", + R"( + + disable SERVERNAME Disables the specified server. + + This command marks a server as disabled on your local machine. + When disabled, dropshell will no longer: + - Check the server status + - Update services on the server + - Interact with the server in any way + + All data and configuration on the server remains intact. + You can re-enable the server at any time using the 'enable' command. + + Note: This setting is stored locally only and does not affect the server itself. + )"}); + } + } disable_command_register; + + int disable_handler(const CommandContext &ctx) + { + std::string server_name = ctx.args[0]; + + // Check if server exists + if (!server_exists(server_name)) + { + error << "Server '" << server_name << "' does not exist" << std::endl; + return 1; + } + + // Check if already disabled + if (gConfig().is_server_disabled(server_name)) + { + info << "Server '" << server_name << "' is already disabled" << std::endl; + return 0; + } + + // Disable the server + gConfig().set_server_disabled(server_name, true); + + info << "Server '" << server_name << "' has been disabled" << std::endl; + info << "Dropshell will no longer check, update, or interact with this server" << std::endl; + info << "Use 'dropshell enable " << server_name << "' to re-enable interaction" << std::endl; + + return 0; + } + +} // namespace dropshell \ No newline at end of file diff --git a/source/src/commands/enable.cpp b/source/src/commands/enable.cpp new file mode 100644 index 0000000..abc339f --- /dev/null +++ b/source/src/commands/enable.cpp @@ -0,0 +1,70 @@ +#include "command_registry.hpp" +#include "config.hpp" +#include "servers.hpp" +#include "utils/output.hpp" +#include "shared_commands.hpp" + +namespace dropshell +{ + int enable_handler(const CommandContext &ctx); + + static std::vector enable_name_list = {"enable"}; + + // Static registration + struct EnableCommandRegister + { + EnableCommandRegister() + { + CommandRegistry::instance().register_command({enable_name_list, + enable_handler, + shared_commands::std_autocomplete, + false, // hidden + true, // requires_config + false, // requires_install + 1, // min_args + 1, // max_args + "enable SERVERNAME", + "Re-enable interaction with a previously disabled server", + R"( + + enable SERVERNAME Re-enables the specified server. + + This command removes a server from the disabled list, allowing + dropshell to resume normal operations with the server, including: + - Checking server status + - Updating and managing services + - All other server interactions + + Note: This setting is stored locally only and does not affect the server itself. + )"}); + } + } enable_command_register; + + int enable_handler(const CommandContext &ctx) + { + std::string server_name = ctx.args[0]; + + // Check if server exists + if (!server_exists(server_name)) + { + error << "Server '" << server_name << "' does not exist" << std::endl; + return 1; + } + + // Check if not disabled + if (!gConfig().is_server_disabled(server_name)) + { + info << "Server '" << server_name << "' is not disabled" << std::endl; + return 0; + } + + // Enable the server + gConfig().set_server_disabled(server_name, false); + + info << "Server '" << server_name << "' has been enabled" << std::endl; + info << "Dropshell will resume checking, updating, and interacting with this server" << std::endl; + + return 0; + } + +} // namespace dropshell \ No newline at end of file diff --git a/source/src/commands/install.cpp b/source/src/commands/install.cpp index 1cee35a..d63b7a3 100644 --- a/source/src/commands/install.cpp +++ b/source/src/commands/install.cpp @@ -466,6 +466,14 @@ complete -F _dropshell_completions ds int install_server(const ServerConfig &server) { + // Check if server is disabled + if (gConfig().is_server_disabled(server.get_server_name())) + { + warning << "Server '" << server.get_server_name() << "' is disabled. Skipping installation." << std::endl; + info << "Use 'dropshell enable " << server.get_server_name() << "' to re-enable this server." << std::endl; + return 0; + } + // install the dropshell agent on the given server. maketitle("Installing dropshell agent on " + server.get_server_name(), sColour::INFO); @@ -557,6 +565,14 @@ complete -F _dropshell_completions ds return 1; } + // Check if server is disabled + if (gConfig().is_server_disabled(server)) + { + warning << "Server '" << server << "' is disabled. Skipping installation." << std::endl; + info << "Use 'dropshell enable " << server << "' to re-enable this server." << std::endl; + return 0; + } + ServerConfig server_env(server); ASSERT(server_env.is_valid(), "Invalid server environment for " + server); if (safearg(ctx.args, 1) == "all") diff --git a/source/src/commands/list.cpp b/source/src/commands/list.cpp index 9f15a2d..b73fc1c 100644 --- a/source/src/commands/list.cpp +++ b/source/src/commands/list.cpp @@ -118,9 +118,12 @@ void list_servers() { std::string ports_used_str = ""; std::set ports_used; + // Check if server is disabled + bool is_disabled = gConfig().is_server_disabled(sup.server.get_server_name()); + // Check if server is online (with caching to avoid redundant checks for multiple users) bool is_online = false; - { + if (!is_disabled) { auto it = server_online_status.find(sup.server.get_server_name()); if (it != server_online_status.end()) { is_online = it->second; @@ -133,8 +136,8 @@ void list_servers() { } } - // Only check service status if server is online - if (is_online) { + // Only check service status if server is online and not disabled + if (is_online && !is_disabled) { std::map status = shared_commands::get_all_services_status(sup.server.get_server_name(),sup.user.user); for (const auto& [service_name, service_status] : status) { @@ -146,12 +149,14 @@ void list_servers() { ports_used_str += std::to_string(port) + " "; } - // Add red cross to address if server is offline + // Add red cross to address if server is offline or disabled std::string address_display = sup.server.get_SSH_HOST(); - if (!is_online) { + if (is_disabled) { + address_display += " :disabled:"; + } else if (!is_online) { address_display += " :cross:"; } - + // critical section { std::lock_guard lock(tp_mutex); diff --git a/source/src/commands/start.cpp b/source/src/commands/start.cpp index 1dd09f4..7a0b071 100644 --- a/source/src/commands/start.cpp +++ b/source/src/commands/start.cpp @@ -44,6 +44,14 @@ namespace dropshell bool start_service(const std::string &server, const std::string &service) { + // Check if server is disabled + if (gConfig().is_server_disabled(server)) + { + warning << "Server '" << server << "' is disabled. Cannot start services." << std::endl; + info << "Use 'dropshell enable " << server << "' to re-enable this server." << std::endl; + return false; + } + ServerConfig server_env(server); if (!server_env.is_valid()) { diff --git a/source/src/commands/stop.cpp b/source/src/commands/stop.cpp index 13f4cfe..21b4df3 100644 --- a/source/src/commands/stop.cpp +++ b/source/src/commands/stop.cpp @@ -44,6 +44,14 @@ namespace dropshell bool stop_service(const std::string &server, const std::string &service) { + // Check if server is disabled + if (gConfig().is_server_disabled(server)) + { + warning << "Server '" << server << "' is disabled. Cannot stop services." << std::endl; + info << "Use 'dropshell enable " << server << "' to re-enable this server." << std::endl; + return false; + } + ServerConfig server_env(server); if (!server_env.is_valid()) { diff --git a/source/src/config.cpp b/source/src/config.cpp index 49e3092..928f1c4 100644 --- a/source/src/config.cpp +++ b/source/src/config.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "config.hpp" #include "utils/utils.hpp" #include @@ -48,7 +49,8 @@ bool config::load_config() { // load json config file. "template_local_paths", "template_registries", "backups_path", - "log_level" + "log_level", + "disabled_servers" }; std::set deprecated_fields = { @@ -307,4 +309,71 @@ void config::apply_log_level() set_log_level(level); } +bool config::is_server_disabled(const std::string &server_name) const +{ + if (!mIsConfigSet || !mConfig.contains("disabled_servers")) + return false; + + const auto& disabled = mConfig["disabled_servers"]; + if (!disabled.is_array()) + return false; + + for (const auto& server : disabled) { + if (server.is_string() && server == server_name) + return true; + } + return false; +} + +void config::set_server_disabled(const std::string &server_name, bool disabled) +{ + if (!mIsConfigSet) { + return; + } + + // Ensure disabled_servers array exists + if (!mConfig.contains("disabled_servers") || !mConfig["disabled_servers"].is_array()) { + mConfig["disabled_servers"] = nlohmann::json::array(); + } + + auto& disabled_servers = mConfig["disabled_servers"]; + + // Find if server is already in the list + auto it = std::find(disabled_servers.begin(), disabled_servers.end(), server_name); + + if (disabled) { + // Add to disabled list if not already there + if (it == disabled_servers.end()) { + disabled_servers.push_back(server_name); + save_config(false); // Save immediately + } + } else { + // Remove from disabled list if present + if (it != disabled_servers.end()) { + disabled_servers.erase(it); + save_config(false); // Save immediately + } + } +} + +std::vector config::get_disabled_servers() const +{ + std::vector result; + + if (!mIsConfigSet || !mConfig.contains("disabled_servers")) + return result; + + const auto& disabled = mConfig["disabled_servers"]; + if (!disabled.is_array()) + return result; + + for (const auto& server : disabled) { + if (server.is_string() && !server.empty()) { + result.push_back(server); + } + } + + return result; +} + } // namespace dropshell \ No newline at end of file diff --git a/source/src/config.hpp b/source/src/config.hpp index 5f8021b..5077bb8 100644 --- a/source/src/config.hpp +++ b/source/src/config.hpp @@ -43,6 +43,11 @@ class config { std::string get_log_level() const; void apply_log_level(); + // Server enable/disable management + bool is_server_disabled(const std::string &server_name) const; + void set_server_disabled(const std::string &server_name, bool disabled); + std::vector get_disabled_servers() const; + private: nlohmann::json mConfig; bool mIsConfigSet;