From b3cc53579070b8459b736f959fd875cae6bbfc75 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Sat, 20 Jan 2024 10:43:33 +0000 Subject: [PATCH] Initial commit --- .gitignore | 1 + STOMPClient.pro | 8 +++ main.cpp | 7 +++ stompframe.cpp | 151 ++++++++++++++++++++++++++++++++++++++++++++++++ stompframe.h | 62 ++++++++++++++++++++ 5 files changed, 229 insertions(+) create mode 100644 .gitignore create mode 100644 STOMPClient.pro create mode 100644 main.cpp create mode 100644 stompframe.cpp create mode 100644 stompframe.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..75c107b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pro.user diff --git a/STOMPClient.pro b/STOMPClient.pro new file mode 100644 index 0000000..e3e96e3 --- /dev/null +++ b/STOMPClient.pro @@ -0,0 +1,8 @@ +QT += network gui widgets +CONFIG += c++14 console +CONFIG -= app_bundle +HEADERS += \ + stompframe.h +SOURCES += \ + main.cpp \ + stompframe.cpp diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..bf2b52a --- /dev/null +++ b/main.cpp @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) { + QApplication application(argc, argv); + + return application.exec(); +} diff --git a/stompframe.cpp b/stompframe.cpp new file mode 100644 index 0000000..0b40080 --- /dev/null +++ b/stompframe.cpp @@ -0,0 +1,151 @@ +#include "stompframe.h" + +STOMPFrame::STOMPFrame(Command command, std::initializer_list> headers, const QByteArray& body): + command_(command), body_(body) { + for (const auto& header: headers) { + headers_[header.first] = header.second; + } +} + +qint64 STOMPFrame::send(QIODevice& device) { + QByteArray encoded; + QTextStream out {&encoded}; + out << command_ << "\n"; + for (const auto& key: headers_.keys()) { + out << key << ":" << headers_[key] << "\n"; + } + if (!headers_.contains("content-length")) { + out << "content-length" << ":" << body_.size() << "\n"; + } + out << "\n" << body_ << '\0'; + out.flush(); + return device.write(encoded); +} + +STOMPFrame STOMPFrame::receive(QIODevice& device) { + STOMPFrame frame; + QTextStream in(&device); + + QString commandStr; + if (!in.readLineInto(&commandStr)) { + return {}; + } + if (commandStr == "STOMP") { + frame.command_ = STOMPFrame::STOMP; + } else if (commandStr == "SEND") { + frame.command_ = STOMPFrame::SEND; + } else if (commandStr == "SUBSCRIBE") { + frame.command_ = STOMPFrame::SUBSCRIBE; + } else if (commandStr == "UNSUBSCRIBE") { + frame.command_ = STOMPFrame::UNSUBSCRIBE; + } else if (commandStr == "BEGIN") { + frame.command_ = STOMPFrame::BEGIN; + } else if (commandStr == "COMMIT") { + frame.command_ = STOMPFrame::COMMIT; + } else if (commandStr == "ABORT") { + frame.command_ = STOMPFrame::ABORT; + } else if (commandStr == "ACK") { + frame.command_ = STOMPFrame::ACK; + } else if (commandStr == "NACK") { + frame.command_ = STOMPFrame::NACK; + } else if (commandStr == "DISCONNECT") { + frame.command_ = STOMPFrame::DISCONNECT; + } else if (commandStr == "CONNECTED") { + frame.command_ = STOMPFrame::CONNECTED; + } else if (commandStr == "MESSAGE") { + frame.command_ = STOMPFrame::MESSAGE; + } else if (commandStr == "RECEIPT") { + frame.command_ = STOMPFrame::RECEIPT; + } else if (commandStr == "ERROR") { + frame.command_ = STOMPFrame::ERROR; + } else { + return {}; + } + + QString headerLine; + while (in.readLineInto(&headerLine) && headerLine != "") { + auto components = headerLine.split(':'); + if (components.count() != 2) { + return {}; + } + frame.headers_.insert(components[0].trimmed(), components[1].trimmed()); + } + + if (frame.headers_.contains("content-length")) { + bool conversionOk; + qint64 length = frame.headers_["content-length"].toLongLong(&conversionOk); + if (!conversionOk) { + return {}; + } + while (frame.body_.length() < length) { + frame.body_ += in.read(length - frame.body_.length()).toUtf8(); + } + } else { + in >> frame.body_; + } + + return frame; +} + +QTextStream& operator <<(QTextStream& out, STOMPFrame::Command command) { + switch (command) { + case STOMPFrame::INVALID: + break; + + case STOMPFrame::STOMP: + out << "STOMP"; + break; + + case STOMPFrame::SEND: + out << "SEND"; + break; + + case STOMPFrame::SUBSCRIBE: + out << "SUBSCRIBE"; + break; + + case STOMPFrame::UNSUBSCRIBE: + out << "UNSUBSCRIBE"; + break; + + case STOMPFrame::BEGIN: + out << "BEGIN"; + break; + + case STOMPFrame::COMMIT: + out << "COMMIT"; + break; + + case STOMPFrame::ABORT: + out << "ABORT"; + break; + + case STOMPFrame::ACK: + out << "ACK"; + break; + + case STOMPFrame::NACK: + out << "NACK"; + break; + + case STOMPFrame::DISCONNECT: + out << "DISCONNECT"; + break; + + case STOMPFrame::CONNECTED: + out << "CONNECTED"; + break; + + case STOMPFrame::MESSAGE: + out << "MESSAGE"; + break; + + case STOMPFrame::RECEIPT: + out << "RECEIPT"; + break; + case STOMPFrame::ERROR: + out << "ERROR"; + break; + } + return out; +} diff --git a/stompframe.h b/stompframe.h new file mode 100644 index 0000000..d3352b6 --- /dev/null +++ b/stompframe.h @@ -0,0 +1,62 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +class STOMPFrame { + public: + enum Command { + INVALID, + + // Client messages + STOMP, SEND, SUBSCRIBE, UNSUBSCRIBE, BEGIN, COMMIT, ABORT, ACK, NACK, DISCONNECT, + + // Server messages + CONNECTED, MESSAGE, RECEIPT, ERROR + }; + + explicit STOMPFrame(Command command, std::initializer_list> headers = {}, const QByteArray& body = {}); + + bool isNull() const { + return command_ == INVALID; + } + + Command command() const { + return command_; + } + + void setCommand(Command command) { + command_ = command; + } + + const QMap& headers() const { + return headers_; + } + + void setHeaders(const QMap& headers) { + headers_ = headers; + } + + const QByteArray& body() const { + return body_; + } + + void setBody(const QByteArray& body) { + body_ = body; + } + + qint64 send(QIODevice& device); + static STOMPFrame receive(QIODevice& device); + + private: + STOMPFrame() = default; + + Command command_ = INVALID; + QMap headers_; + QByteArray body_; +}; + +QTextStream& operator <<(QTextStream& out, STOMPFrame::Command command);