wip: Inter-process messaging
This commit is contained in:
parent
c480f6fd1e
commit
489f3ce480
@ -79,5 +79,7 @@ set(SETTING_PATH_MEMORY_INFO "/proc/meminfo"
|
||||
CACHE STRING "Path to file containing memory info")
|
||||
set(SETTING_PATH_TEMPERATURE_INFO "/sys/class/thermal/thermal_zone%zone%/temp"
|
||||
CACHE STRING "Path to file containing the current temperature")
|
||||
set(SETTING_PATH_MESSAGING_FIFO "/tmp/lemonbuddy_mqueue.%pid%"
|
||||
CACHE STRING "Path to file containing the current temperature")
|
||||
|
||||
# }}}
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include "components/bar.hpp"
|
||||
#include "components/config.hpp"
|
||||
#include "components/eventloop.hpp"
|
||||
#include "components/ipc.hpp"
|
||||
#include "components/logger.hpp"
|
||||
#include "components/signals.hpp"
|
||||
#include "config.hpp"
|
||||
#include "utils/command.hpp"
|
||||
#include "utils/inotify.hpp"
|
||||
@ -17,12 +17,13 @@ LEMONBUDDY_NS
|
||||
class controller {
|
||||
public:
|
||||
explicit controller(connection& conn, const logger& logger, const config& config, unique_ptr<eventloop> eventloop,
|
||||
unique_ptr<bar> bar, inotify_util::watch_t& confwatch)
|
||||
unique_ptr<bar> bar, unique_ptr<ipc> ipc, inotify_util::watch_t& confwatch)
|
||||
: m_connection(conn)
|
||||
, m_log(logger)
|
||||
, m_conf(config)
|
||||
, m_eventloop(forward<decltype(eventloop)>(eventloop))
|
||||
, m_bar(forward<decltype(bar)>(bar))
|
||||
, m_ipc(forward<decltype(ipc)>(ipc))
|
||||
, m_confwatch(confwatch) {}
|
||||
|
||||
~controller();
|
||||
@ -53,6 +54,7 @@ class controller {
|
||||
const config& m_conf;
|
||||
unique_ptr<eventloop> m_eventloop;
|
||||
unique_ptr<bar> m_bar;
|
||||
unique_ptr<ipc> m_ipc;
|
||||
|
||||
stateflag m_running{false};
|
||||
stateflag m_reload{false};
|
||||
@ -67,7 +69,7 @@ class controller {
|
||||
inotify_util::watch_t& m_confwatch;
|
||||
command_util::command_t m_command;
|
||||
|
||||
bool m_writeback = false;
|
||||
bool m_writeback{false};
|
||||
};
|
||||
|
||||
namespace {
|
||||
@ -83,7 +85,8 @@ namespace {
|
||||
configure_logger(),
|
||||
configure_config(),
|
||||
configure_eventloop(),
|
||||
configure_bar());
|
||||
configure_bar(),
|
||||
configure_ipc());
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
|
54
include/components/ipc.hpp
Normal file
54
include/components/ipc.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
#include "components/logger.hpp"
|
||||
|
||||
LEMONBUDDY_NS
|
||||
|
||||
/**
|
||||
* Component used for inter-process communication.
|
||||
*
|
||||
* A unique messaging channel will be setup for each
|
||||
* running process which will allow messages and
|
||||
* events to be sent to the process externally.
|
||||
*/
|
||||
class ipc {
|
||||
public:
|
||||
struct message_internal {
|
||||
static constexpr auto prefix{"app:"};
|
||||
};
|
||||
struct message_command {
|
||||
static constexpr auto prefix{"cmd:"};
|
||||
};
|
||||
struct message_custom {
|
||||
static constexpr auto prefix{"custom:"};
|
||||
};
|
||||
|
||||
explicit ipc(const logger& logger) : m_log(logger) {}
|
||||
~ipc();
|
||||
|
||||
void receive_messages();
|
||||
|
||||
protected:
|
||||
void parse(string payload);
|
||||
|
||||
private:
|
||||
const logger& m_log;
|
||||
|
||||
stateflag m_running{false};
|
||||
|
||||
string m_fifo;
|
||||
int m_fd;
|
||||
};
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Configure injection module
|
||||
*/
|
||||
template <typename T = unique_ptr<ipc>>
|
||||
di::injector<T> configure_ipc() {
|
||||
return di::make_injector(configure_logger());
|
||||
}
|
||||
}
|
||||
|
||||
LEMONBUDDY_NS_END
|
@ -39,6 +39,7 @@
|
||||
#define PATH_CPU_INFO "@SETTING_PATH_CPU_INFO@"
|
||||
#define PATH_MEMORY_INFO "@SETTING_PATH_MEMORY_INFO@"
|
||||
#define PATH_TEMPERATURE_INFO "@SETTING_PATH_TEMPERATURE_INFO@"
|
||||
#define PATH_MESSAGING_FIFO "@SETTING_PATH_MESSAGING_FIFO@"
|
||||
|
||||
auto print_build_info = []() {
|
||||
// clang-format off
|
||||
|
@ -2,6 +2,12 @@
|
||||
#include <mutex>
|
||||
|
||||
#include "components/controller.hpp"
|
||||
|
||||
#include "components/bar.hpp"
|
||||
#include "components/config.hpp"
|
||||
#include "components/eventloop.hpp"
|
||||
#include "components/ipc.hpp"
|
||||
#include "components/logger.hpp"
|
||||
#include "components/signals.hpp"
|
||||
#include "modules/backlight.hpp"
|
||||
#include "modules/battery.hpp"
|
||||
@ -56,6 +62,11 @@ controller::~controller() {
|
||||
m_eventloop.reset();
|
||||
}
|
||||
|
||||
if (m_ipc) {
|
||||
m_log.info("Deconstructing ipc");
|
||||
m_ipc.reset();
|
||||
}
|
||||
|
||||
if (m_bar) {
|
||||
m_log.info("Deconstructing bar");
|
||||
m_bar.reset();
|
||||
@ -94,30 +105,23 @@ void controller::bootstrap(bool writeback, bool dump_wmname) {
|
||||
// Listen for events on the root window to be able to
|
||||
// break the blocking wait call when cleaning up
|
||||
m_log.trace("controller: Listen for events on the root window");
|
||||
try {
|
||||
const uint32_t value_list[2]{XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY};
|
||||
m_connection.change_window_attributes_checked(m_connection.root(), XCB_CW_EVENT_MASK, value_list);
|
||||
} catch (const exception& err) {
|
||||
throw application_error("Failed to change root window event mask: " + string{err.what()});
|
||||
}
|
||||
|
||||
try {
|
||||
m_log.trace("controller: Setup bar");
|
||||
m_bar->bootstrap(m_writeback || dump_wmname);
|
||||
m_bar->bootstrap_tray();
|
||||
} catch (const exception& err) {
|
||||
throw application_error("Failed to setup bar renderer: " + string{err.what()});
|
||||
}
|
||||
|
||||
if (dump_wmname) {
|
||||
std::cout << m_bar->settings().wmname << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_log.trace("controller: Attach eventloop callbacks");
|
||||
m_log.trace("controller: Attach eventloop update callback");
|
||||
m_eventloop->set_update_cb(bind(&controller::on_update, this));
|
||||
|
||||
if (!m_writeback) {
|
||||
m_log.trace("controller: Attach eventloop input callback");
|
||||
g_signals::bar::action_click = bind(&controller::on_mouse_event, this, placeholders::_1);
|
||||
m_eventloop->set_input_db(bind(&controller::on_unrecognized_action, this, placeholders::_1));
|
||||
}
|
||||
@ -138,6 +142,11 @@ bool controller::run() {
|
||||
install_sigmask();
|
||||
install_confwatch();
|
||||
|
||||
#if DEBUG
|
||||
// Start listening for ipc messages
|
||||
m_threads.emplace_back(thread(&ipc::receive_messages, m_ipc.get()));
|
||||
#endif
|
||||
|
||||
// Listen for X events in separate thread
|
||||
if (!m_writeback) {
|
||||
m_threads.emplace_back(thread(&controller::wait_for_xevent, this));
|
||||
|
67
src/components/ipc.cpp
Normal file
67
src/components/ipc.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "components/ipc.hpp"
|
||||
#include "config.hpp"
|
||||
#include "utils/file.hpp"
|
||||
#include "utils/io.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
LEMONBUDDY_NS
|
||||
|
||||
/**
|
||||
* Interrupt the blocked listener and
|
||||
* remove the file handler
|
||||
*/
|
||||
ipc::~ipc() {
|
||||
m_running = false;
|
||||
|
||||
if (!m_fifo.empty()) {
|
||||
m_log.info("Interrupting ipc message receiver");
|
||||
|
||||
auto f{make_unique<file_util::file_ptr>(m_fifo)};
|
||||
char p[1]{'q'};
|
||||
|
||||
fwrite(p, sizeof(char), sizeof(p), (*f)());
|
||||
unlink(m_fifo.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start listening for event messages
|
||||
*/
|
||||
void ipc::receive_messages() {
|
||||
m_running = true;
|
||||
m_fifo = string_util::replace(PATH_MESSAGING_FIFO, "%pid%", to_string(getpid()));
|
||||
|
||||
if (mkfifo(m_fifo.c_str(), 0666) == -1) {
|
||||
m_log.err("Failed to create messaging channel");
|
||||
}
|
||||
|
||||
m_log.info("Listening for ipc messages on: %s", m_fifo);
|
||||
|
||||
while ((m_fd = open(m_fifo.c_str(), O_RDONLY)) != -1 && m_running) {
|
||||
parse(io_util::readline(m_fd));
|
||||
close(m_fd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process received message and delegate
|
||||
* valid events to the target modules
|
||||
*/
|
||||
void ipc::parse(string payload) {
|
||||
if (payload.empty()) {
|
||||
return;
|
||||
} else if (payload.find(message_internal::prefix) == 0) {
|
||||
m_log.info("Received internal message: (payload=%s)", payload);
|
||||
} else if (payload.find(message_command::prefix) == 0) {
|
||||
m_log.info("Received command message: (payload=%s)", payload);
|
||||
} else if (payload.find(message_custom::prefix) == 0) {
|
||||
m_log.info("Received custom message: (payload=%s)", payload);
|
||||
} else {
|
||||
m_log.info("Received unknown message: (payload=%s)", payload);
|
||||
}
|
||||
}
|
||||
|
||||
LEMONBUDDY_NS_END
|
@ -37,26 +37,24 @@ namespace io_util {
|
||||
}
|
||||
|
||||
string readline(int read_fd, int& bytes_read) {
|
||||
std::stringstream buffer;
|
||||
stringstream buffer;
|
||||
char char_;
|
||||
|
||||
int bytes = 0;
|
||||
bytes_read = 0;
|
||||
|
||||
while ((bytes_read += ::read(read_fd, &char_, 1)) > 0) {
|
||||
buffer << char_;
|
||||
while ((bytes = ::read(read_fd, &char_, 1)) > 0) {
|
||||
if (bytes <= 0)
|
||||
break;
|
||||
if (char_ == '\n' || char_ == '\x00')
|
||||
break;
|
||||
bytes_read += bytes;
|
||||
buffer << char_;
|
||||
}
|
||||
|
||||
if (bytes_read == 0) {
|
||||
// Reached EOF
|
||||
} else if (bytes_read == -1) {
|
||||
// Read failed
|
||||
} else {
|
||||
return string_util::strip_trailing_newline(buffer.str());
|
||||
}
|
||||
|
||||
if (bytes_read <= 0)
|
||||
return "";
|
||||
|
||||
return string_util::strip_trailing_newline(buffer.str());
|
||||
}
|
||||
|
||||
string readline(int read_fd) {
|
||||
|
Loading…
Reference in New Issue
Block a user