basic IPC working
This commit is contained in:
commit
7bf8c5dd38
7 changed files with 232 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
cmake-build-debug
|
||||||
|
.idea
|
14
CMakeLists.txt
Normal file
14
CMakeLists.txt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
cmake_minimum_required(VERSION 3.28)
|
||||||
|
project(ipcswaytest)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
|
find_package(nlohmann_json 3.2.0 REQUIRED)
|
||||||
|
|
||||||
|
add_executable(ipcswaytest main.cpp
|
||||||
|
sway_bindings/swaymsg.h
|
||||||
|
sway_bindings/Sway.h
|
||||||
|
sway_bindings/Sway.cpp
|
||||||
|
sway_bindings/Formatter.h)
|
||||||
|
|
||||||
|
target_link_libraries(ipcswaytest PRIVATE nlohmann_json::nlohmann_json)
|
12
main.cpp
Normal file
12
main.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "sway_bindings/swaymsg.h"
|
||||||
|
#include "sway_bindings/Sway.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto sway = Sway();
|
||||||
|
auto resp = sway.sendIPC(SWAY_GET_TREE);
|
||||||
|
std::cout << resp.msg << "\n";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
41
sway_bindings/Formatter.h
Normal file
41
sway_bindings/Formatter.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
//
|
||||||
|
// Created by grimmauld on 03.03.24.
|
||||||
|
// https://stackoverflow.com/questions/12261915/how-to-throw-stdexceptions-with-variable-messages
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef IPCSWAYTEST_FORMATTER_H
|
||||||
|
#define IPCSWAYTEST_FORMATTER_H
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
class Formatter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Formatter() = default;
|
||||||
|
~Formatter() = default;
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
Formatter & operator << (const Type & value)
|
||||||
|
{
|
||||||
|
stream_ << value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string str() const { return stream_.str(); }
|
||||||
|
explicit operator std::string () const { return stream_.str(); }
|
||||||
|
|
||||||
|
enum ConvertToString
|
||||||
|
{
|
||||||
|
to_str
|
||||||
|
};
|
||||||
|
std::string operator >> (ConvertToString) { return stream_.str(); }
|
||||||
|
|
||||||
|
Formatter(const Formatter &) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::stringstream stream_;
|
||||||
|
// Formatter & operator = (Formatter &);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //IPCSWAYTEST_FORMATTER_H
|
37
sway_bindings/Sway.cpp
Normal file
37
sway_bindings/Sway.cpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
//
|
||||||
|
// Created by grimmauld on 03.03.24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Sway.h"
|
||||||
|
|
||||||
|
swaymsg Sway::sendIPC(const swaymsg &query) const {
|
||||||
|
if (send(socketfd, query.asBuffer(), query.size(), 0) == -1) {
|
||||||
|
throw std::runtime_error("Swaysock: Error on send() call");
|
||||||
|
}
|
||||||
|
|
||||||
|
return swaymsg::fromSock(socketfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Sway::Sway() : socketfd(socket(AF_UNIX, SOCK_STREAM, 0)) {
|
||||||
|
initializeSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sway::initializeSocket() const {
|
||||||
|
auto *sockaddr = std::getenv("SWAYSOCK");
|
||||||
|
if (sockaddr == nullptr) {
|
||||||
|
throw std::runtime_error("Binding socket: reading SWAYSOCK env var failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socketfd == -1) {
|
||||||
|
throw std::runtime_error("Binding socket: could not get file descriptor");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_un swaysock{};
|
||||||
|
swaysock.sun_family = AF_UNIX;
|
||||||
|
strcpy(swaysock.sun_path, sockaddr);
|
||||||
|
auto dlen = strlen(swaysock.sun_path) + sizeof(swaysock.sun_family);
|
||||||
|
|
||||||
|
if (connect(socketfd, (struct sockaddr *) &swaysock, dlen) == -1) {
|
||||||
|
throw std::runtime_error("Binding socket: could not connect to socket");
|
||||||
|
}
|
||||||
|
}
|
23
sway_bindings/Sway.h
Normal file
23
sway_bindings/Sway.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//
|
||||||
|
// Created by grimmauld on 03.03.24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef IPCSWAYTEST_SWAY_H
|
||||||
|
#define IPCSWAYTEST_SWAY_H
|
||||||
|
|
||||||
|
#include "swaymsg.h"
|
||||||
|
|
||||||
|
class Sway {
|
||||||
|
protected:
|
||||||
|
const int socketfd;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Sway();
|
||||||
|
|
||||||
|
void initializeSocket() const;
|
||||||
|
|
||||||
|
[[nodiscard]] swaymsg sendIPC(const swaymsg& query) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //IPCSWAYTEST_SWAY_H
|
103
sway_bindings/swaymsg.h
Normal file
103
sway_bindings/swaymsg.h
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
//
|
||||||
|
// Created by grimmauld on 03.03.24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef IPCSWAYTEST_SWAYMSG_H
|
||||||
|
#define IPCSWAYTEST_SWAYMSG_H
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include "Formatter.h"
|
||||||
|
|
||||||
|
struct swaymsg {
|
||||||
|
explicit swaymsg(const unsigned int payloadType, const char *msg) : swaymsg(payloadType, msg,
|
||||||
|
msg == nullptr ? 0 : strlen(msg)) {};
|
||||||
|
|
||||||
|
explicit swaymsg(const unsigned int payloadType, const char *msg, const unsigned int payload_len)
|
||||||
|
: payload_len(payload_len), payload_type(payloadType) {
|
||||||
|
|
||||||
|
this->msg = static_cast<char *>(std::malloc(payload_len));
|
||||||
|
std::memcpy(this->msg, msg, payload_len);
|
||||||
|
|
||||||
|
buff = static_cast<unsigned char *>(std::malloc(size()));
|
||||||
|
std::memcpy(buff, magic, strlen(magic));
|
||||||
|
std::memcpy(buff + (unsigned int) strlen(magic), &payload_len, sizeof(payload_len));
|
||||||
|
std::memcpy(buff + (unsigned int) strlen(magic) + sizeof(payload_len), &payload_type, sizeof(payload_type));
|
||||||
|
std::memcpy(buff + (unsigned int) strlen(magic) + sizeof(payload_len) + sizeof(payload_type), msg, payload_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit swaymsg(const unsigned int payloadType) : swaymsg(payloadType, nullptr) {}
|
||||||
|
|
||||||
|
[[nodiscard]] static swaymsg fromSock(const int sockfd) {
|
||||||
|
char buff[6];
|
||||||
|
size_t dlen;
|
||||||
|
if ((dlen = recv(sockfd, buff, 6, 0)) != 6) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
Formatter() << "Swaysock: Unexpected length on recv() call for magic: " << dlen
|
||||||
|
>> Formatter::to_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(buff, magic, 6) != 0) {
|
||||||
|
throw std::runtime_error("Swaysock: magic did not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int payloadType;
|
||||||
|
unsigned int payloadLen;
|
||||||
|
static_assert(sizeof(payloadType) == 4);
|
||||||
|
static_assert(sizeof(payloadLen) == 4);
|
||||||
|
|
||||||
|
if ((dlen = recv(sockfd, &payloadLen, sizeof(payloadLen), 0)) != sizeof(payloadLen)) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
Formatter() << "Swaysock: Unexpected length on recv() call for len: " << dlen >> Formatter::to_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dlen = recv(sockfd, &payloadType, sizeof(payloadType), 0)) != sizeof(payloadType)) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
Formatter() << "Swaysock: Unexpected length on recv() call for type: " << dlen
|
||||||
|
>> Formatter::to_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
char msgBuff[payloadLen];
|
||||||
|
if ((dlen = recv(sockfd, msgBuff, payloadLen, 0)) != payloadLen) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
Formatter() << "Swaysock: Unexpected length on recv() call for message: " << dlen
|
||||||
|
>> Formatter::to_str);
|
||||||
|
}
|
||||||
|
return swaymsg(payloadType, msgBuff, payloadLen);
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const static char *magic = "i3-ipc";
|
||||||
|
const unsigned int payload_len;
|
||||||
|
const unsigned int payload_type;
|
||||||
|
char *msg;
|
||||||
|
unsigned char *buff = nullptr;
|
||||||
|
|
||||||
|
static_assert(sizeof(payload_len) == 4);
|
||||||
|
static_assert(sizeof(payload_type) == 4);
|
||||||
|
|
||||||
|
[[nodiscard]] size_t size() const {
|
||||||
|
return (int) strlen(magic) + sizeof(payload_len) + sizeof(payload_type) + payload_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] void *asBuffer() const {
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
~swaymsg() {
|
||||||
|
delete buff;
|
||||||
|
delete msg;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const swaymsg SWAY_EXIT = swaymsg(0, "exit");
|
||||||
|
static const swaymsg SWAY_GET_WORKSPACES = swaymsg(1);
|
||||||
|
static const swaymsg SWAY_GET_OUTPUTS = swaymsg(3);
|
||||||
|
static const swaymsg SWAY_GET_TREE = swaymsg(4);
|
||||||
|
static const swaymsg SWAY_GET_VERSION = swaymsg(7);
|
||||||
|
static const swaymsg SWAY_GET_CONFIG = swaymsg(9);
|
||||||
|
static const swaymsg SWAY_GET_INPUTS = swaymsg(100);
|
||||||
|
|
||||||
|
|
||||||
|
#endif //IPCSWAYTEST_SWAYMSG_H
|
Loading…
Reference in a new issue