diff --git a/launcher/backend/include_public/DhfsInstance.hpp b/launcher/backend/include_public/DhfsInstance.hpp index 7542f90b..2e61dcb2 100644 --- a/launcher/backend/include_public/DhfsInstance.hpp +++ b/launcher/backend/include_public/DhfsInstance.hpp @@ -15,11 +15,15 @@ #include "DhfsWxProcess.hpp" enum class DhfsInstanceState { + STARTING, RUNNING, + STOPPING, STOPPED, }; class DhfsInstance { + friend DhfsWxProcess; + public: DhfsInstance(); @@ -31,14 +35,16 @@ public: void stop(); - virtual void OnTerminate(int pid, int status) = 0; +protected: + virtual void OnStateChange() = 0; virtual void OnRead(std::string s) = 0; -protected: +private: std::unique_ptr process = std::make_unique(*this); -private: + void OnTerminateInternal(int pid, int status); + DhfsInstanceState _state = DhfsInstanceState::STOPPED; std::thread _readThread; std::thread _readThreadErr; diff --git a/launcher/backend/src/DhfsInstance.cpp b/launcher/backend/src/DhfsInstance.cpp index 4fae6686..d63a82cb 100644 --- a/launcher/backend/src/DhfsInstance.cpp +++ b/launcher/backend/src/DhfsInstance.cpp @@ -25,13 +25,17 @@ void DhfsInstance::start(DhfsStartOptions options) { std::lock_guard lock(_mutex); switch (_state) { case DhfsInstanceState::RUNNING: + case DhfsInstanceState::STARTING: + case DhfsInstanceState::STOPPING: return; case DhfsInstanceState::STOPPED: break; default: throw std::runtime_error("Unknown DhfsInstanceState"); } - _state = DhfsInstanceState::RUNNING; + + _state = DhfsInstanceState::STARTING; + OnStateChange(); std::vector args; auto readyOptions = options.getOptions(); @@ -46,18 +50,36 @@ void DhfsInstance::start(DhfsStartOptions options) { throw Exception("Failed to start DHFS"); } - OnRead("Started! " + std::to_string(ret) + " PID: " + std::to_string(process->GetPid()) + "\n"); + OnRead("Started! PID: " + std::to_string(process->GetPid()) + "\n"); _readThread = std::thread([&]() { auto stream = process->GetInputStream(); + + bool searching = true; + std::string lastLine; + while (!stream->Eof() || stream->CanRead()) { char buffer[1024]; size_t bytesRead = stream->Read(buffer, sizeof(buffer) - 1).LastRead(); if (bytesRead > 0) { - buffer[bytesRead] = '\0'; // Null-terminate the string + buffer[bytesRead] = '\0'; + if (searching) { + for (size_t i = 0; i < bytesRead; i++) { + lastLine += buffer[i]; + if (buffer[i] == '\n') { + if (lastLine.find("Listening on:") != std::string::npos) { + searching = false; + std::lock_guard lock(_mutex); + if (_state == DhfsInstanceState::STARTING) { + _state = DhfsInstanceState::RUNNING; + OnStateChange(); + } + } + lastLine = ""; + } + } + } OnRead(std::string(buffer)); - } else if (bytesRead == 0) { - break; // EOF reached } } }); @@ -67,10 +89,8 @@ void DhfsInstance::start(DhfsStartOptions options) { char buffer[1024]; size_t bytesRead = stream->Read(buffer, sizeof(buffer) - 1).LastRead(); if (bytesRead > 0) { - buffer[bytesRead] = '\0'; // Null-terminate the string + buffer[bytesRead] = '\0'; OnRead(std::string(buffer)); - } else if (bytesRead == 0) { - break; // EOF reached } } }); @@ -80,21 +100,30 @@ void DhfsInstance::stop() { std::lock_guard lock(_mutex); switch (_state) { case DhfsInstanceState::RUNNING: + case DhfsInstanceState::STARTING: break; case DhfsInstanceState::STOPPED: + case DhfsInstanceState::STOPPING: return; default: throw std::runtime_error("Unknown DhfsInstanceState"); } - _state = DhfsInstanceState::STOPPED; + _state = DhfsInstanceState::STOPPING; + OnStateChange(); int err = wxProcess::Kill(process->GetPid(), wxSIGTERM, wxKILL_CHILDREN); - _readThread.join(); - _readThreadErr.join(); - OnRead("Stopped!\n"); if (err != wxKILL_OK) { OnRead("Failed to stop DHFS: " + std::to_string(err) + "\n"); } - OnTerminate(0, 0); +} + +void DhfsInstance::OnTerminateInternal(int pid, int status) { + std::lock_guard lock(_mutex); + _state = DhfsInstanceState::STOPPED; + + _readThread.join(); + _readThreadErr.join(); + OnRead("Stopped!\n"); + OnStateChange(); } diff --git a/launcher/backend/src/DhfsWxProcess.cpp b/launcher/backend/src/DhfsWxProcess.cpp index d4b92eb2..8a28ba14 100644 --- a/launcher/backend/src/DhfsWxProcess.cpp +++ b/launcher/backend/src/DhfsWxProcess.cpp @@ -10,5 +10,5 @@ DhfsWxProcess::DhfsWxProcess(DhfsInstance& parent): wxProcess(wxPROCESS_REDIRECT } void DhfsWxProcess::OnTerminate(int pid, int status) { - _instance.stop(); + _instance.OnTerminateInternal(pid, status); } diff --git a/launcher/gui/src/DhfsGuiInstance.cpp b/launcher/gui/src/DhfsGuiInstance.cpp index 0b97a9b8..995fa44f 100644 --- a/launcher/gui/src/DhfsGuiInstance.cpp +++ b/launcher/gui/src/DhfsGuiInstance.cpp @@ -9,8 +9,8 @@ DhfsGuiInstance::DhfsGuiInstance(LauncherAppMainFrame& parent): _parent(parent) { } -void DhfsGuiInstance::OnTerminate(int pid, int status) { - wxCommandEvent* event = new wxCommandEvent(SHUTDOWN_EVENT, _parent.GetId()); +void DhfsGuiInstance::OnStateChange() { + wxCommandEvent* event = new wxCommandEvent(DHFS_STATE_CHANGE_EVENT, _parent.GetId()); event->SetEventObject(&_parent); _parent.GetEventHandler()->QueueEvent(event); } diff --git a/launcher/gui/src/DhfsGuiInstance.hpp b/launcher/gui/src/DhfsGuiInstance.hpp index e2e385ce..2a809b8d 100644 --- a/launcher/gui/src/DhfsGuiInstance.hpp +++ b/launcher/gui/src/DhfsGuiInstance.hpp @@ -13,7 +13,7 @@ class DhfsGuiInstance : public DhfsInstance { public: DhfsGuiInstance(LauncherAppMainFrame& parent); - void OnTerminate(int pid, int status) override; + void OnStateChange() override; void OnRead(std::string s) override; diff --git a/launcher/gui/src/LauncherAppMainFrame.cpp b/launcher/gui/src/LauncherAppMainFrame.cpp index 9c273acb..7d06ec84 100644 --- a/launcher/gui/src/LauncherAppMainFrame.cpp +++ b/launcher/gui/src/LauncherAppMainFrame.cpp @@ -6,7 +6,7 @@ #include "Exception.h" wxDEFINE_EVENT(NEW_LINE_OUTPUT_EVENT, wxCommandEvent); -wxDEFINE_EVENT(SHUTDOWN_EVENT, wxCommandEvent); +wxDEFINE_EVENT(DHFS_STATE_CHANGE_EVENT, wxCommandEvent); LauncherAppMainFrame::LauncherAppMainFrame(wxWindow* parent) : MainFrame(parent) { @@ -20,7 +20,7 @@ LauncherAppMainFrame::LauncherAppMainFrame(wxWindow* parent) m_webViewSizer->Fit(m_panel5); Bind(NEW_LINE_OUTPUT_EVENT, &LauncherAppMainFrame::onNewLineOutput, this); - Bind(SHUTDOWN_EVENT, &LauncherAppMainFrame::onShutdown, this); + Bind(DHFS_STATE_CHANGE_EVENT, &LauncherAppMainFrame::onShutdown, this); wxFont font = wxFont(wxSize(16, 16), wxFontFamily::wxFONTFAMILY_TELETYPE, wxFontStyle::wxFONTSTYLE_NORMAL, @@ -36,12 +36,24 @@ void LauncherAppMainFrame::updateState() { m_startStopButton->SetLabel("Stop"); m_statusBar1->SetStatusText("Running", 0); break; + case DhfsInstanceState::STARTING: { + m_statusText->SetLabel("Starting"); + m_startStopButton->SetLabel("Stop"); + m_statusBar1->SetStatusText("Starting", 0); + break; + } case DhfsInstanceState::STOPPED: { m_statusText->SetLabel("Stopped"); m_startStopButton->SetLabel("Start"); m_statusBar1->SetStatusText("Stopped", 0); break; } + case DhfsInstanceState::STOPPING: { + m_statusText->SetLabel("Stopping"); + m_startStopButton->SetLabel("Kill"); + m_statusBar1->SetStatusText("Stopping", 0); + break; + } default: throw Exception("Unhandled switch case"); } @@ -50,8 +62,10 @@ void LauncherAppMainFrame::updateState() { void LauncherAppMainFrame::OnStartStopButtonClick(wxCommandEvent& event) { switch (_dhfsInstance.state()) { case DhfsInstanceState::RUNNING: + case DhfsInstanceState::STARTING: { _dhfsInstance.stop(); break; + } case DhfsInstanceState::STOPPED: { DhfsStartOptions options; options.java_home = wxFileConfig::Get()->Read(kJavaHomeSettingsKey); @@ -65,6 +79,10 @@ void LauncherAppMainFrame::OnStartStopButtonClick(wxCommandEvent& event) { _dhfsInstance.start(options); break; } + case DhfsInstanceState::STOPPING: { + // TODO: + break; + } default: throw Exception("Unhandled switch case"); } diff --git a/launcher/gui/src/LauncherAppMainFrame.h b/launcher/gui/src/LauncherAppMainFrame.h index f38c7c52..28fe52e9 100644 --- a/launcher/gui/src/LauncherAppMainFrame.h +++ b/launcher/gui/src/LauncherAppMainFrame.h @@ -19,7 +19,7 @@ static constexpr auto kMountPointSettingsKey = "DHFS/MountDir"; static constexpr auto kDataDirSettingsKey = "DHFS/DataDir"; wxDECLARE_EVENT(NEW_LINE_OUTPUT_EVENT, wxCommandEvent); -wxDECLARE_EVENT(SHUTDOWN_EVENT, wxCommandEvent); +wxDECLARE_EVENT(DHFS_STATE_CHANGE_EVENT, wxCommandEvent); /** Implementing MainFrame */ class LauncherAppMainFrame : public MainFrame {