diff --git a/include/ArcadeProcess.h b/include/ArcadeProcess.h new file mode 100644 index 0000000..714be49 --- /dev/null +++ b/include/ArcadeProcess.h @@ -0,0 +1,27 @@ +#ifndef ARCADE_MACHINE_PROCESS_H +#define ARCADE_MACHINE_PROCESS_H + +#include +#include +#include +#include +#include +#include + +class ArcadeProcess { + private: + std::string _command; + std::vector _args; + std::thread _execution_context; + bool _is_running = false; + void _execute_async_thread(); + + public: + std::vector output_stream; + ArcadeProcess(std::string command, std::vector args); + bool is_running() const { return this->_is_running; } + std::string execute_sync(); + void execute_async(); +}; + +#endif \ No newline at end of file diff --git a/include/ConfigData.h b/include/ConfigData.h index 9e96deb..32d87f1 100644 --- a/include/ConfigData.h +++ b/include/ConfigData.h @@ -3,6 +3,8 @@ #include #include +#include +#include #include "splashkit.h" /** @@ -77,4 +79,4 @@ class ConfigData }; -#endif \ No newline at end of file +#endif diff --git a/src/ArcadeProcess.cpp b/src/ArcadeProcess.cpp new file mode 100644 index 0000000..288c593 --- /dev/null +++ b/src/ArcadeProcess.cpp @@ -0,0 +1,73 @@ +#include "ArcadeProcess.h" + +#include +#include +#include +#include +#include + + +void ArcadeProcess::_execute_async_thread() { + // Don't allow duplicate threads to execute. + if (this->_is_running) + return; + + std::string command = std::string(this->_command); + for (auto arg : this->_args) + command.append(" " + arg); + + this->_is_running = true; + auto pipe = popen(command.c_str(), "r"); + if (! pipe) + throw std::runtime_error("Error running process (async) `" + command + "`"); + + std::array buffer; + while (! feof(pipe)) { + if (fgets(buffer.data(), 256, pipe) != nullptr) + this->output_stream.push_back(buffer.data()); + } + + if (pclose(pipe) != EXIT_SUCCESS) + std::cerr << "Unable to close process (async), possible memory leak" << std::endl; + + this->_is_running = false; +} + +ArcadeProcess::ArcadeProcess(std::string command, std::vector args) { + this->_command = command; + this->_args = args; + this->output_stream = std::vector(); +} + +std::string ArcadeProcess::execute_sync() { + // This should never happen, but you never know... + if (this->_is_running) + throw std::runtime_error("Instance of process is already running."); + + std::string command = std::string(this->_command); + for (auto arg : this->_args) + command.append(" " + arg); + + this->_is_running = true; + auto pipe = popen(command.c_str(), "r"); + if (! pipe) + throw std::runtime_error("Error running process `" + command + "`"); + + std::array buffer; + std::string str_buffer; + while (! feof(pipe)) { + if (fgets(buffer.data(), 256, pipe) != nullptr) + str_buffer += buffer.data(); + } + + if (pclose(pipe) != EXIT_SUCCESS) + std::cerr << "Unable to close process, possible memory leak" << std::endl; + + this->_is_running = false; + return str_buffer; +} + +void ArcadeProcess::execute_async() { + this->_execution_context = std::thread(&ArcadeProcess::_execute_async_thread, this); + this->_execution_context.detach(); +}