feat(ipc): Add polybar-msg to facilitate ipc messaging
This commit is contained in:
parent
0f0d786cbd
commit
79856d7ed2
4
build.sh
4
build.sh
@ -28,6 +28,7 @@ function main
|
|||||||
mkdir ./build || msg_err "Failed to create build dir"
|
mkdir ./build || msg_err "Failed to create build dir"
|
||||||
cd ./build || msg_err "Failed to enter build dir"
|
cd ./build || msg_err "Failed to enter build dir"
|
||||||
|
|
||||||
|
local build_ipc_msg="ON"
|
||||||
local enable_alsa="ON"
|
local enable_alsa="ON"
|
||||||
local enable_i3="ON"
|
local enable_i3="ON"
|
||||||
local enable_network="ON"
|
local enable_network="ON"
|
||||||
@ -46,6 +47,8 @@ function main
|
|||||||
[[ "${p^^}" != "Y" ]] && enable_mpd="OFF"
|
[[ "${p^^}" != "Y" ]] && enable_mpd="OFF"
|
||||||
read -r -p "$(msg "Include support for \"internal/github\" (requires libcurl) ---------- [Y/n]: ")" -n 1 p && echo
|
read -r -p "$(msg "Include support for \"internal/github\" (requires libcurl) ---------- [Y/n]: ")" -n 1 p && echo
|
||||||
[[ "${p^^}" != "Y" ]] && enable_curl="OFF"
|
[[ "${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 cxx="c++"
|
||||||
local cc="cc"
|
local cc="cc"
|
||||||
@ -69,6 +72,7 @@ function main
|
|||||||
-DENABLE_MPD:BOOL="${enable_mpd}" \
|
-DENABLE_MPD:BOOL="${enable_mpd}" \
|
||||||
-DENABLE_NETWORK:BOOL="${enable_network}" \
|
-DENABLE_NETWORK:BOOL="${enable_network}" \
|
||||||
-DENABLE_CURL:BOOL="${enable_curl}" \
|
-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_err "Failed to generate build... read output to get a hint of what went wrong"
|
||||||
|
|
||||||
msg "Building project"
|
msg "Building project"
|
||||||
|
@ -48,6 +48,7 @@ endif()
|
|||||||
option(CXXLIB_CLANG "Link against libc++" OFF)
|
option(CXXLIB_CLANG "Link against libc++" OFF)
|
||||||
option(CXXLIB_GCC "Link against stdlibc++" OFF)
|
option(CXXLIB_GCC "Link against stdlibc++" OFF)
|
||||||
|
|
||||||
|
option(BUILD_IPC_MSG "Build ipc messager" ON)
|
||||||
option(BUILD_TESTS "Build testsuite" OFF)
|
option(BUILD_TESTS "Build testsuite" OFF)
|
||||||
option(DEBUG_LOGGER "Enable extra debug logging" OFF)
|
option(DEBUG_LOGGER "Enable extra debug logging" OFF)
|
||||||
option(VERBOSE_TRACELOG "Enable verbose trace logs" OFF)
|
option(VERBOSE_TRACELOG "Enable verbose trace logs" OFF)
|
||||||
|
@ -53,6 +53,7 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
message(STATUS "--------------------------")
|
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 " 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 " Debug logging ${DEBUG_LOGGER}" DEBUG_LOGGER "32;1" "37;2")
|
||||||
colored_option(STATUS " Verbose tracing ${VERBOSE_TRACELOG}" VERBOSE_TRACELOG "32;1" "37;2")
|
colored_option(STATUS " Verbose tracing ${VERBOSE_TRACELOG}" VERBOSE_TRACELOG "32;1" "37;2")
|
||||||
|
@ -102,6 +102,7 @@ namespace file_util {
|
|||||||
string pick(const vector<string>& filenames);
|
string pick(const vector<string>& filenames);
|
||||||
string contents(const string& filename);
|
string contents(const string& filename);
|
||||||
bool is_fifo(const string& filename);
|
bool is_fifo(const string& filename);
|
||||||
|
vector<string> glob(const string& pattern);
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
decltype(auto) make_file_descriptor(Args&&... args) {
|
decltype(auto) make_file_descriptor(Args&&... args) {
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
file(GLOB_RECURSE SOURCES RELATIVE ${PROJECT_SOURCE_DIR}/src *.c[p]*)
|
file(GLOB_RECURSE SOURCES RELATIVE ${PROJECT_SOURCE_DIR}/src *.c[p]*)
|
||||||
|
list(REMOVE_ITEM SOURCES ipc.cpp)
|
||||||
|
|
||||||
# Locate dependencies {{{
|
# Locate dependencies {{{
|
||||||
|
|
||||||
@ -142,14 +143,18 @@ target_compile_definitions(${PROJECT_NAME} PUBLIC
|
|||||||
${XCB_DEFINITIONS})
|
${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_BINARY ${PROJECT_SOURCE_DIR}/bin/${PROJECT_NAME} PARENT_SCOPE)
|
||||||
set(APP_LIBRARIES ${APP_LIBRARIES} PARENT_SCOPE)
|
set(APP_LIBRARIES ${APP_LIBRARIES} PARENT_SCOPE)
|
||||||
set(APP_INCLUDE_DIRS ${APP_INCLUDE_DIRS} PARENT_SCOPE)
|
set(APP_INCLUDE_DIRS ${APP_INCLUDE_DIRS} PARENT_SCOPE)
|
||||||
|
|
||||||
# }}}
|
|
||||||
|
|
||||||
execute_process(COMMAND git describe --tags --dirty=-git
|
execute_process(COMMAND git describe --tags --dirty=-git
|
||||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||||
OUTPUT_VARIABLE APP_VERSION
|
OUTPUT_VARIABLE APP_VERSION
|
||||||
|
126
src/ipc.cpp
Normal file
126
src/ipc.cpp
Normal 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;
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <glob.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -201,6 +202,23 @@ namespace file_util {
|
|||||||
struct stat buffer {};
|
struct stat buffer {};
|
||||||
return stat(filename.c_str(), &buffer) == 0 && S_ISFIFO(buffer.st_mode);
|
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
|
POLYBAR_NS_END
|
||||||
|
Loading…
Reference in New Issue
Block a user