From 442ad330ae1f45151718aca96625b167a67f0805 Mon Sep 17 00:00:00 2001 From: mrkmntal Date: Fri, 28 Aug 2026 22:46:44 -0400 Subject: [PATCH] Added an optional timeout_seconds parameter to stopContainer --- DEVLOG.md | 3 +++ main.cpp | 32 +++++++++++++++++++++++++------- src/docker_manager.cpp | 8 ++++++-- src/docker_manager.hpp | 4 +++- 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/DEVLOG.md b/DEVLOG.md index d2bc0c4..f786a35 100644 --- a/DEVLOG.md +++ b/DEVLOG.md @@ -1,5 +1,8 @@ # Tux-Dock Development Log +## 0.3.1-beta +Added an optional timeout_seconds parameter to stopContainer + ## 0.3-beta This release introduces `tuxreaperd`, a micro init system for containers. diff --git a/main.cpp b/main.cpp index 13974b3..e465047 100644 --- a/main.cpp +++ b/main.cpp @@ -154,6 +154,7 @@ private: std::vector action_threads_; OperationState operation_state_; std::size_t spinner_frame_ = 0; + static constexpr int kMaxStopTimeout = 300; static bool IsDigits(const std::string& value); static bool IsValidContainerName(const std::string& name); @@ -197,7 +198,7 @@ private: void BeginBusyOperation(const std::string&, const std::string&, std::function); void StartSpinner(); void StopSpinner(); - void BeginStopOperation(const std::string& id); + void BeginStopOperation(const std::string& id, int timeout_seconds = 10); void RefreshState(const std::string& message = "Refreshing Docker state..."); void ApplyRefreshResults(DockerManager::ListResult containers, DockerManager::ListResult images); @@ -479,16 +480,16 @@ void TuxDockApp::BeginBusyOperation(const std::string& title, } }); } -void TuxDockApp::BeginStopOperation(const std::string& id) { +void TuxDockApp::BeginStopOperation(const std::string& id, int timeout_seconds) { operation_state_.begin("Stopping container", "Stopping and refreshing state..."); modal_mode_ = ModalMode::Busy; InstallSignalTraps(); auto* active = screen_; spinner_frame_ = 0; StartSpinner(); - action_threads_.emplace_back([this, active, id] { + action_threads_.emplace_back([this, active, id, timeout_seconds] { std::string message; - const bool stopped = docker_.stopContainer(id, message); + const bool stopped = docker_.stopContainer(id, message, timeout_seconds); auto containers = docker_.getContainerList(); auto images = docker_.getImageList(); if (!active || ftxui::ScreenInteractive::Active() != active) return; @@ -644,8 +645,25 @@ void TuxDockApp::ActionDeleteImage() { void TuxDockApp::ActionStopContainer() { PromptContainerSelection( "Stop Container", - [this](const std::string& id, const std::string&) { - BeginStopOperation(id); + [this](const std::string& id, const std::string& name) { + OpenInput( + "Stop Container", + "Shutdown grace period in seconds for " + name + + " (default 10, max " + std::to_string(kMaxStopTimeout) + "):", + [this, id](bool ok, const std::string& value) { + if (!ok) return; + int seconds = 10; + if (!value.empty()) { + try { + seconds = std::stoi(value); + } catch (...) { + seconds = 10; + } + } + if (seconds < 0) seconds = 10; + if (seconds > kMaxStopTimeout) seconds = kMaxStopTimeout; + BeginStopOperation(id, seconds); + }); }); } @@ -699,7 +717,7 @@ void TuxDockApp::ActionExecDetachedCommand() { } void TuxDockApp::ActionAbout() { - OpenMessage("About Tux-Dock", "Tux-Dock 0.3-beta | Created by markmental"); + OpenMessage("About Tux-Dock", "Tux-Dock 0.3.1-beta | Created by markmental"); } void TuxDockApp::ExecuteSelectedAction() { diff --git a/src/docker_manager.cpp b/src/docker_manager.cpp index 704a00c..14a2961 100644 --- a/src/docker_manager.cpp +++ b/src/docker_manager.cpp @@ -157,8 +157,12 @@ bool DockerManager::deleteImage(const std::string& id, std::string& message) con return true; } -bool DockerManager::stopContainer(const std::string& id, std::string& message) const { - const auto stop_request = [this, &id] { return engine_.request("POST", "/containers/" + id + "/stop"); }; +bool DockerManager::stopContainer(const std::string& id, + std::string& message, + int timeout_seconds) const { + const auto stop_request = [this, &id, timeout_seconds] { + return engine_.request("POST", "/containers/" + id + "/stop?t=" + std::to_string(timeout_seconds)); + }; const auto acceptable = [](const EngineResponse& response) { return response.status_code == 204 || response.status_code == 304 || response.status_code == 404 || response.ok(); }; diff --git a/src/docker_manager.hpp b/src/docker_manager.hpp index cc3f192..0b4d8ba 100644 --- a/src/docker_manager.hpp +++ b/src/docker_manager.hpp @@ -38,7 +38,9 @@ public: std::string& message) const; bool startDetached(const std::string& containerId, std::string& message) const; bool deleteImage(const std::string& imageId, std::string& message) const; - bool stopContainer(const std::string& containerId, std::string& message) const; + bool stopContainer(const std::string& containerId, + std::string& message, + int timeout_seconds = 10) const; bool removeContainer(const std::string& containerId, std::string& message) const; bool execShell(const std::string& containerId, std::string& message) const; bool execDetachedCommand(const std::string& containerId,