Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 42 additions & 44 deletions endpoint/core/include/privmx/endpoint/core/VarDeserializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ limitations under the License.

#include <Pson/BinaryString.hpp>
#include <privmx/utils/Utils.hpp>
#include <optional>
#include <string>
#include <vector>

#include "privmx/endpoint/core/BufferVarHolderImpl.hpp"
#include "privmx/endpoint/core/Exception.hpp"
Expand All @@ -31,94 +33,90 @@ namespace core {
class VarDeserializer {
public:
template<typename T>
T deserialize(const Poco::Dynamic::Var& value, const std::string& name) = delete;
T deserialize(const Poco::Dynamic::Var& value, const std::string& name);
template<typename T>
std::vector<T> deserializeVector(const Poco::Dynamic::Var& value, const std::string& name);
void deserialize(const Poco::Dynamic::Var& value, const std::string& name, T& out) = delete;
template<typename T>
std::optional<T> deserializeOptional(const Poco::Dynamic::Var& value, const std::string& name);
void deserialize(const Poco::Dynamic::Var& value, const std::string& name, std::vector<T>& out);
template<typename T>
std::optional<std::vector<T>> deserializeOptionalVector(const Poco::Dynamic::Var& val, const std::string& name);
void deserialize(const Poco::Dynamic::Var& value, const std::string& name, std::optional<T>& out);
template<typename T>
std::shared_ptr<T>* deserializePointer(const Poco::Dynamic::Var& value, const std::string& name);
void deserialize(const Poco::Dynamic::Var& value, const std::string& name, std::optional<std::vector<T>>& out);
template<typename T>
void deserialize(const Poco::Dynamic::Var& value, const std::string& name, std::shared_ptr<T>*& out);
};

template<typename T>
inline std::vector<T> VarDeserializer::deserializeVector(const Poco::Dynamic::Var& val, const std::string& name) {
std::vector<T> res;
inline T VarDeserializer::deserialize(const Poco::Dynamic::Var& value, const std::string& name) {
T tmp{};
deserialize(value, name, tmp);
return tmp;
}

template<typename T>
inline void VarDeserializer::deserialize(const Poco::Dynamic::Var& val, const std::string& name, std::vector<T>& out) {
TypeValidator::validateArray(val, name);
Poco::JSON::Array::Ptr arr = val.extract<Poco::JSON::Array::Ptr>();
res.reserve(arr->size());
out.reserve(arr->size());
for (const auto& item : *arr) {
res.emplace_back(deserialize<T>(item, name + "[]"));
T elem{};
deserialize(item, name + "[]", elem);
out.emplace_back(std::move(elem));
}
return res;
}

template<typename T>
inline std::optional<T> VarDeserializer::deserializeOptional(const Poco::Dynamic::Var& val, const std::string& name) {
inline void VarDeserializer::deserialize(const Poco::Dynamic::Var& val, const std::string& name, std::optional<T>& out) {
if (val.isEmpty()) {
return std::nullopt;
out = std::nullopt;
return;
}
return deserialize<T>(val, name);
T tmp{};
deserialize(val, name, tmp);
out = std::move(tmp);
}

template<typename T>
inline std::optional<std::vector<T>> VarDeserializer::deserializeOptionalVector(const Poco::Dynamic::Var& val, const std::string& name) {
inline void VarDeserializer::deserialize(const Poco::Dynamic::Var& val, const std::string& name, std::optional<std::vector<T>>& out) {
if (val.isEmpty()) {
return std::nullopt;
out = std::nullopt;
return;
}
return deserializeVector<T>(val, name);
std::vector<T> tmp;
deserialize(val, name, tmp);
out = std::move(tmp);
}

template<typename T>
std::shared_ptr<T>* VarDeserializer::deserializePointer(const Poco::Dynamic::Var& value, const std::string& name) {
inline void VarDeserializer::deserialize(const Poco::Dynamic::Var& value, const std::string& name, std::shared_ptr<T>*& out) {
if (value.isEmpty()) {
throw InvalidArgumentTypeException(name + " | Expected pointer, value is empty");
}
if (!value.isInteger()) {
throw InvalidArgumentTypeException(name + " | Expected pointer, value has type " + value.type().name());
}
return reinterpret_cast<std::shared_ptr<T>*>(static_cast<uintptr_t>(value.convert<Poco::Int64>()));
out = reinterpret_cast<std::shared_ptr<T>*>(static_cast<uintptr_t>(value.convert<Poco::Int64>()));
}

template<>
int64_t VarDeserializer::deserialize<int64_t>(const Poco::Dynamic::Var& val, const std::string& name);

template<>
std::string VarDeserializer::deserialize<std::string>(const Poco::Dynamic::Var& val, const std::string& name);

template<>
Buffer VarDeserializer::deserialize<Buffer>(const Poco::Dynamic::Var& val, const std::string& name);

template<>
bool VarDeserializer::deserialize<bool>(const Poco::Dynamic::Var& val, const std::string& name);
void VarDeserializer::deserialize<int64_t>(const Poco::Dynamic::Var& val, const std::string& name, int64_t& out);

template<>
Poco::JSON::Object::Ptr VarDeserializer::deserialize<Poco::JSON::Object::Ptr>(const Poco::Dynamic::Var& val, const std::string& name);
void VarDeserializer::deserialize<std::string>(const Poco::Dynamic::Var& val, const std::string& name, std::string& out);

template<>
UserWithPubKey VarDeserializer::deserialize<UserWithPubKey>(const Poco::Dynamic::Var& val, const std::string& name);
void VarDeserializer::deserialize<Buffer>(const Poco::Dynamic::Var& val, const std::string& name, Buffer& out);

template<>
PagingQuery VarDeserializer::deserialize<PagingQuery>(const Poco::Dynamic::Var& val, const std::string& name);
void VarDeserializer::deserialize<bool>(const Poco::Dynamic::Var& val, const std::string& name, bool& out);

template<>
ContainerPolicyWithoutItem VarDeserializer::deserialize<ContainerPolicyWithoutItem>(const Poco::Dynamic::Var& val, const std::string& name);

template<>
ContainerPolicy VarDeserializer::deserialize<ContainerPolicy>(const Poco::Dynamic::Var& val, const std::string& name);

template<>
PKIVerificationOptions VarDeserializer::deserialize<PKIVerificationOptions>(const Poco::Dynamic::Var& val, const std::string& name);

template<>
core::EventType VarDeserializer::deserialize<core::EventType>(const Poco::Dynamic::Var& val, const std::string& name);

template<>
core::EventSelectorType VarDeserializer::deserialize<core::EventSelectorType>(const Poco::Dynamic::Var& val, const std::string& name);
void VarDeserializer::deserialize<Poco::JSON::Object::Ptr>(const Poco::Dynamic::Var& val, const std::string& name, Poco::JSON::Object::Ptr& out);

} // namespace core
} // namespace endpoint
} // namespace privmx

#include "privmx/endpoint/core/VarSerialization.hpp"

#endif // _PRIVMXLIB_ENDPOINT_CORE_VARDESERIALIZER_HPP_
178 changes: 178 additions & 0 deletions endpoint/core/include/privmx/endpoint/core/VarSerialization.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*
PrivMX Endpoint.
Copyright © 2026 Simplito sp. z o.o.

This file is part of the PrivMX Platform (https://privmx.dev).
This software is Licensed under the PrivMX Free License.

See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef _PRIVMXLIB_ENDPOINT_CORE_VARSERIALIZATION_HPP_
#define _PRIVMXLIB_ENDPOINT_CORE_VARSERIALIZATION_HPP_

#include "privmx/endpoint/core/CoreException.hpp"
#include "privmx/endpoint/core/Types.hpp"
#include "privmx/endpoint/core/VarDeserializer.hpp"
#include "privmx/endpoint/core/VarSerializer.hpp"
#include "privmx/endpoint/core/VarSerializationMacros.hpp"

namespace privmx {
namespace endpoint {
namespace core {

// ---------------------------------------------------------------------------
// Standard types — field layout matches struct, no custom __type string
// ---------------------------------------------------------------------------

VAR_DEFINE_TYPE(UserWithPubKey, userId, pubKey)
VAR_DEFINE_TYPE(Context, userId, contextId)
VAR_DEFINE_TYPE(CollectionItemChange, itemId, action)
VAR_DEFINE_TYPE(CollectionChangedEventData, moduleType, moduleId, affectedItemsCount, items)
VAR_DEFINE_TYPE(ContextUserEventData, contextId, user)
VAR_DEFINE_TYPE(UserWithAction, user, action)
VAR_DEFINE_TYPE(ContainerPolicyWithoutItem, get, update, delete_, updatePolicy, updaterCanBeRemovedFromManagers, ownerCanBeRemovedFromManagers)
VAR_DEFINE_TYPE(ItemPolicy, get, listMy, listAll, create, update, delete_)
VAR_DEFINE_TYPE(UserStatusChange, action, timestamp)
VAR_DEFINE_TYPE(UserInfo, user, isActive, lastStatusChange)
VAR_DEFINE_TYPE(BridgeIdentity, url, pubKey, instanceId)
VAR_DEFINE_TYPE(VerificationRequest, contextId, senderId, senderPubKey, date, bridgeIdentity)
VAR_DEFINE_TYPE(PagingQuery, skip, limit, sortOrder, lastId, sortBy, queryAsJson)
VAR_DEFINE_TYPE(PKIVerificationOptions, bridgePubKey, bridgeInstanceId)

VAR_DEFINE_TYPE(PagingList<Context>, totalAvailable, readItems) // FIXME: custom __type
VAR_DEFINE_TYPE(PagingList<UserInfo>, totalAvailable, readItems) // FIXME: custom __type

// ---------------------------------------------------------------------------
// PagingList<T> — custom __type strings
// ---------------------------------------------------------------------------

// template<>
// inline Poco::Dynamic::Var VarSerializer::serialize<PagingList<Context>>(const PagingList<Context>& val) {
// Poco::JSON::Object::Ptr obj = new Poco::JSON::Object();
// if (_options.addType) { obj->set("__type", "core$PagingList<core$Context>"); }
// obj->set("totalAvailable", serialize(val.totalAvailable));
// obj->set("readItems", serialize(val.readItems));
// return obj;
// }

// template<>
// inline Poco::Dynamic::Var VarSerializer::serialize<PagingList<UserInfo>>(const PagingList<UserInfo>& val) {
// Poco::JSON::Object::Ptr obj = new Poco::JSON::Object();
// if (_options.addType) { obj->set("__type", "core$PagingList<core$UserInfo>"); }
// obj->set("totalAvailable", serialize(val.totalAvailable));
// obj->set("readItems", serialize(val.readItems));
// return obj;
// }

// ---------------------------------------------------------------------------
// Event types — delegate to serializeBase / serializeBaseWithData
// ---------------------------------------------------------------------------

template<>
inline Poco::Dynamic::Var VarSerializer::serialize<LibPlatformDisconnectedEvent>(const LibPlatformDisconnectedEvent& val) {
return serializeBase<Event>(val, "core$LibPlatformDisconnectedEvent");
}

template<>
inline Poco::Dynamic::Var VarSerializer::serialize<LibConnectedEvent>(const LibConnectedEvent& val) {
return serializeBase<Event>(val, "core$LibConnectedEvent");
}

template<>
inline Poco::Dynamic::Var VarSerializer::serialize<LibDisconnectedEvent>(const LibDisconnectedEvent& val) {
return serializeBase<Event>(val, "core$LibDisconnectedEvent");
}

template<>
inline Poco::Dynamic::Var VarSerializer::serialize<LibBreakEvent>(const LibBreakEvent& val) {
return serializeBase<Event>(val, "core$LibBreakEvent");
}

template<>
inline Poco::Dynamic::Var VarSerializer::serialize<ContextUsersStatusChangedEventData>(const ContextUsersStatusChangedEventData& val) {
Poco::JSON::Object::Ptr obj = new Poco::JSON::Object();
if (_options.addType) { obj->set("__type", "core$ContextUsersStatusChangeData"); }
obj->set("contextId", serialize(val.contextId));
obj->set("users", serialize(val.users));
return obj;
}

template<>
inline Poco::Dynamic::Var VarSerializer::serialize<ContextUserAddedEvent>(const ContextUserAddedEvent& val) {
return serializeBaseWithData<Event>(val, "core$ContextUserAddedEvent");
}

template<>
inline Poco::Dynamic::Var VarSerializer::serialize<ContextUserRemovedEvent>(const ContextUserRemovedEvent& val) {
return serializeBaseWithData<Event>(val, "core$ContextUserRemovedEvent");
}

template<>
inline Poco::Dynamic::Var VarSerializer::serialize<ContextUsersStatusChangedEvent>(const ContextUsersStatusChangedEvent& val) {
return serializeBaseWithData<Event>(val, "core$ContextUsersStatusChangedEvent");
}

template<>
inline Poco::Dynamic::Var VarSerializer::serialize<CollectionChangedEvent>(const CollectionChangedEvent& val) {
return serializeBaseWithData<Event>(val, "core$CollectionChangedEvent");
}

// ---------------------------------------------------------------------------
// ContainerPolicy — serializer extends ContainerPolicyWithoutItem
// ---------------------------------------------------------------------------

template<>
inline Poco::Dynamic::Var VarSerializer::serialize<ContainerPolicy>(const ContainerPolicy& val) {
auto varN = serialize<ContainerPolicyWithoutItem>(val);
Poco::JSON::Object::Ptr obj = varN.extract<Poco::JSON::Object::Ptr>();
if (_options.addType) { obj->set("__type", "core$ContainerPolicy"); }
obj->set("item", serialize(val.item));
return obj;
}

// ContainerPolicy deserializer — cannot reuse VAR_DEFINE_TYPE (inherits WithoutItem fields)
template<>
inline void VarDeserializer::deserialize<ContainerPolicy>(
const Poco::Dynamic::Var& val, const std::string& name, ContainerPolicy& out) {
TypeValidator::validateObject(val, name);
Poco::JSON::Object::Ptr obj = val.extract<Poco::JSON::Object::Ptr>();
deserialize(obj->get("get"), name + ".get", out.get);
deserialize(obj->get("update"), name + ".update", out.update);
deserialize(obj->get("delete_"), name + ".delete_", out.delete_);
deserialize(obj->get("updatePolicy"), name + ".updatePolicy", out.updatePolicy);
deserialize(obj->get("updaterCanBeRemovedFromManagers"), name + ".updaterCanBeRemovedFromManagers", out.updaterCanBeRemovedFromManagers);
deserialize(obj->get("ownerCanBeRemovedFromManagers"), name + ".ownerCanBeRemovedFromManagers", out.ownerCanBeRemovedFromManagers);
deserialize(obj->get("item"), name + ".item", out.item);
}

// ---------------------------------------------------------------------------
// Enum deserializers — switch on integer value
// ---------------------------------------------------------------------------

template<>
inline void VarDeserializer::deserialize<EventType>(
const Poco::Dynamic::Var& val, const std::string& name, EventType& out) {
switch (val.convert<int64_t>()) {
case core::EventType::USER_ADD: out = core::EventType::USER_ADD; return;
case core::EventType::USER_REMOVE: out = core::EventType::USER_REMOVE; return;
case core::EventType::USER_STATUS: out = core::EventType::USER_STATUS; return;
}
throw InvalidParamsException(name + " | Unknown thread::EventType value, received " + std::to_string(val.convert<int64_t>()));
}

template<>
inline void VarDeserializer::deserialize<EventSelectorType>(
const Poco::Dynamic::Var& val, const std::string& name, EventSelectorType& out) {
switch (val.convert<int64_t>()) {
case core::EventSelectorType::CONTEXT_ID: out = core::EventSelectorType::CONTEXT_ID; return;
}
throw InvalidParamsException(name + " | Unknown thread::EventSelectorType value, received " + std::to_string(val.convert<int64_t>()));
}

} // namespace core
} // namespace endpoint
} // namespace privmx

#endif // _PRIVMXLIB_ENDPOINT_CORE_VARSERIALIZATION_HPP_
Loading
Loading