feat(ipc): Add polybar-msg to facilitate ipc messaging

This commit is contained in:
Michael Carlberg 2017-01-10 02:09:27 +01:00
parent 0f0d786cbd
commit 79856d7ed2
7 changed files with 159 additions and 3 deletions

View File

@ -28,6 +28,7 @@ function main
mkdir ./build || msg_err "Failed to create build dir"
cd ./build || msg_err "Failed to enter build dir"
local build_ipc_msg="ON"
local enable_alsa="ON"
local enable_i3="ON"
local enable_network="ON"
@ -46,6 +47,8 @@ function main
[[ "${p^^}" != "Y" ]] && enable_mpd="OFF"
read -r -p "$(msg "Include support for \"internal/github\" (requires libcurl) ---------- [Y/n]: ")" -n 1 p && echo
[[ "${p^^}" != "Y" ]] && enable_curl="OFF"
read -r -p "$(msg "Build \"polybar-msg\" used to send ipc messages --------------------- [Y/n]: ")" -n 1 p && echo
[[ "${p^^}" != "Y" ]] && build_ipc_msg="OFF"
local cxx="c++"
local cc="cc"
@ -69,6 +72,7 @@ function main
-DENABLE_MPD:BOOL="${enable_mpd}" \
-DENABLE_NETWORK:BOOL="${enable_network}" \
-DENABLE_CURL:BOOL="${enable_curl}" \
-DBUILD_IPC_MSG:BOOL="${build_ipc_msg}" \
.. || msg_err "Failed to generate build... read output to get a hint of what went wrong"
msg "Building project"

View File

@ -48,6 +48,7 @@ endif()
option(CXXLIB_CLANG "Link against libc++" OFF)
option(CXXLIB_GCC "Link against stdlibc++" OFF)
option(BUILD_IPC_MSG "Build ipc messager" ON)
option(BUILD_TESTS "Build testsuite" OFF)
option(DEBUG_LOGGER "Enable extra debug logging" OFF)
option(VERBOSE_TRACELOG "Enable verbose trace logs" OFF)

View File

@ -53,6 +53,7 @@ else()
endif()
message(STATUS "--------------------------")
colored_option(STATUS " Build polybar-msg ${BUILD_IPC_MSG}" BUILD_IPC_MSG "32;1" "37;2")
colored_option(STATUS " Build testsuite ${BUILD_TESTS}" BUILD_TESTS "32;1" "37;2")
colored_option(STATUS " Debug logging ${DEBUG_LOGGER}" DEBUG_LOGGER "32;1" "37;2")
colored_option(STATUS " Verbose tracing ${VERBOSE_TRACELOG}" VERBOSE_TRACELOG "32;1" "37;2")

View File

