1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
|
#include <hyprwire/hyprwire.hpp>
#include <print>
#include <sys/poll.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include "generated/test_protocol_v1-server.hpp"
#include "generated/test_protocol_v1-client.hpp"
using namespace Hyprutils::Memory;
#define SP CSharedPointer
#define WP CWeakPointer
constexpr const uint32_t TEST_PROTOCOL_VERSION = 1;
static bool quitt = false;
static void sigHandler(int sig) {
quitt = true;
}
static SP<CMyManagerV1Object> manager;
static std::vector<SP<CMyObjectV1Object>> objects;
static SP<Hyprwire::IServerSocket> serverSock;
static SP<CCTestProtocolV1Impl> impl = makeShared<CCTestProtocolV1Impl>(TEST_PROTOCOL_VERSION);
static void makeObject(uint32_t seq) {
auto object = makeShared<CMyObjectV1Object>(serverSock->createObject(manager->getObject()->client(), manager->getObject(), "my_object_v1", seq));
object->sendSendMessage("Hello object");
object->setMakeObject(makeObject);
object->setSendMessage([](const char* msg) { std::println("Object says hello: {}", msg); });
object->setSendEnum([wobj = WP<CMyObjectV1Object>{object}](testProtocolV1MyEnum e) {
std::println("Object sent enum: {}", sc<uint32_t>(e));
std::println("Erroring out the client!");
quitt = true;
if (wobj)
wobj->error(TEST_PROTOCOL_V1_MY_ERROR_ENUM_ERROR_IMPORTANT, "Important error occurred!");
});
objects.emplace_back(std::move(object));
}
static SP<CTestProtocolV1Impl> spec = makeShared<CTestProtocolV1Impl>(TEST_PROTOCOL_VERSION, [](SP<Hyprwire::IObject> obj) {
std::println("Object bound XD");
manager = makeShared<CMyManagerV1Object>(std::move(obj));
manager->sendSendMessage("Hello manager");
manager->setSendMessage([](const char* msg) { std::println("Recvd message: {}", msg); });
manager->setSendMessageFd([](int fd) {
char msgbuf[6] = {0};
sc<void>(read(fd, msgbuf, 5));
std::println("Recvd fd {} with data: {}", fd, msgbuf);
});
manager->setSendMessageArray([](std::vector<const char*> data) {
std::string conct = "";
for (const auto& d : data) {
conct += d + std::string{", "};
}
if (conct.size() > 1) {
conct.pop_back();
conct.pop_back();
}
std::println("Got array message: \"{}\"", conct);
});
manager->setSendMessageArrayUint([](std::vector<uint32_t> data) {
std::string conct = "";
for (const auto& d : data) {
conct += std::format("{}, ", d);
}
conct.pop_back();
conct.pop_back();
std::println("Got uint array message: \"{}\"", conct);
});
manager->setMakeObject(makeObject);
manager->setOnDestroy([w = WP<CMyManagerV1Object>{manager}]() { //
std::println("object {:x} destroyed", (uintptr_t)manager.get());
});
});
static void server(int clientFd) {
serverSock = Hyprwire::IServerSocket::open();
pollfd pfd = {.fd = clientFd, .events = POLLIN, .revents = 0};
serverSock->addImplementation(spec);
// This is not requried, but it is nice to have
if (!(poll(&pfd, 1, 1000) > 0 && (pfd.revents & POLLIN))) {
std::println("Failed to wait for client hello");
exit(1);
}
if (serverSock->addClient(clientFd) == nullptr) {
std::println("Failed to add clientFd to the server socket!");
exit(1);
}
signal(SIGINT, ::sigHandler);
signal(SIGTERM, ::sigHandler);
pfd = {.fd = serverSock->extractLoopFD(), .events = POLLIN, .revents = 0};
while (!quitt) {
int events = poll(&pfd, 1, -1);
if (events < 0) {
if (errno == EAGAIN)
continue;
else
break;
} else if (events == 0)
continue;
if (pfd.revents & POLLHUP)
break;
if (!(pfd.revents & POLLIN))
continue;
serverSock->dispatchEvents(false);
}
}
static void client(int serverFd) {
auto sock = Hyprwire::IClientSocket::open(serverFd);
if (!sock->waitForHandshake()) {
std::println("err: handshake failed");
return;
}
sock->addImplementation(impl);
std::println("OK!");
const auto SPEC = sock->getSpec(impl->protocol()->specName());
if (!SPEC) {
std::println("err: test protocol unsupported");
return;
}
std::println("test protocol supported at version {}. Binding.", SPEC->specVer());
auto cmanager = makeShared<CCMyManagerV1Object>(sock->bindProtocol(impl->protocol(), TEST_PROTOCOL_VERSION));
std::println("Bound!");
int pips[2];
sc<void>(pipe(pips));
sc<void>(write(pips[1], "pipe!", 5));
std::println("Will send fd {}", pips[0]);
cmanager->sendSendMessage("Hello!");
cmanager->sendSendMessageFd(pips[0]);
cmanager->sendSendMessageArray(std::vector<const char*>{"Hello", "via", "array!"});
cmanager->sendSendMessageArray(std::vector<const char*>{});
cmanager->sendSendMessageArrayUint(std::vector<uint32_t>{69, 420, 2137});
cmanager->setSendMessage([](const char* msg) { std::println("Server says {}", msg); });
auto cobject = makeShared<CCMyObjectV1Object>(cmanager->sendMakeObject());
auto cobject2 = makeShared<CCMyObjectV1Object>(cobject->sendMakeObject());
cobject->setSendMessage([&cobject](const char* msg) { std::println("Server says on object {}", msg); });
cobject2->setSendMessage([&cobject](const char* msg) {
std::println("Server says on object2 {}", msg);
cobject->sendSendEnum(TEST_PROTOCOL_V1_MY_ENUM_WORLD);
quitt = true;
});
cobject->sendSendMessage("Hello from object");
cobject2->sendSendMessage("Hello from object2");
while (!quitt)
sock->dispatchEvents(true);
sock->roundtrip();
}
int main(int argc, char** argv, char** envp) {
int sockFds[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockFds))
return 1;
int s = 0;
int c = 1;
pid_t chld = fork();
if (chld < 0) {
close(sockFds[s]);
close(sockFds[c]);
std::println(stderr, "Failed to fork");
} else if (chld == 0) {
// CHILD (Client)
close(sockFds[s]);
client(sockFds[c]);
} else {
// PARENT (Server)
close(sockFds[c]);
server(sockFds[s]);
}
return 0;
}
|