#ifndef COMMUNICATION_PROTO_API_IMPL_H #define COMMUNICATION_PROTO_API_IMPL_H #include #ifdef _WIN32 #pragma warning(push, 0) #endif #include #include #include #ifdef _WIN32 #pragma warning(pop) #endif namespace icsneo { namespace protoapi { enum class Command : uint8_t { Unspecified = 0, GET = 1, PUT = 2, PATCH = 3, }; enum class Id : uint32_t { Unspecified = 0, MfgConfig = 1, CpuId = 2, NetworkMutex = 3, ClientId = 4, }; template struct IDLookup { constexpr static common::v1::ProtoId value = common::v1::ProtoId::PROTO_ID_UNSPECIFIED; }; template <> struct IDLookup { constexpr static common::v1::ProtoId value = common::v1::ProtoId::PROTO_ID_NETWORK_MUTEX; }; template <> struct IDLookup { constexpr static common::v1::ProtoId value = common::v1::ProtoId::PROTO_ID_GET_CLIENT_ID; }; inline uint8_t* writeVarint32(uint32_t value, uint8_t* target) { return google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(value, target); } inline const uint8_t* readVarint32(uint32_t& value, const uint8_t* source) { value = 0; do { value <<= 7; value += *source & 0x7F; } while(*source++ & 0x80); return source; } template std::vector getPayload(Command command, const T& msg) { std::vector payload; constexpr uint32_t proto_version = 1; common::v1::ProtoHeader hdr; hdr.set_version(proto_version); hdr.set_api_command(static_cast(command)); hdr.set_auth_method(common::v1::AuthMethod::PROTO_API_AUTH_NONE); // TODO hdr.set_proto_id(IDLookup::value); static constexpr size_t varint_size_max = 5; size_t header_size = hdr.ByteSizeLong(); size_t msg_size = msg.ByteSizeLong(); size_t payload_size_max = header_size + msg_size + (varint_size_max * 2); // TODO: auth payload.resize(payload_size_max); uint8_t* target = payload.data(); target = writeVarint32(static_cast(header_size), target); hdr.SerializeToArray(target, static_cast(header_size)); target += header_size; if(msg_size) { target = writeVarint32(static_cast(msg_size), target); msg.SerializeToArray(target, static_cast(msg_size)); target += msg_size; } payload.resize(target - payload.data()); return payload; } template bool processResponse(const uint8_t* payload, size_t /* payload_length */, T& msg) { // TODO: we should probably check payload_length throughout to not go past the end of the supplied buffer // header common::v1::ProtoHeader hdr; uint32_t length; const uint8_t* serialized = readVarint32(length, payload); if(!hdr.ParseFromArray(serialized, length)) { return false; } // message payload serialized = readVarint32(length, serialized + length); if(!msg.ParseFromArray(serialized, length)) { return false; } return true; } inline Id getProtoId(const uint8_t* payload, size_t /* payload_length */) { // TODO: we should probably check this throughout to not go past the end of the supplied buffer // header common::v1::ProtoHeader hdr; uint32_t length; const uint8_t* serialized = readVarint32(length, payload); if(!hdr.ParseFromArray(serialized, length)) { return Id::Unspecified; } return static_cast(hdr.proto_id()); } } // namespace protoapi } // namespace icsneo #endif