mirror-chatterino2/src/util/IpcQueue.cpp
pajlada 74d65a345d
fix: cleanly exit on shutdown (#5537)
Co-authored-by: Mm2PL <mm2pl+gh@kotmisia.pl>
Co-authored-by: Nerixyz <nerixdev@outlook.de>
2024-08-10 14:24:25 +02:00

135 lines
3.1 KiB
C++

#include "util/IpcQueue.hpp"
#include "common/QLogging.hpp"
#include "singletons/Paths.hpp"
#define BOOST_INTERPROCESS_SHARED_DIR_FUNC
#include <boost/interprocess/ipc/message_queue.hpp>
#include <QByteArray>
#include <QString>
#include <QtGlobal>
namespace boost_ipc = boost::interprocess;
namespace {
static const chatterino::Paths *PATHS = nullptr;
} // namespace
namespace boost::interprocess::ipcdetail {
void get_shared_dir(std::string &shared_dir)
{
if (!PATHS)
{
assert(false && "PATHS not set");
qCCritical(chatterinoNativeMessage)
<< "PATHS not set for shared directory";
return;
}
shared_dir = PATHS->ipcDirectory.toStdString();
}
#ifdef BOOST_INTERPROCESS_WINDOWS
void get_shared_dir(std::wstring &shared_dir)
{
if (!PATHS)
{
assert(false && "PATHS not set");
qCCritical(chatterinoNativeMessage)
<< "PATHS not set for shared directory";
return;
}
shared_dir = PATHS->ipcDirectory.toStdWString();
}
#endif
} // namespace boost::interprocess::ipcdetail
namespace chatterino::ipc {
void initPaths(const Paths *paths)
{
PATHS = paths;
}
void sendMessage(const char *name, const QByteArray &data)
{
try
{
boost_ipc::message_queue messageQueue(boost_ipc::open_only, name);
messageQueue.try_send(data.data(), size_t(data.size()), 1);
}
catch (boost_ipc::interprocess_exception &ex)
{
qCDebug(chatterinoNativeMessage)
<< "Failed to send message:" << ex.what();
}
}
class IpcQueuePrivate
{
public:
IpcQueuePrivate(const char *name, size_t maxMessages, size_t maxMessageSize)
: queue(boost_ipc::open_or_create, name, maxMessages, maxMessageSize)
{
}
boost_ipc::message_queue queue;
};
IpcQueue::IpcQueue(IpcQueuePrivate *priv)
: private_(priv){};
IpcQueue::~IpcQueue() = default;
std::pair<std::unique_ptr<IpcQueue>, QString> IpcQueue::tryReplaceOrCreate(
const char *name, size_t maxMessages, size_t maxMessageSize)
{
try
{
boost_ipc::message_queue::remove(name);
return std::make_pair(
std::unique_ptr<IpcQueue>(new IpcQueue(
new IpcQueuePrivate(name, maxMessages, maxMessageSize))),
QString());
}
catch (boost_ipc::interprocess_exception &ex)
{
return {nullptr, QString::fromLatin1(ex.what())};
}
}
bool IpcQueue::remove(const char *name)
{
return boost_ipc::message_queue::remove(name);
}
QByteArray IpcQueue::receive()
{
try
{
auto *d = this->private_.get();
QByteArray buf;
// The new storage is uninitialized
buf.resize(static_cast<qsizetype>(d->queue.get_max_msg_size()));
size_t messageSize = 0;
unsigned int priority = 0;
d->queue.receive(buf.data(), buf.size(), messageSize, priority);
// truncate to the initialized storage
buf.truncate(static_cast<qsizetype>(messageSize));
return buf;
}
catch (boost_ipc::interprocess_exception &ex)
{
qCDebug(chatterinoNativeMessage)
<< "Failed to receive message:" << ex.what();
}
return {};
}
} // namespace chatterino::ipc