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")
|
CACHE STRING "Path to file containing memory info")
|
||||||
set(SETTING_PATH_TEMPERATURE_INFO "/sys/class/thermal/thermal_zone%zone%/temp"
|
set(SETTING_PATH_TEMPERATURE_INFO "/sys/class/thermal/thermal_zone%zone%/temp"
|
||||||
CACHE STRING "Path to file containing the current temperature")
|
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/bar.hpp"
|
||||||
#include "components/config.hpp"
|
#include "components/config.hpp"
|
||||||
#include "components/eventloop.hpp"
|
#include "components/eventloop.hpp"
|
||||||
|
#include "components/ipc.hpp"
|
||||||
#include "components/logger.hpp"
|
#include "components/logger.hpp"
|
||||||
#include "components/signals.hpp"
|
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
#include "utils/command.hpp"
|
#include "utils/command.hpp"
|
||||||
#include "utils/inotify.hpp"
|
#include "utils/inotify.hpp"
|
||||||
@ -17,12 +17,13 @@ LEMONBUDDY_NS
|
|||||||
class controller {
|
class controller {
|
||||||
public:
|
public:
|
||||||
explicit controller(connection& conn, const logger& logger, const config& config, unique_ptr<eventloop> eventloop,
|
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_connection(conn)
|
||||||
, m_log(logger)
|
, m_log(logger)
|
||||||
, m_conf(config)
|
, m_conf(config)
|
||||||
, m_eventloop(forward<decltype(eventloop)>(eventloop))
|
, m_eventloop(forward<decltype(eventloop)>(eventloop))
|
||||||
, m_bar(forward<decltype(bar)>(bar))
|
, m_bar(forward<decltype(bar)>(bar))
|
||||||
|
, m_ipc(forward<decltype(ipc)>(ipc))
|
||||||
, m_confwatch(confwatch) {}
|
, m_confwatch(confwatch) {}
|
||||||
|
|
||||||
~controller();
|
~controller();
|
||||||
@ -53,6 +54,7 @@ class controller {
|
|||||||
const config& m_conf;
|
const config& m_conf;
|
||||||
unique_ptr<eventloop> m_eventloop;
|
unique_ptr<eventloop> m_eventloop;
|
||||||
unique_ptr<bar> m_bar;
|
unique_ptr<bar> m_bar;
|
||||||
|
unique_ptr<ipc> m_ipc;
|
||||||
|
|
||||||
stateflag m_running{false};
|
stateflag m_running{false};
|
||||||
stateflag m_reload{false};
|
stateflag m_reload{false};
|
||||||
@ -67,7 +69,7 @@ class controller {
|
|||||||
inotify_util::watch_t& m_confwatch;
|
inotify_util::watch_t& m_confwatch;
|
||||||
command_util::command_t m_command;
|
command_util::command_t m_command;
|
||||||
|
|
||||||
bool m_writeback = false;
|
bool m_writeback{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -83,7 +85,8 @@ namespace {
|
|||||||
configure_logger(),
|
configure_logger(),
|
||||||
configure_config(),
|
configure_config(),
|
||||||
configure_eventloop(),
|
configure_eventloop(),
|
||||||
configure_bar());
|
configure_bar(),
|
||||||
|
configure_ipc());
|
||||||
// clang-format on
|
// 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_CPU_INFO "@SETTING_PATH_CPU_INFO@"
|
||||||
#define PATH_MEMORY_INFO "@SETTING_PATH_MEMORY_INFO@"
|
#define PATH_MEMORY_INFO "@SETTING_PATH_MEMORY_INFO@"
|
||||||
#define PATH_TEMPERATURE_INFO "@SETTING_PATH_TEMPERATURE_INFO@"
|
#define PATH_TEMPERATURE_INFO "@SETTING_PATH_TEMPERATURE_INFO@"
|
||||||
|
#define PATH_MESSAGING_FIFO "@SETTING_PATH_MESSAGING_FIFO@"
|
||||||
|
|
||||||
auto print_build_info = []() {
|
auto print_build_info = []() {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
@ -2,6 +2,12 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "components/controller.hpp"
|
#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 "components/signals.hpp"
|
||||||
#include "modules/backlight.hpp"
|
#include "modules/backlight.hpp"
|
||||||
#include "modules/battery.hpp"
|
#include "modules/battery.hpp"
|
||||||
@ -56,6 +62,11 @@ controller::~controller() {
|
|||||||
m_eventloop.reset();
|
m_eventloop.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_ipc) {
|
||||||
|
m_log.info("Deconstructing ipc");
|
||||||
|
m_ipc.reset();
|
||||||
|
}
|
||||||
|
|
||||||
if (m_bar) {
|
if (m_bar) {
|
||||||
m_log.info("Deconstructing bar");
|
m_log.info("Deconstructing bar");
|
||||||
m_bar.reset();
|
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
|
// Listen for events on the root window to be able to
|
||||||
// break the blocking wait call when cleaning up
|
// break the blocking wait call when cleaning up
|
||||||
m_log.trace("controller: Listen for events on the root window");
|
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};
|
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);
|
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_log.trace("controller: Setup bar");
|
||||||
m_bar->bootstrap(m_writeback || dump_wmname);
|
m_bar->bootstrap(m_writeback || dump_wmname);
|
||||||
m_bar->bootstrap_tray();
|
m_bar->bootstrap_tray();
|
||||||
} catch (const exception& err) {
|
|
||||||
throw application_error("Failed to setup bar renderer: " + string{err.what()});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dump_wmname) {
|
if (dump_wmname) {
|
||||||
std::cout << m_bar->settings().wmname << std::endl;
|
std::cout << m_bar->settings().wmname << std::endl;
|
||||||
return;
|
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));
|
m_eventloop->set_update_cb(bind(&controller::on_update, this));
|
||||||
|
|
||||||
if (!m_writeback) {
|
if (!m_writeback) {
|
||||||
|
m_log.trace("controller: Attach eventloop input callback");
|
||||||
g_signals::bar::action_click = bind(&controller::on_mouse_event, this, placeholders::_1);
|
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));
|
m_eventloop->set_input_db(bind(&controller::on_unrecognized_action, this, placeholders::_1));
|
||||||
}
|
}
|
||||||
@ -138,6 +142,11 @@ bool controller::run() {
|
|||||||
install_sigmask();
|
install_sigmask();
|
||||||
install_confwatch();
|
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
|
// Listen for X events in separate thread
|
||||||
if (!m_writeback) {
|
if (!m_writeback) {
|
||||||
m_threads.emplace_back(thread(&controller::wait_for_xevent, this));
|
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) {
|
string readline(int read_fd, int& bytes_read) {
|
||||||
std::stringstream buffer;
|
stringstream buffer;
|
||||||
char char_;
|
char char_;
|
||||||
|
int bytes = 0;
|
||||||
bytes_read = 0;
|
bytes_read = 0;
|
||||||
|
|
||||||
while ((bytes_read += ::read(read_fd, &char_, 1)) > 0) {
|
while ((bytes = ::read(read_fd, &char_, 1)) > 0) {
|
||||||
buffer << char_;
|
if (bytes <= 0)
|
||||||
|
break;
|
||||||
if (char_ == '\n' || char_ == '\x00')
|
if (char_ == '\n' || char_ == '\x00')
|
||||||
break;
|
break;
|
||||||
|
bytes_read += bytes;
|
||||||
|
buffer << char_;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_read == 0) {
|
if (bytes_read <= 0)
|
||||||
// Reached EOF
|
|
||||||
} else if (bytes_read == -1) {
|
|
||||||
// Read failed
|
|
||||||
} else {
|
|
||||||
return string_util::strip_trailing_newline(buffer.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
|
return string_util::strip_trailing_newline(buffer.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
string readline(int read_fd) {
|
string readline(int read_fd) {
|
||||||
|
Loading…
Reference in New Issue
Block a user