@ -102,6 +102,7 @@ namespace file_util {
string pick(const vector<string>& filenames);
string contents(const string& filename);
bool is_fifo(const string& filename);
vector<string> glob(const string& pattern);
template <typename... Args>
decltype(auto) make_file_descriptor(Args&&... args) {

View File

@ -3,6 +3,7 @@
#
file(GLOB_RECURSE SOURCES RELATIVE ${PROJECT_SOURCE_DIR}/src *.c[p]*)
list(REMOVE_ITEM SOURCES ipc.cpp)
# Locate dependencies {{{
@ -142,14 +143,18 @@ target_compile_definitions(${PROJECT_NAME} PUBLIC
${XCB_DEFINITIONS})
# }}}
# Export target details {{{
# Create executable target: ipc messager {{{
if(BUILD_IPC_MSG)
make_executable(${PROJECT_NAME}-msg SOURCES ipc.cpp utils/file.cpp)
endif()
# }}}
set(APP_BINARY ${PROJECT_SOURCE_DIR}/bin/${PROJECT_NAME} PARENT_SCOPE)
set(APP_LIBRARIES ${APP_LIBRARIES} PARENT_SCOPE)
set(APP_INCLUDE_DIRS ${APP_INCLUDE_DIRS} PARENT_SCOPE)
# }}}
execute_process(COMMAND git describe --tags --dirty=-git
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
OUTPUT_VARIABLE APP_VERSION

126
src/ipc.cpp Normal file
View File

@ -0,0 +1,126 @@
#include <fcntl.h>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include "common.hpp"
#include "utils/file.hpp"
using namespace polybar;
void log(const string& msg) {
std::cerr << "polybar-msg: " << msg << std::endl;
}
void log(int exit_code, const string& msg) {
std::cerr << "polybar-msg: " << msg << std::endl;
exit(exit_code);
}
void usage(const string& parameters) {
std::cerr << "Usage: polybar-msg [-p pid] " << parameters << std::endl;
exit(127);
}
bool validate_type(const string& type) {
if (type == "action") {
return true;
} else if (type == "cmd") {
return true;
} else if (type == "hook") {
return true;
} else {
return false;
}
}
int main(int argc, char** argv) {
const int E_GENERIC{1};
const int E_NO_CHANNELS{2};
const int E_MESSAGE_TYPE{3};
const int E_INVALID_PID{4};
const int E_INVALID_CHANNEL{5};
const int E_WRITE{6};
vector<string> args{argv + 1, argv + argc};
string::size_type p;
int pid{0};
// If -p <pid> is passed, check if the process is running and that
// a valid channel pipe is available
if (args.size() >= 2 && args[0].compare(0, 2, "-p") == 0) {
if (!file_util::exists("/proc/" + args[1])) {
log(E_INVALID_PID, "No process with pid " + args[1]);
} else if (!file_util::is_fifo("/tmp/polybar_mqueue." + args[1])) {
log(E_INVALID_CHANNEL, "No channel available for pid " + args[1]);
}
pid = std::atoi(args[1].c_str());
args.erase(args.begin());
args.erase(args.begin());
}
// Validate args
if (args.size() < 2) {
usage("<command=(action|cmd|hook)> <payload> [...]");
} else if (!validate_type(args[0])) {
log(E_MESSAGE_TYPE, "\"" + args[0] + "\" is not a valid type.");
}
string ipc_type{args[0]};
args.erase(args.begin());
string ipc_payload{args[0]};
args.erase(args.begin());
// Check hook specific args
if (ipc_type == "hook") {
if (args.size() != 1) {
usage("hook <module-name> <hook-index>");
} else if ((p = ipc_payload.find("module/")) != 0) {
ipc_payload = "module/" + ipc_payload + args[0];
args.erase(args.begin());
} else {
ipc_payload += args[0];
args.erase(args.begin());
}
}
// Get availble channel pipes
auto channels = file_util::glob("/tmp/polybar_mqueue.*");
if (channels.empty()) {
log(E_NO_CHANNELS, "There are no active ipc channels");
}
// Write the message to each channel in the list and remove stale
// channel pipes that may be left lingering if the owning process got
// SIGKILLED or crashed
for (auto&& channel : channels) {
string handle{channel};
int handle_pid{0};
if ((p = handle.rfind('.')) != string::npos) {
handle_pid = std::atoi(handle.substr(p + 1).c_str());
}
if (!file_util::exists("/proc/" + to_string(handle_pid))) {
if (unlink(handle.c_str()) == -1) {
log(E_GENERIC, "Could not remove stale ipc channel: " + string{std::strerror(errno)});
} else {
log("Removed stale ipc channel: " + handle);
}
} else if (!pid || pid == handle_pid) {
string payload{ipc_type + ":" + ipc_payload};
try {
fd_stream<std::ostream> out(handle, O_WRONLY);
out << payload << '\n';
log("Successfully wrote \"" + payload + "\" to \"" + handle + "\"");
} catch (const std::exception& err) {
log(E_WRITE, "Failed to write \"" + payload + "\" to \"" + handle + "\" (err: " + err.what() + ")");
}
}
}
return 0;
}

View File

@ -1,4 +1,5 @@
#include <fcntl.h>
#include <glob.h>
#include <sys/stat.h>
#include <cstdio>
#include <fstream>
@ -201,6 +202,23 @@ namespace file_util {
struct stat buffer {};
return stat(filename.c_str(), &buffer) == 0 && S_ISFIFO(buffer.st_mode);
}
/**
* Get glob results using given pattern
*/
vector<string> glob(const string& pattern) {
glob_t result;
vector<string> ret;
if (glob(pattern.c_str(), GLOB_TILDE, nullptr, &result) == 0) {
for (size_t i = 0_z; i < result.gl_pathc; ++i) {
ret.emplace_back(result.gl_pathv[i]);
}
globfree(&result);
}
return ret;
}
}
POLYBAR_NS_END