Separate worker thread into util class
parent
6eb9606f23
commit
ccdc9b8e0b
|
@ -1,27 +1,28 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "ALabel.hpp"
|
#include "ALabel.hpp"
|
||||||
#include "util/command.hpp"
|
#include "util/command.hpp"
|
||||||
#include "util/json.hpp"
|
#include "util/json.hpp"
|
||||||
#include "util/sleeper_thread.hpp"
|
#include "util/worker_thread.hpp"
|
||||||
|
|
||||||
namespace waybar::modules {
|
namespace waybar::modules {
|
||||||
|
|
||||||
class Custom : public ALabel {
|
class Custom : public ALabel {
|
||||||
public:
|
public:
|
||||||
Custom(const std::string&, const std::string&, const Json::Value&);
|
Custom(const std::string&, const std::string&, const Json::Value&);
|
||||||
~Custom();
|
|
||||||
auto update() -> void;
|
auto update() -> void;
|
||||||
void refresh(int /*signal*/);
|
void refresh(int /*signal*/);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void delayWorker();
|
void workerExitCallback(int);
|
||||||
void continuousWorker();
|
void workerOutputCallback(std::string);
|
||||||
void parseOutputRaw();
|
void parseOutputRaw(const std::string&);
|
||||||
void parseOutputJson();
|
void parseOutputJson(const std::string&);
|
||||||
void handleEvent();
|
void handleEvent();
|
||||||
bool handleScroll(GdkEventScroll* e);
|
bool handleScroll(GdkEventScroll* e);
|
||||||
bool handleToggle(GdkEventButton* const& e);
|
bool handleToggle(GdkEventButton* const& e);
|
||||||
|
@ -32,12 +33,10 @@ class Custom : public ALabel {
|
||||||
std::string tooltip_;
|
std::string tooltip_;
|
||||||
std::vector<std::string> class_;
|
std::vector<std::string> class_;
|
||||||
int percentage_;
|
int percentage_;
|
||||||
FILE* fp_;
|
|
||||||
int pid_;
|
|
||||||
util::command::res output_;
|
util::command::res output_;
|
||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
|
|
||||||
util::SleeperThread thread_;
|
waybar::util::WorkerThread thread_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules
|
} // namespace waybar::modules
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "util/command.hpp"
|
||||||
|
#include "util/sleeper_thread.hpp"
|
||||||
|
|
||||||
|
namespace waybar::util {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a child process and reads output from it, providing it to
|
||||||
|
* the callbacks.
|
||||||
|
*/
|
||||||
|
class WorkerThread {
|
||||||
|
public:
|
||||||
|
WorkerThread() : pid_(-1) {}
|
||||||
|
|
||||||
|
WorkerThread(const Json::Value& config, std::function<void(std::string)> output_callback,
|
||||||
|
std::function<void(int)> exit_callback)
|
||||||
|
: output_callback_(output_callback), exit_callback_(exit_callback), pid_(-1) {
|
||||||
|
if (config["exec"].isString()) {
|
||||||
|
exec_ = config["exec"].asString();
|
||||||
|
}
|
||||||
|
if (config["exec_if"].isString()) {
|
||||||
|
exec_if_ = config["exec_if"].asString();
|
||||||
|
}
|
||||||
|
if (config["interval"].isUInt()) {
|
||||||
|
interval_ = std::chrono::seconds(config["interval"].asUInt());
|
||||||
|
} else if (config["interval"] == "once") {
|
||||||
|
interval_ = std::chrono::seconds(100000000);
|
||||||
|
} else {
|
||||||
|
interval_ = std::chrono::seconds(0);
|
||||||
|
}
|
||||||
|
if (config["restart-interval"].isUInt()) {
|
||||||
|
restart_interval_ = std::chrono::seconds(config["restart-interval"].asUInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interval_.count() > 0) {
|
||||||
|
thread_ = [this] { delay_worker(); };
|
||||||
|
} else if (!exec_.empty()) {
|
||||||
|
thread_ = [this] { continuous_worker(); };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~WorkerThread() {
|
||||||
|
if (pid_ != -1) {
|
||||||
|
killpg(pid_, SIGTERM);
|
||||||
|
pid_ = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto wake_up() { return thread_.wake_up(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void delay_worker() {
|
||||||
|
bool can_update = true;
|
||||||
|
if (!exec_if_.empty()) {
|
||||||
|
util::command::res output = util::command::execNoRead(exec_if_);
|
||||||
|
if (output.exit_code != 0) {
|
||||||
|
can_update = false;
|
||||||
|
exit_callback_(output.exit_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (can_update) {
|
||||||
|
if (!exec_.empty()) {
|
||||||
|
util::command::res output = util::command::exec(exec_);
|
||||||
|
if (output.exit_code == 0) {
|
||||||
|
output_callback_(std::move(output.out));
|
||||||
|
} else {
|
||||||
|
exit_callback_(output.exit_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thread_.sleep_for(interval_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void continuous_worker() {
|
||||||
|
pid_ = -1;
|
||||||
|
FILE* fp = util::command::open(exec_, pid_);
|
||||||
|
if (!fp) {
|
||||||
|
throw std::runtime_error("Unable to open " + exec_);
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
char* buff = nullptr;
|
||||||
|
size_t len = 0;
|
||||||
|
if (getline(&buff, &len, fp) == -1) {
|
||||||
|
int exit_code = 1;
|
||||||
|
if (fp) {
|
||||||
|
exit_code = WEXITSTATUS(util::command::close(fp, pid_));
|
||||||
|
fp = nullptr;
|
||||||
|
}
|
||||||
|
if (exit_code != 0) {
|
||||||
|
spdlog::error("'{}' stopped unexpectedly, is it endless?", exec_);
|
||||||
|
exit_callback_(exit_code);
|
||||||
|
}
|
||||||
|
if (restart_interval_.has_value()) {
|
||||||
|
pid_ = -1;
|
||||||
|
thread_.sleep_for(std::chrono::seconds(*restart_interval_));
|
||||||
|
fp = util::command::open(exec_, pid_);
|
||||||
|
if (!fp) {
|
||||||
|
throw std::runtime_error("Unable to open " + exec_);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread_.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::string output = buff;
|
||||||
|
|
||||||
|
// Remove last newline
|
||||||
|
if (!output.empty() && output[output.length() - 1] == '\n') {
|
||||||
|
output.erase(output.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
output_callback_(std::move(output));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string exec_;
|
||||||
|
std::string exec_if_;
|
||||||
|
std::chrono::seconds interval_;
|
||||||
|
std::optional<std::chrono::seconds> restart_interval_;
|
||||||
|
std::function<void(std::string)> output_callback_;
|
||||||
|
std::function<void(int)> exit_callback_;
|
||||||
|
int pid_;
|
||||||
|
SleeperThread thread_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::util
|
|
@ -4,85 +4,22 @@
|
||||||
|
|
||||||
waybar::modules::Custom::Custom(const std::string& name, const std::string& id,
|
waybar::modules::Custom::Custom(const std::string& name, const std::string& id,
|
||||||
const Json::Value& config)
|
const Json::Value& config)
|
||||||
: ALabel(config, "custom-" + name, id, "{}"), name_(name), fp_(nullptr), pid_(-1) {
|
: ALabel(config, "custom-" + name, id, "{}"),
|
||||||
|
name_(name),
|
||||||
|
thread_(
|
||||||
|
config, [this](std::string output) { workerOutputCallback(std::move(output)); },
|
||||||
|
[this](int exit_code) { workerExitCallback(exit_code); }) {
|
||||||
dp.emit();
|
dp.emit();
|
||||||
if (interval_.count() > 0) {
|
|
||||||
delayWorker();
|
|
||||||
} else if (config_["exec"].isString()) {
|
|
||||||
continuousWorker();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
waybar::modules::Custom::~Custom() {
|
void waybar::modules::Custom::workerExitCallback(int exit_code) {
|
||||||
if (pid_ != -1) {
|
output_ = {exit_code, ""};
|
||||||
killpg(pid_, SIGTERM);
|
dp.emit();
|
||||||
pid_ = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Custom::delayWorker() {
|
void waybar::modules::Custom::workerOutputCallback(std::string output) {
|
||||||
thread_ = [this] {
|
output_ = {0, std::move(output)};
|
||||||
bool can_update = true;
|
dp.emit();
|
||||||
if (config_["exec-if"].isString()) {
|
|
||||||
output_ = util::command::execNoRead(config_["exec-if"].asString());
|
|
||||||
if (output_.exit_code != 0) {
|
|
||||||
can_update = false;
|
|
||||||
dp.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (can_update) {
|
|
||||||
if (config_["exec"].isString()) {
|
|
||||||
output_ = util::command::exec(config_["exec"].asString());
|
|
||||||
}
|
|
||||||
dp.emit();
|
|
||||||
}
|
|
||||||
thread_.sleep_for(interval_);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void waybar::modules::Custom::continuousWorker() {
|
|
||||||
auto cmd = config_["exec"].asString();
|
|
||||||
pid_ = -1;
|
|
||||||
fp_ = util::command::open(cmd, pid_);
|
|
||||||
if (!fp_) {
|
|
||||||
throw std::runtime_error("Unable to open " + cmd);
|
|
||||||
}
|
|
||||||
thread_ = [this, cmd] {
|
|
||||||
char* buff = nullptr;
|
|
||||||
size_t len = 0;
|
|
||||||
if (getline(&buff, &len, fp_) == -1) {
|
|
||||||
int exit_code = 1;
|
|
||||||
if (fp_) {
|
|
||||||
exit_code = WEXITSTATUS(util::command::close(fp_, pid_));
|
|
||||||
fp_ = nullptr;
|
|
||||||
}
|
|
||||||
if (exit_code != 0) {
|
|
||||||
output_ = {exit_code, ""};
|
|
||||||
dp.emit();
|
|
||||||
spdlog::error("{} stopped unexpectedly, is it endless?", name_);
|
|
||||||
}
|
|
||||||
if (config_["restart-interval"].isUInt()) {
|
|
||||||
pid_ = -1;
|
|
||||||
thread_.sleep_for(std::chrono::seconds(config_["restart-interval"].asUInt()));
|
|
||||||
fp_ = util::command::open(cmd, pid_);
|
|
||||||
if (!fp_) {
|
|
||||||
throw std::runtime_error("Unable to open " + cmd);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
thread_.stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::string output = buff;
|
|
||||||
|
|
||||||
// Remove last newline
|
|
||||||
if (!output.empty() && output[output.length() - 1] == '\n') {
|
|
||||||
output.erase(output.length() - 1);
|
|
||||||
}
|
|
||||||
output_ = {0, output};
|
|
||||||
dp.emit();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Custom::refresh(int sig) {
|
void waybar::modules::Custom::refresh(int sig) {
|
||||||
|
@ -116,9 +53,9 @@ auto waybar::modules::Custom::update() -> void {
|
||||||
event_box_.hide();
|
event_box_.hide();
|
||||||
} else {
|
} else {
|
||||||
if (config_["return-type"].asString() == "json") {
|
if (config_["return-type"].asString() == "json") {
|
||||||
parseOutputJson();
|
parseOutputJson(output_.out);
|
||||||
} else {
|
} else {
|
||||||
parseOutputRaw();
|
parseOutputRaw(output_.out);
|
||||||
}
|
}
|
||||||
auto str = fmt::format(format_,
|
auto str = fmt::format(format_,
|
||||||
text_,
|
text_,
|
||||||
|
@ -154,8 +91,8 @@ auto waybar::modules::Custom::update() -> void {
|
||||||
ALabel::update();
|
ALabel::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Custom::parseOutputRaw() {
|
void waybar::modules::Custom::parseOutputRaw(const std::string& output_str) {
|
||||||
std::istringstream output(output_.out);
|
std::istringstream output(output_str);
|
||||||
std::string line;
|
std::string line;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (getline(output, line)) {
|
while (getline(output, line)) {
|
||||||
|
@ -178,8 +115,8 @@ void waybar::modules::Custom::parseOutputRaw() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Custom::parseOutputJson() {
|
void waybar::modules::Custom::parseOutputJson(const std::string& output_str) {
|
||||||
std::istringstream output(output_.out);
|
std::istringstream output(output_str);
|
||||||
std::string line;
|
std::string line;
|
||||||
class_.clear();
|
class_.clear();
|
||||||
while (getline(output, line)) {
|
while (getline(output, line)) {
|
||||||
|
|
Loading…
Reference in New Issue