From a3240426952aac2b03c99f0ebba7fe3e9ed35561 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Mon, 11 Apr 2022 14:55:22 +0200 Subject: [PATCH] Use custom process library for notifications Instead of using Boost.Process here. Last usage of Boost.Process is for launching the child process. --- src/common/process.cpp | 24 +++++++++++++++++++++++- src/common/process.h | 9 ++++++++- src/plugin/utils.cpp | 37 +++++++++++++++++-------------------- 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/common/process.cpp b/src/common/process.cpp index c8fa8013..6c5950e2 100644 --- a/src/common/process.cpp +++ b/src/common/process.cpp @@ -115,7 +115,7 @@ std::optional Process::Handle::wait() const noexcept { Process::Process(std::string command) : command_(command) {} -Process::StringResult Process::spawn_get_stdout_line() { +Process::StringResult Process::spawn_get_stdout_line() const { /// We'll read the results from a pipe. The child writes to the second pipe, /// we'll read from the first one. int output_pipe[2]; @@ -167,6 +167,28 @@ Process::StringResult Process::spawn_get_stdout_line() { } } +Process::StatusResult Process::spawn_get_status() const { + const auto argv = build_argv(); + const auto envp = env_ ? env_->make_environ() : environ; + + pid_t child_pid = 0; + const auto result = posix_spawnp(&child_pid, command_.c_str(), nullptr, + nullptr, argv, envp); + if (result == 2) { + return Process::CommandNotFound{}; + } else if (result != 0) { + return std::error_code(result, std::system_category()); + } + + int status = 0; + assert(waitpid(child_pid, &status, 0) > 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) == 127) { + return Process::CommandNotFound{}; + } else { + return WEXITSTATUS(status); + } +} + char* const* Process::build_argv() const { argv_.clear(); diff --git a/src/common/process.h b/src/common/process.h index 66dac02f..1b30b602 100644 --- a/src/common/process.h +++ b/src/common/process.h @@ -164,7 +164,14 @@ class Process { * non-zero exit code. Uses `posix_spawn()`, leaves file descriptors in * tact. */ - StringResult spawn_get_stdout_line(); + StringResult spawn_get_stdout_line() const; + + /** + * Spawn the process, leave STDOUT, STDIN and STDERR alone, and return an + * empty string if the program ran successfully. Uses `posix_spawn()`, + * leaves file descriptors in tact. + */ + StatusResult spawn_get_status() const; private: /** diff --git a/src/plugin/utils.cpp b/src/plugin/utils.cpp index 6719c8d8..bfce1221 100644 --- a/src/plugin/utils.cpp +++ b/src/plugin/utils.cpp @@ -132,7 +132,7 @@ std::string PluginInfo::wine_version() const { process.arg("--version"); process.environment(create_host_env_2()); - auto result = process.spawn_get_stdout_line(); + const auto result = process.spawn_get_stdout_line(); return std::visit( overload{ [](std::string version_string) -> std::string { @@ -462,13 +462,6 @@ Configuration load_config_for(const fs::path& yabridge_path) { bool send_notification(const std::string& title, const std::string body, bool append_origin) { - // FIXME: Replace Boost.Filesystem - const boost::filesystem::path notify_send_path = - bp::search_path("notify-send"); - if (notify_send_path.empty()) { - return false; - } - // I think there's a zero chance that we're going to call this function with // anything that even somewhat resembles HTML, but we should still do a // basic XML escape anyways. @@ -493,16 +486,20 @@ bool send_notification(const std::string& title, } } - // TODO: Also use a custom process here, and wrap the above code in a - // class - try { - return bp::system(notify_send_path, "--urgency=normal", - "--expire-time=15000", "--app-name=yabridge", title, - formatted_body.str(), - bp::posix::use_vfork) == EXIT_SUCCESS; - } catch (const boost::process::process_error&) { - // We will have printed the message to the terminal anyways, so if the - // user doesn't have libnotify installed we'll just fail silently - return false; - } + Process process("notify-send"); + process.arg("--urgency=normal"); + process.arg("--app-name=yabridge"); + process.arg(title); + process.arg(formatted_body.str()); + + // We will have printed the message to the terminal anyways, so if the user + // doesn't have libnotify installed we'll just fail silently + const auto result = process.spawn_get_status(); + return std::visit( + overload{ + [](int status) -> bool { return status == EXIT_SUCCESS; }, + [](const Process::CommandNotFound&) -> bool { return false; }, + [](const std::error_code&) -> bool { return false; }, + }, + result); }