//------------------------------------------------------------------------------ // File: SharedSerialization.cc // Author: Georgios Bitzes - CERN //------------------------------------------------------------------------------ /************************************************************************ * qclient - A simple redis C++ client with support for redirects * * Copyright (C) 2019 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ #include "SharedSerialization.hh" #include "qclient/shared/PendingRequestVault.hh" #include "qclient/utils/Macros.hh" #include "qclient/Debug.hh" #include "BinarySerializer.hh" #include namespace qclient { //------------------------------------------------------------------------------ //! Utilities for serializing the payload of messages intended for shared //! data structures. //------------------------------------------------------------------------------ std::string serializeBatch(const std::map &batch) { std::string retval; size_t retvalSize = 8; // 8 bytes for array size for(auto it = batch.begin(); it != batch.end(); it++) { // 8 bytes for key size + actual key retvalSize += 8 + it->first.size(); // 8 bytes for value size + actual value retvalSize += 8 + it->second.size(); } BinarySerializer serializer(retval, retvalSize); serializer.appendInt64(batch.size() * 2); for(auto it = batch.begin(); it != batch.end(); it++) { serializer.appendString(it->first); serializer.appendString(it->second); } return retval; } bool parseBatch(const std::string &payload, std::map &out) { out.clear(); BinaryDeserializer deserializer(payload); int64_t elements = 0; if(!deserializer.consumeInt64(elements)) return false; if(elements < 0 || elements % 2 != 0) return false; std::string key; for(int64_t i = 0; i < elements; i++) { std::string value; if(!deserializer.consumeString(value)) return false; // adjust output if(i % 2 != 0) { out[key] = value; } else { key = std::move(value); } } return true; } //------------------------------------------------------------------------------ //! Serialize Communicator request //------------------------------------------------------------------------------ std::string serializeCommunicatorRequest(const std::string &uuid, const std::string &contents) { std::string retval; // REQ (string) + uuid (string) + contents (string) size_t payloadSize = (8+3) + (8 + uuid.size()) + (8 + contents.size()); BinarySerializer serializer(retval, payloadSize); serializer.appendString("REQ"); serializer.appendString(uuid); serializer.appendString(contents); qclient_assert(serializer.getRemaining() == 0); return retval; } //------------------------------------------------------------------------------ //! Parse Communicator request //------------------------------------------------------------------------------ bool parseCommunicatorRequest(const std::string &payload, std::string &uuid, std::string &contents) { BinaryDeserializer deserializer(payload); std::string tmp; if(!deserializer.consumeString(tmp)) return false; if(tmp != "REQ") return false; if(!deserializer.consumeString(uuid)) return false; if(!deserializer.consumeString(contents)) return false; if(deserializer.bytesLeft() != 0) return false; return true; } //------------------------------------------------------------------------------ //! Serialize Communicator Reply //------------------------------------------------------------------------------ std::string serializeCommunicatorReply(const std::string &uuid, const CommunicatorReply &reply) { std::string retval; // RESP (string) + uuid (string) + status (int64) + contents (string) size_t payloadSize = (8 + 4) + (8 + uuid.size()) + (8) + (8 + reply.contents.size()); BinarySerializer serializer(retval, payloadSize); serializer.appendString("RESP"); serializer.appendString(uuid); serializer.appendInt64(reply.status); serializer.appendString(reply.contents); qclient_assert(serializer.getRemaining() == 0); return retval; } //------------------------------------------------------------------------------ //! Parse Communicator Reply //------------------------------------------------------------------------------ bool parseCommunicatorReply(const std::string &payload, CommunicatorReply &reply, std::string &uuid) { BinaryDeserializer deserializer(payload); std::string tmp; if(!deserializer.consumeString(tmp)) return false; if(tmp != "RESP") return false; if(!deserializer.consumeString(uuid)) return false; if(!deserializer.consumeInt64(reply.status)) return false; if(!deserializer.consumeString(reply.contents)) return false; if(deserializer.bytesLeft() != 0) return false; return true; } }