From 8a23aa89a58d3a90d5851b449b5552e1fcdcaded Mon Sep 17 00:00:00 2001 From: rtk0c Date: Mon, 27 Jun 2022 00:13:08 +0000 Subject: (From git) Initial server setup git-svn-id: file:///home/arch/svn/epistmool/trunk@4 71f44415-077c-4ad7-a976-72ddbf76608f --- .../source/EpistmoolServer/Protocol/CMakeLists.txt | 6 + .../source/EpistmoolServer/Protocol/Command.cpp | 200 +++++++++++++++++++++ .../source/EpistmoolServer/Protocol/Command.hpp | 124 +++++++++++++ .../source/EpistmoolServer/Protocol/Error.cpp | 1 + .../source/EpistmoolServer/Protocol/Error.hpp | 21 +++ .../source/EpistmoolServer/Protocol/Version.hpp | 9 + server-v1/source/EpistmoolServer/Protocol/fwd.hpp | 13 ++ 7 files changed, 374 insertions(+) create mode 100644 server-v1/source/EpistmoolServer/Protocol/CMakeLists.txt create mode 100644 server-v1/source/EpistmoolServer/Protocol/Command.cpp create mode 100644 server-v1/source/EpistmoolServer/Protocol/Command.hpp create mode 100644 server-v1/source/EpistmoolServer/Protocol/Error.cpp create mode 100644 server-v1/source/EpistmoolServer/Protocol/Error.hpp create mode 100644 server-v1/source/EpistmoolServer/Protocol/Version.hpp create mode 100644 server-v1/source/EpistmoolServer/Protocol/fwd.hpp (limited to 'server-v1/source/EpistmoolServer/Protocol') diff --git a/server-v1/source/EpistmoolServer/Protocol/CMakeLists.txt b/server-v1/source/EpistmoolServer/Protocol/CMakeLists.txt new file mode 100644 index 0000000..54f1da7 --- /dev/null +++ b/server-v1/source/EpistmoolServer/Protocol/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(EpistmoolServer PRIVATE + fwd.hpp + Command.hpp Command.cpp + Error.hpp Error.cpp + Version.hpp +) diff --git a/server-v1/source/EpistmoolServer/Protocol/Command.cpp b/server-v1/source/EpistmoolServer/Protocol/Command.cpp new file mode 100644 index 0000000..a108e0e --- /dev/null +++ b/server-v1/source/EpistmoolServer/Protocol/Command.cpp @@ -0,0 +1,200 @@ +#include "Command.hpp" + +#include +#include +#include + +using namespace Epistmool::Server; + +namespace { +auto kKindTraits = []() { + using enum ProtocolMessage::Kind; + std::array(KindCOUNT)> array; + + array[SessionAuth] = { .isC2S = true, .hasReply = true }; + array[SessionDestroy] = { .isC2S = true, .hasReply = true }; + + array[WorkspaceCreate] = { .isC2S = true, .hasReply = true }; + array[WorkspaceOpen] = { .isC2S = true, .hasReply = true }; + array[WorkspaceFetchIndex] = { .isC2S = true, .hasReply = true }; + + array[WorkspaceFetchKnowledge] = { .isC2S = true, .hasReply = true }; + array[WorkspaceUpdateKnowledge] = { .isC2S = true, .hasReply = true }; + array[WorkspaceCreateKnowledge] = { .isC2S = true, .hasReply = true }; + array[WorkspaceDeleteKnowledge] = { .isC2S = true, .hasReply = true }; + + array[WorkspaceFetchKeyword] = { .isC2S = true, .hasReply = true }; + array[WorkspaceUpdateKeyword] = { .isC2S = true, .hasReply = true }; + array[WorkspaceCreateKeyword] = { .isC2S = true, .hasReply = true }; + array[WorkspaceDeleteKeyword] = { .isC2S = true, .hasReply = true }; + + array[NotificationWorkspaceUpdated] = { .isC2S = false, .hasReply = false }; + array[NotificationKnowledgeUpdated] = { .isC2S = false, .hasReply = false }; + + return array; +}(); +} + +std::unique_ptr ProtocolMessage::createRequest(Kind kind) +{ + switch(kind) { + case SessionAuth: return std::make_unique(); + case SessionDestroy: return nullptr; + + case WorkspaceCreate: return nullptr; + case WorkspaceOpen: return nullptr; + case WorkspaceFetchIndex: return nullptr; + + case WorkspaceFetchKnowledge: return nullptr; + case WorkspaceUpdateKnowledge: return nullptr; + case WorkspaceCreateKnowledge: return nullptr; + case WorkspaceDeleteKnowledge: return nullptr; + + case WorkspaceFetchKeyword: return nullptr; + case WorkspaceUpdateKeyword: return nullptr; + case WorkspaceCreateKeyword: return nullptr; + case WorkspaceDeleteKeyword: return nullptr; + + case NotificationWorkspaceUpdated: return nullptr; + case NotificationKnowledgeUpdated: return nullptr; + + default: return nullptr; + } +} + +std::unique_ptr ProtocolMessage::createReply(Kind kind) +{ + switch(kind) { + case SessionAuth: return std::make_unique(); + case SessionDestroy: return nullptr; + + case WorkspaceCreate: return nullptr; + case WorkspaceOpen: return nullptr; + case WorkspaceFetchIndex: return nullptr; + + case WorkspaceFetchKnowledge: return nullptr; + case WorkspaceUpdateKnowledge: return nullptr; + case WorkspaceCreateKnowledge: return nullptr; + case WorkspaceDeleteKnowledge: return nullptr; + + case WorkspaceFetchKeyword: return nullptr; + case WorkspaceUpdateKeyword: return nullptr; + case WorkspaceCreateKeyword: return nullptr; + case WorkspaceDeleteKeyword: return nullptr; + + case NotificationWorkspaceUpdated: return nullptr; + case NotificationKnowledgeUpdated: return nullptr; + + default: return nullptr; + } +} + +const ProtocolMessage::KindTrait& ProtocolMessage::getKindTrait(Kind kind) +{ + return kKindTraits[kind]; +} + +ProtocolMessage::ProtocolMessage(Kind kind, Variant variant) + : kind{ kind } + , variant{ variant } +{ +} + +ProtocolRequest::ProtocolRequest(Kind kind) + : ProtocolMessage(kind, RequestVariant) +{ +} + +QJsonObject ProtocolRequest::serialize(const ProtocolRequest& msg) +{ + QJsonObject object; + object.insert("method", QMetaEnum::fromType().valueToKey(msg.kind)); + + QJsonObject fields; + msg.serializeFields(fields); + + return object; +} + +std::unique_ptr ProtocolRequest::deserialize(const QJsonObject& object) +{ + bool ok; + auto methodName = object.value("method").toString().toStdString(); + auto method = static_cast(QMetaEnum::fromType().keysToValue(methodName.c_str(), &ok)); + if (!ok) return nullptr; + + auto msg = createRequest(method); + + auto fieldsVal = object.value("fields"); + if (!fieldsVal.isObject()) return nullptr; + msg->deserializeFields(fieldsVal.toObject()); + + return msg; +} + +ProtocolReply::ProtocolReply(Kind kind) + : ProtocolMessage(kind, ReplyVariant) +{ +} + +QJsonObject ProtocolReply::serialize(const ProtocolReply& msg) +{ + QJsonObject object; + object.insert("method", QMetaEnum::fromType().valueToKey(msg.kind)); + object.insert("sequence", msg.sequence); + + QJsonObject fields; + msg.serializeFields(fields); + + return object; +} + +std::unique_ptr ProtocolReply::deserialize(const QJsonObject& object) +{ + bool ok; + auto methodName = object.value("method").toString().toStdString(); + auto method = static_cast(QMetaEnum::fromType().keysToValue(methodName.c_str(), &ok)); + if (!ok) return nullptr; + + auto msg = createReply(method); + + msg->sequence = object.value("sequence").toInt(-1); + + auto fieldsVal = object.value("fields"); + if (!fieldsVal.isObject()) return nullptr; + msg->deserializeFields(fieldsVal.toObject()); + + return msg; +} + +ProtocolRequest_SessionAuth::ProtocolRequest_SessionAuth() + : ProtocolRequest(SessionAuth) {} + +void ProtocolRequest_SessionAuth::serializeFields(QJsonObject& object) const +{ + ProtocolRequest::serializeFields(object); + object.insert("session", theSession); + object.insert("createIfInvalid", createIfInvalid); +} + +void ProtocolRequest_SessionAuth::deserializeFields(const QJsonObject& object) +{ + ProtocolRequest::deserializeFields(object); + theSession = object.value("session").toInt(); + createIfInvalid = object.value("createIfInvalid").toBool(); +} + +ProtocolReply_SessionAuth::ProtocolReply_SessionAuth() + : ProtocolReply(SessionAuth) {} + +void ProtocolReply_SessionAuth::serializeFields(QJsonObject& object) const +{ + ProtocolReply::serializeFields(object); + object.insert("session", theSession); +} + +void ProtocolReply_SessionAuth::deserializeFields(const QJsonObject& object) +{ + ProtocolReply::deserializeFields(object); + theSession = object.value("session").toInt(); +} diff --git a/server-v1/source/EpistmoolServer/Protocol/Command.hpp b/server-v1/source/EpistmoolServer/Protocol/Command.hpp new file mode 100644 index 0000000..9ec9786 --- /dev/null +++ b/server-v1/source/EpistmoolServer/Protocol/Command.hpp @@ -0,0 +1,124 @@ +#pragma once + +#include "all_fwd.hpp" + +#include +#include +#include +#include + +class QJsonObject; + +namespace Epistmool::Server { + +// Note: not all message kinds have a corresponding reply format. In such case the Kind enum is prefixed with 'Notification'. +class ProtocolMessage +{ + Q_GADGET + +public: + struct KindTrait + { + bool isC2S; + bool hasReply; + }; + + enum Kind + { + SessionAuth, + SessionDestroy, + + WorkspaceCreate, + WorkspaceOpen, + WorkspaceFetchIndex, + + WorkspaceFetchKnowledge, + WorkspaceUpdateKnowledge, + WorkspaceCreateKnowledge, + WorkspaceDeleteKnowledge, + + WorkspaceFetchKeyword, + WorkspaceUpdateKeyword, + WorkspaceCreateKeyword, + WorkspaceDeleteKeyword, + + NotificationWorkspaceUpdated, + NotificationKnowledgeUpdated, + + KindCOUNT, + }; + Q_ENUM(Kind) + + static std::unique_ptr createRequest(Kind kind); + static std::unique_ptr createReply(Kind kind); + static const KindTrait& getKindTrait(Kind kind); + + enum Variant + { + RequestVariant, + ReplyVariant, + }; + Q_ENUM(Variant) + +public: + Kind kind; + Variant variant; + +public: + ProtocolMessage(Kind kind, Variant variant); + virtual ~ProtocolMessage() = default; + +protected: + virtual void serializeFields(QJsonObject& object) const = 0; + virtual void deserializeFields(const QJsonObject& object) = 0; +}; + +struct ProtocolRequest : public ProtocolMessage +{ + ProtocolRequest(Kind kind); + static QJsonObject serialize(const ProtocolRequest& msg); + static std::unique_ptr deserialize(const QJsonObject& object); +}; + +struct ProtocolReply : public ProtocolMessage +{ + int sequence; + + ProtocolReply(Kind kind); + static QJsonObject serialize(const ProtocolReply& msg); + static std::unique_ptr deserialize(const QJsonObject& object); +}; + +// =========================== +// Individual messages classes + +struct ProtocolRequest_SessionAuth : public ProtocolRequest +{ + int theSession; + bool createIfInvalid; + + ProtocolRequest_SessionAuth(); + +protected: + virtual void serializeFields(QJsonObject& object) const override; + virtual void deserializeFields(const QJsonObject& object) override; +}; + +struct ProtocolReply_SessionAuth : public ProtocolReply +{ + /// The same value as provided in the request message. + /// If \l ProcotolCommandSessionAuth::createIfValid is set and the given session is invalid, a new session is created and written here instead of the original value. + int theSession; + + ProtocolReply_SessionAuth(); + +protected: + virtual void serializeFields(QJsonObject& object) const override; + virtual void deserializeFields(const QJsonObject& object) override; +}; + +struct ProtocolNotification_WorkspaceUpdate : public ProtocolRequest +{ +}; + +} // namespace Epistmool::Server diff --git a/server-v1/source/EpistmoolServer/Protocol/Error.cpp b/server-v1/source/EpistmoolServer/Protocol/Error.cpp new file mode 100644 index 0000000..5bf4840 --- /dev/null +++ b/server-v1/source/EpistmoolServer/Protocol/Error.cpp @@ -0,0 +1 @@ +#include "Error.hpp" diff --git a/server-v1/source/EpistmoolServer/Protocol/Error.hpp b/server-v1/source/EpistmoolServer/Protocol/Error.hpp new file mode 100644 index 0000000..1ddedf9 --- /dev/null +++ b/server-v1/source/EpistmoolServer/Protocol/Error.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "EpistmoolServer/Protocol/Version.hpp" + +#include +#include + +namespace Epistmool::Server { +struct ProtocolError +{ + QVersionNumber since; + QLatin1String name; +}; + +namespace ProtocolErrors { + const ProtocolError kUnsupportedVersion{ + .since = ProtocolVersions::v0_1, + .name = QLatin1String("unsupportedVersion"), + }; +} +} // namespace Epistmool::Server diff --git a/server-v1/source/EpistmoolServer/Protocol/Version.hpp b/server-v1/source/EpistmoolServer/Protocol/Version.hpp new file mode 100644 index 0000000..aae72bd --- /dev/null +++ b/server-v1/source/EpistmoolServer/Protocol/Version.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace Epistmool::Server { +namespace ProtocolVersions { + const QVersionNumber v0_1(0, 1); +} +} // namespace Epistmool::Server diff --git a/server-v1/source/EpistmoolServer/Protocol/fwd.hpp b/server-v1/source/EpistmoolServer/Protocol/fwd.hpp new file mode 100644 index 0000000..adf8138 --- /dev/null +++ b/server-v1/source/EpistmoolServer/Protocol/fwd.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace Epistmool::Server{ + +// Command.hpp +class ProtocolMessage; +struct ProtocolRequest; +struct ProtocolReply; + +// Error.hpp +struct ProtocolError; + +} // namespace Epistmool::Server -- cgit v1.2.3-70-g09d2