mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-05-02 22:25:04 -04:00
Implement automatic JSON API generation
qmake file add jsonapi-generator target to compile JSON API generator qmake files add rs_jsonapi CONFIG option to enable/disable JSON API at compile time RsTypeSerializer pass down same serialization flags when creating new context for nested objects serial job RsGxsChannels expose a few methods through JSON API as example Derive a few GXS types (RsGxsChannelGroup, RsGxsChannelPost, RsGxsFile, RsMsgMetaData) from RsSerializables so they can be used for the JSON API Create RsGenericSerializer::SERIALIZATION_FLAG_YIELDING so JSON objects that miss some fields can be still deserialized, this improve API usability SerializeContext offer friendly constructor with default paramethers Add restbed 4.6 library as git submodule as most systems doesn't have it yet Add a bit of documentation about JSON API into jsonapi-generator/README.adoc Add JsonApiServer class to expose the JSON API via HTTP protocol
This commit is contained in:
parent
2f159efb10
commit
7ad337c8d2
22 changed files with 1205 additions and 83 deletions
45
libretroshare/src/jsonapi/jsonapi.cpp
Normal file
45
libretroshare/src/jsonapi/jsonapi.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* RetroShare JSON API
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "jsonapi.h"
|
||||
|
||||
// Generated at compile time
|
||||
#include "jsonapi-wrappers.h"
|
||||
|
||||
JsonApiServer::JsonApiServer(uint16_t port) : mPort(port)
|
||||
{
|
||||
// Generated at compile time
|
||||
#include "jsonapi-register.inl"
|
||||
}
|
||||
|
||||
void JsonApiServer::run()
|
||||
{
|
||||
std::shared_ptr<rb::Settings> settings(new rb::Settings);
|
||||
settings->set_port(mPort);
|
||||
settings->set_default_header("Connection", "close");
|
||||
service.start(settings);
|
||||
}
|
||||
|
||||
void JsonApiServer::registerHandler(const std::string& path, const std::function<void (const std::shared_ptr<restbed::Session>)>& handler)
|
||||
{
|
||||
std::shared_ptr<restbed::Resource> resource(new rb::Resource);
|
||||
resource->set_path(path);
|
||||
resource->set_method_handler("GET", handler);
|
||||
resource->set_method_handler("POST", handler);
|
||||
service.publish(resource);
|
||||
}
|
62
libretroshare/src/jsonapi/jsonapi.h
Normal file
62
libretroshare/src/jsonapi/jsonapi.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* RetroShare JSON API
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <restbed>
|
||||
#include <rapid_json/document.h>
|
||||
|
||||
#include "retroshare/rsgxschannels.h"
|
||||
#include "serialiser/rstypeserializer.h"
|
||||
#include "util/rsthreads.h"
|
||||
|
||||
namespace rb = restbed;
|
||||
|
||||
void apiVersionHandler(const std::shared_ptr<rb::Session> session);
|
||||
void createChannelHandler(const std::shared_ptr<rb::Session> session);
|
||||
|
||||
/**
|
||||
* Simple usage
|
||||
* \code{.cpp}
|
||||
* JsonApiServer jas(9092);
|
||||
* jas.start("JsonApiServer");
|
||||
* \endcode
|
||||
*/
|
||||
struct JsonApiServer : RsSingleJobThread
|
||||
{
|
||||
JsonApiServer(uint16_t port);
|
||||
|
||||
/// @see RsSingleJobThread
|
||||
virtual void run();
|
||||
|
||||
/**
|
||||
* @param[in] handler function which will be called to handle the requested
|
||||
* path, the function must be declared like:
|
||||
* \code{.cpp}
|
||||
* void functionName(const shared_ptr<restbed::Session> session)
|
||||
* \endcode
|
||||
*/
|
||||
void registerHandler(
|
||||
const std::string& path,
|
||||
const std::function<void(const std::shared_ptr<rb::Session>)>& handler );
|
||||
|
||||
private:
|
||||
uint16_t mPort;
|
||||
rb::Service service;
|
||||
};
|
||||
|
|
@ -849,6 +849,64 @@ rs_gxs_trans {
|
|||
SOURCES += gxstrans/p3gxstransitems.cc gxstrans/p3gxstrans.cc
|
||||
}
|
||||
|
||||
rs_jsonapi {
|
||||
JSONAPI_GENERATOR_SRC=$$system_path($$clean_path($${RS_SRC_PATH}/jsonapi-generator/src/))
|
||||
JSONAPI_GENERATOR_OUT=$$system_path($$clean_path($${RS_BUILD_PATH}/jsonapi-generator/src/))
|
||||
JSONAPI_GENERATOR_EXE=$$system_path($$clean_path($${JSONAPI_GENERATOR_OUT}/jsonapi-generator))
|
||||
DOXIGEN_INPUT_DIRECTORY=$$system_path($$clean_path($${PWD}/retroshare/))
|
||||
DOXIGEN_CONFIG_SRC=$$system_path($$clean_path($${RS_SRC_PATH}/jsonapi-generator/src/jsonapi-generator-doxygen.conf))
|
||||
DOXIGEN_CONFIG_OUT=$$system_path($$clean_path($${JSONAPI_GENERATOR_OUT}/jsonapi-generator-doxygen.conf))
|
||||
WRAPPERS_DEF_FILE=$$system_path($$clean_path($${JSONAPI_GENERATOR_OUT}/jsonapi-wrappers.cpp))
|
||||
WRAPPERS_DECL_FILE=$$system_path($$clean_path($${JSONAPI_GENERATOR_OUT}/jsonapi-wrappers.h))
|
||||
WRAPPERS_REG_FILE=$$system_path($$clean_path($${JSONAPI_GENERATOR_OUT}/jsonapi-register.inl))
|
||||
|
||||
restbed.target = $$system_path($$clean_path($${RESTBED_BUILD_PATH}/library/librestbed.a))
|
||||
restbed.commands = \
|
||||
cd $${RS_SRC_PATH}; git submodule update --init --recursive;\
|
||||
mkdir -p $${RESTBED_BUILD_PATH}; cd $${RESTBED_BUILD_PATH};\
|
||||
cmake -DBUILD_SSL=OFF -DCMAKE_INSTALL_PREFIX=. -B. -H$${RESTBED_SRC_PATH};\
|
||||
make; make install
|
||||
QMAKE_EXTRA_TARGETS += restbed
|
||||
libretroshare.depends += restbed
|
||||
PRE_TARGETDEPS *= $${restbed.target}
|
||||
|
||||
PRE_TARGETDEPS *= $${JSONAPI_GENERATOR_EXE}
|
||||
INCLUDEPATH *= $${JSONAPI_GENERATOR_OUT}
|
||||
GENERATED_HEADERS += $${WRAPPERS_DECL_FILE} $${WRAPPERS_REG_FILE}
|
||||
GENERATED_SOURCES += $${WRAPPERS_DEF_FILE}
|
||||
|
||||
jsonwrappersdecl.target = $${WRAPPERS_DECL_FILE}
|
||||
jsonwrappersdecl.commands = \
|
||||
cp $${DOXIGEN_CONFIG_SRC} $${DOXIGEN_CONFIG_OUT}; \
|
||||
echo OUTPUT_DIRECTORY=$${JSONAPI_GENERATOR_OUT} >> $${DOXIGEN_CONFIG_OUT};\
|
||||
echo INPUT=$${DOXIGEN_INPUT_DIRECTORY} >> $${DOXIGEN_CONFIG_OUT}; \
|
||||
doxygen $${DOXIGEN_CONFIG_OUT}; \
|
||||
$${JSONAPI_GENERATOR_EXE} $${JSONAPI_GENERATOR_SRC} $${JSONAPI_GENERATOR_OUT};
|
||||
QMAKE_EXTRA_TARGETS += jsonwrappersdecl
|
||||
libretroshare.depends += jsonwrappersdecl
|
||||
PRE_TARGETDEPS *= $${WRAPPERS_DECL_FILE}
|
||||
|
||||
jsonwrappersdef.target = $${WRAPPERS_DEF_FILE}
|
||||
jsonwrappersdef.commands = touch $${WRAPPERS_DEF_FILE}
|
||||
jsonwrappersdef.depends = jsonwrappersdecl
|
||||
QMAKE_EXTRA_TARGETS += jsonwrappersdef
|
||||
libretroshare.depends += jsonwrappersdef
|
||||
PRE_TARGETDEPS *= $${WRAPPERS_DEF_FILE}
|
||||
|
||||
jsonwrappersreg.target = $${WRAPPERS_REG_FILE}
|
||||
jsonwrappersreg.commands = touch $${WRAPPERS_REG_FILE}
|
||||
jsonwrappersreg.depends = jsonwrappersdef
|
||||
QMAKE_EXTRA_TARGETS += jsonwrappersreg
|
||||
libretroshare.depends += jsonwrappersreg
|
||||
PRE_TARGETDEPS *= $${WRAPPERS_REG_FILE}
|
||||
|
||||
# Force recalculation of libretroshare dependencies see https://stackoverflow.com/a/47884045
|
||||
QMAKE_EXTRA_TARGETS += libretroshare
|
||||
|
||||
HEADERS += jsonapi/jsonapi.h
|
||||
SOURCES += jsonapi/jsonapi.cpp
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
*
|
||||
* RetroShare C++ Interface.
|
||||
*
|
||||
* Copyright 2012-2012 by Robert Fernie.
|
||||
* Copyright (C) 2012 by Robert Fernie.
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
@ -33,35 +34,47 @@
|
|||
#include "retroshare/rstokenservice.h"
|
||||
#include "retroshare/rsgxsifacehelper.h"
|
||||
#include "retroshare/rsgxscommon.h"
|
||||
#include "serialiser/rsserializable.h"
|
||||
|
||||
|
||||
|
||||
/* The Main Interface Class - for information about your Peers */
|
||||
class RsGxsChannels;
|
||||
extern RsGxsChannels *rsGxsChannels;
|
||||
|
||||
/**
|
||||
* Pointer to global instance of RsGxsChannels service implementation
|
||||
* @jsonapi{development}
|
||||
*/
|
||||
extern RsGxsChannels* rsGxsChannels;
|
||||
|
||||
// These should be in rsgxscommon.h
|
||||
|
||||
class RsGxsChannelGroup
|
||||
struct RsGxsChannelGroup : RsSerializable
|
||||
{
|
||||
public:
|
||||
RsGroupMetaData mMeta;
|
||||
std::string mDescription;
|
||||
RsGxsImage mImage;
|
||||
|
||||
bool mAutoDownload;
|
||||
|
||||
/// @see RsSerializable
|
||||
virtual void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx )
|
||||
{
|
||||
RS_SERIAL_PROCESS(mMeta);
|
||||
RS_SERIAL_PROCESS(mDescription);
|
||||
//RS_SERIAL_PROCESS(mImage);
|
||||
RS_SERIAL_PROCESS(mAutoDownload);
|
||||
}
|
||||
};
|
||||
|
||||
class RsGxsChannelPost
|
||||
std::ostream &operator<<(std::ostream& out, const RsGxsChannelGroup& group);
|
||||
|
||||
|
||||
struct RsGxsChannelPost : RsSerializable
|
||||
{
|
||||
public:
|
||||
RsGxsChannelPost() : mCount(0), mSize(0) {}
|
||||
|
||||
public:
|
||||
RsMsgMetaData mMeta;
|
||||
|
||||
std::set<RsGxsMessageId> mOlderVersions ;
|
||||
std::set<RsGxsMessageId> mOlderVersions;
|
||||
std::string mMsg; // UTF8 encoded.
|
||||
|
||||
std::list<RsGxsFile> mFiles;
|
||||
|
@ -69,18 +82,31 @@ public:
|
|||
uint64_t mSize; // auto calced.
|
||||
|
||||
RsGxsImage mThumbnail;
|
||||
|
||||
/// @see RsSerializable
|
||||
virtual void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx )
|
||||
{
|
||||
RS_SERIAL_PROCESS(mMeta);
|
||||
RS_SERIAL_PROCESS(mOlderVersions);
|
||||
|
||||
RS_SERIAL_PROCESS(mMsg);
|
||||
RS_SERIAL_PROCESS(mFiles);
|
||||
RS_SERIAL_PROCESS(mCount);
|
||||
RS_SERIAL_PROCESS(mSize);
|
||||
//RS_SERIAL_PROCESS(mThumbnail);
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream& out, const RsGxsChannelPost& post);
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const RsGxsChannelGroup &group);
|
||||
std::ostream &operator<<(std::ostream &out, const RsGxsChannelPost &post);
|
||||
|
||||
class RsGxsChannels: public RsGxsIfaceHelper, public RsGxsCommentService
|
||||
{
|
||||
public:
|
||||
public:
|
||||
|
||||
explicit RsGxsChannels(RsGxsIface *gxs)
|
||||
:RsGxsIfaceHelper(gxs) {}
|
||||
:RsGxsIfaceHelper(gxs) {}
|
||||
virtual ~RsGxsChannels() {}
|
||||
|
||||
/* Specific Service Data */
|
||||
|
@ -103,7 +129,16 @@ virtual bool setChannelAutoDownload(const RsGxsGroupId &groupId, bool enabled) =
|
|||
virtual bool getChannelAutoDownload(const RsGxsGroupId &groupid, bool& enabled) = 0;
|
||||
|
||||
virtual bool setChannelDownloadDirectory(const RsGxsGroupId &groupId, const std::string& directory)=0;
|
||||
virtual bool getChannelDownloadDirectory(const RsGxsGroupId &groupId, std::string& directory)=0;
|
||||
|
||||
/**
|
||||
* Get download directory for the given channel
|
||||
* @jsonapi{development}
|
||||
* @param[in] channelId id of the channel
|
||||
* @param[out] directory reference to string where to store the path
|
||||
* @return false on error, true otherwise
|
||||
*/
|
||||
virtual bool getChannelDownloadDirectory( const RsGxsGroupId& channelId,
|
||||
std::string& directory ) = 0;
|
||||
|
||||
//virtual void setChannelAutoDownload(uint32_t& token, const RsGxsGroupId& groupId, bool autoDownload) = 0;
|
||||
|
||||
|
@ -113,19 +148,59 @@ virtual bool getChannelDownloadDirectory(const RsGxsGroupId &groupId, std::strin
|
|||
//virtual bool groupRestoreKeys(const std::string &groupId);
|
||||
virtual bool groupShareKeys(const RsGxsGroupId &groupId, std::set<RsPeerId>& peers)=0;
|
||||
|
||||
// Overloaded subscribe fn.
|
||||
virtual bool subscribeToGroup(uint32_t &token, const RsGxsGroupId &groupId, bool subscribe) = 0;
|
||||
/**
|
||||
* @brief Request subscription to a group.
|
||||
* The action is performed asyncronously, so it could fail in a subsequent
|
||||
* phase even after returning true.
|
||||
* @jsonapi{development}
|
||||
* @param[out] token Storage for RsTokenService token to track request
|
||||
* status.
|
||||
* @param[in] groupId Channel id
|
||||
* @param[in] subscribe
|
||||
* @return false on error, true otherwise
|
||||
*/
|
||||
virtual bool subscribeToGroup( uint32_t& token, const RsGxsGroupId &groupId,
|
||||
bool subscribe ) = 0;
|
||||
|
||||
virtual bool createGroup(uint32_t &token, RsGxsChannelGroup &group) = 0;
|
||||
virtual bool createPost(uint32_t &token, RsGxsChannelPost &post) = 0;
|
||||
/**
|
||||
* @brief Request channel creation.
|
||||
* The action is performed asyncronously, so it could fail in a subsequent
|
||||
* phase even after returning true.
|
||||
* @jsonapi{development}
|
||||
* @param[out] token Storage for RsTokenService token to track request
|
||||
* status.
|
||||
* @param[in] group Channel data (name, description...)
|
||||
* @return false on error, true otherwise
|
||||
*/
|
||||
virtual bool createGroup(uint32_t& token, RsGxsChannelGroup& group) = 0;
|
||||
|
||||
virtual bool updateGroup(uint32_t &token, RsGxsChannelGroup &group) = 0;
|
||||
/**
|
||||
* @brief Request post creation.
|
||||
* The action is performed asyncronously, so it could fail in a subsequent
|
||||
* phase even after returning true.
|
||||
* @jsonapi{development}
|
||||
* @param[out] token Storage for RsTokenService token to track request
|
||||
* status.
|
||||
* @param[in] post
|
||||
* @return false on error, true otherwise
|
||||
*/
|
||||
virtual bool createPost(uint32_t& token, RsGxsChannelPost& post) = 0;
|
||||
|
||||
/**
|
||||
* @brief Request channel change.
|
||||
* The action is performed asyncronously, so it could fail in a subsequent
|
||||
* phase even after returning true.
|
||||
* @jsonapi{development}
|
||||
* @param[out] token Storage for RsTokenService token to track request
|
||||
* status.
|
||||
* @param[in] group Channel data (name, description...) with modifications
|
||||
* @return false on error, true otherwise
|
||||
*/
|
||||
virtual bool updateGroup(uint32_t& token, RsGxsChannelGroup& group) = 0;
|
||||
|
||||
// File Interface
|
||||
virtual bool ExtraFileHash(const std::string &path, std::string filename) = 0;
|
||||
virtual bool ExtraFileRemove(const RsFileHash &hash) = 0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -31,28 +31,39 @@
|
|||
#include <list>
|
||||
|
||||
#include "rsgxsifacetypes.h"
|
||||
#include "serialiser/rsserializable.h"
|
||||
|
||||
class RsGxsFile
|
||||
struct RsGxsFile : RsSerializable
|
||||
{
|
||||
public:
|
||||
RsGxsFile();
|
||||
std::string mName;
|
||||
RsFileHash mHash;
|
||||
uint64_t mSize;
|
||||
//std::string mPath;
|
||||
|
||||
/// @see RsSerializable
|
||||
virtual void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx )
|
||||
{
|
||||
RS_SERIAL_PROCESS(mName);
|
||||
RS_SERIAL_PROCESS(mHash);
|
||||
RS_SERIAL_PROCESS(mSize);
|
||||
}
|
||||
};
|
||||
|
||||
class RsGxsImage
|
||||
struct RsGxsImage
|
||||
{
|
||||
public:
|
||||
RsGxsImage();
|
||||
RsGxsImage();
|
||||
~RsGxsImage();
|
||||
RsGxsImage(const RsGxsImage& a); // TEMP use copy constructor and duplicate memory.
|
||||
RsGxsImage &operator=(const RsGxsImage &a); // Need this as well?
|
||||
|
||||
//NB: Must make sure that we always use methods - to be consistent about malloc/free for this data.
|
||||
static uint8_t *allocate(uint32_t size);
|
||||
static void release(void *data);
|
||||
/// Use copy constructor and duplicate memory.
|
||||
RsGxsImage(const RsGxsImage& a);
|
||||
|
||||
RsGxsImage &operator=(const RsGxsImage &a); // Need this as well?
|
||||
|
||||
/** NB: Must make sure that we always use methods - to be consistent about
|
||||
* malloc/free for this data. */
|
||||
static uint8_t *allocate(uint32_t size);
|
||||
static void release(void *data);
|
||||
|
||||
void take(uint8_t *data, uint32_t size); // Copies Pointer.
|
||||
void copy(uint8_t *data, uint32_t size); // Allocates and Copies.
|
||||
|
@ -61,7 +72,6 @@ static void release(void *data);
|
|||
|
||||
uint8_t *mData;
|
||||
uint32_t mSize;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ struct RsGroupMetaData : RsSerializable
|
|||
|
||||
|
||||
|
||||
struct RsMsgMetaData
|
||||
struct RsMsgMetaData : RsSerializable
|
||||
{
|
||||
RsMsgMetaData() : mPublishTs(0), mMsgFlags(0), mMsgStatus(0), mChildTs(0) {}
|
||||
|
||||
|
@ -155,6 +155,24 @@ struct RsMsgMetaData
|
|||
time_t mChildTs;
|
||||
std::string mServiceString; // Service Specific Free-Form extra storage.
|
||||
|
||||
/// @see RsSerializable
|
||||
virtual void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx )
|
||||
{
|
||||
RS_SERIAL_PROCESS(mGroupId);
|
||||
RS_SERIAL_PROCESS(mMsgId);
|
||||
RS_SERIAL_PROCESS(mThreadId);
|
||||
RS_SERIAL_PROCESS(mParentId);
|
||||
RS_SERIAL_PROCESS(mOrigMsgId);
|
||||
RS_SERIAL_PROCESS(mAuthorId);
|
||||
RS_SERIAL_PROCESS(mMsgName);
|
||||
RS_SERIAL_PROCESS(mPublishTs);
|
||||
RS_SERIAL_PROCESS(mMsgFlags);
|
||||
RS_SERIAL_PROCESS(mMsgStatus);
|
||||
RS_SERIAL_PROCESS(mChildTs);
|
||||
RS_SERIAL_PROCESS(mServiceString);
|
||||
}
|
||||
|
||||
const std::ostream &print(std::ostream &out, std::string indent = "", std::string varName = "") const {
|
||||
out
|
||||
<< indent << varName << " of RsMsgMetaData Values ###################" << std::endl
|
||||
|
|
|
@ -35,6 +35,7 @@ const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_NONE ( 0
|
|||
const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_CONFIG ( 0x0001 );
|
||||
const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_SIGNATURE ( 0x0002 );
|
||||
const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_SKIP_HEADER ( 0x0004 );
|
||||
const SerializationFlags RsGenericSerializer::SERIALIZATION_FLAG_YIELDING ( 0x0008 );
|
||||
|
||||
RsItem *RsServiceSerializer::deserialise(void *data, uint32_t *size)
|
||||
{
|
||||
|
|
|
@ -225,7 +225,7 @@ struct RsGenericSerializer : RsSerialType
|
|||
/** Allow shared allocator usage to avoid costly JSON deepcopy for
|
||||
* nested RsSerializable */
|
||||
SerializeContext(
|
||||
uint8_t *data, uint32_t size,
|
||||
uint8_t* data = nullptr, uint32_t size = 0,
|
||||
SerializationFlags flags = SERIALIZATION_FLAG_NONE,
|
||||
RsJson::AllocatorType* allocator = nullptr) :
|
||||
mData(data), mSize(size), mOffset(0), mOk(true), mFlags(flags),
|
||||
|
@ -260,6 +260,12 @@ struct RsGenericSerializer : RsSerialType
|
|||
static const SerializationFlags SERIALIZATION_FLAG_SIGNATURE; // 0x0002
|
||||
static const SerializationFlags SERIALIZATION_FLAG_SKIP_HEADER; // 0x0004
|
||||
|
||||
/** Used for JSON deserialization in JSON API, it causes the deserialization
|
||||
* to continue even if some field is missing (or incorrect), this way the
|
||||
* API is more user friendly as some methods need just part of the structs
|
||||
* they take as parameters. */
|
||||
static const SerializationFlags SERIALIZATION_FLAG_YIELDING; // 0x0008
|
||||
|
||||
/**
|
||||
* The following functions overload RsSerialType.
|
||||
* They *should not* need to be further overloaded.
|
||||
|
|
|
@ -42,7 +42,8 @@
|
|||
//static const uint32_t MAX_SERIALIZED_ARRAY_SIZE = 500 ;
|
||||
static const uint32_t MAX_SERIALIZED_CHUNK_SIZE = 10*1024*1024 ; // 10 MB.
|
||||
|
||||
#define SAFE_GET_JSON_V() \
|
||||
#ifdef RSSERIAL_DEBUG
|
||||
# define SAFE_GET_JSON_V() \
|
||||
const char* mName = memberName.c_str(); \
|
||||
bool ret = jDoc.HasMember(mName); \
|
||||
if(!ret) \
|
||||
|
@ -50,10 +51,16 @@ static const uint32_t MAX_SERIALIZED_CHUNK_SIZE = 10*1024*1024 ; // 10 MB.
|
|||
std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName \
|
||||
<< "\" not found in JSON:" << std::endl \
|
||||
<< jDoc << std::endl << std::endl; \
|
||||
print_stacktrace(); \
|
||||
return false; \
|
||||
} \
|
||||
rapidjson::Value& v = jDoc[mName]
|
||||
#else // ifdef RSSERIAL_DEBUG
|
||||
# define SAFE_GET_JSON_V() \
|
||||
const char* mName = memberName.c_str(); \
|
||||
bool ret = jDoc.HasMember(mName); \
|
||||
if(!ret) return false; \
|
||||
rapidjson::Value& v = jDoc[mName]
|
||||
#endif // ifdef RSSERIAL_DEBUG
|
||||
|
||||
|
||||
//============================================================================//
|
||||
|
|
|
@ -57,9 +57,7 @@
|
|||
{ \
|
||||
/* Use same allocator to avoid deep copy */\
|
||||
RsGenericSerializer::SerializeContext elCtx(\
|
||||
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,\
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE,\
|
||||
&allocator );\
|
||||
nullptr, 0, ctx.mFlags, &allocator );\
|
||||
\
|
||||
/* If el is const the default serial_process template is matched */ \
|
||||
/* also when specialization is necessary so the compilation break */ \
|
||||
|
@ -85,7 +83,7 @@
|
|||
{\
|
||||
using namespace rapidjson;\
|
||||
\
|
||||
bool& ok(ctx.mOk);\
|
||||
bool ok = ctx.mOk || ctx.mFlags & RsGenericSerializer::SERIALIZATION_FLAG_YIELDING;\
|
||||
Document& jDoc(ctx.mJson);\
|
||||
Document::AllocatorType& allocator = jDoc.GetAllocator();\
|
||||
\
|
||||
|
@ -100,19 +98,21 @@
|
|||
for (auto&& arrEl : jDoc[arrKey].GetArray())\
|
||||
{\
|
||||
RsGenericSerializer::SerializeContext elCtx(\
|
||||
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,\
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE,\
|
||||
&allocator );\
|
||||
nullptr, 0, ctx.mFlags, &allocator );\
|
||||
elCtx.mJson.AddMember(arrKey, arrEl, allocator);\
|
||||
\
|
||||
T el;\
|
||||
serial_process(j, elCtx, el, memberName); \
|
||||
ok = ok && elCtx.mOk;\
|
||||
\
|
||||
ctx.mOk &= ok;\
|
||||
if(ok) v.INSERT_FUN(el);\
|
||||
else break;\
|
||||
}\
|
||||
}\
|
||||
\
|
||||
ctx.mOk = false;\
|
||||
\
|
||||
} while(false)
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const RsJson &jDoc);
|
||||
|
@ -133,8 +133,8 @@ struct RsTypeSerializer
|
|||
template<typename T>
|
||||
typename std::enable_if<std::is_same<RsTlvItem,T>::value || !(std::is_base_of<RsSerializable,T>::value || std::is_enum<T>::value || std::is_base_of<RsTlvItem,T>::value)>::type
|
||||
static /*void*/ serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx,
|
||||
T& member, const std::string& member_name)
|
||||
RsGenericSerializer::SerializeContext& ctx,
|
||||
T& member, const std::string& member_name )
|
||||
{
|
||||
switch(j)
|
||||
{
|
||||
|
@ -156,7 +156,8 @@ struct RsTypeSerializer
|
|||
ctx.mOk = ctx.mOk && to_JSON(member_name, member, ctx.mJson);
|
||||
break;
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
ctx.mOk = ctx.mOk && from_JSON(member_name, member, ctx.mJson);
|
||||
ctx.mOk &= (ctx.mOk || ctx.mFlags & RsGenericSerializer::SERIALIZATION_FLAG_YIELDING)
|
||||
&& from_JSON(member_name, member, ctx.mJson);
|
||||
break;
|
||||
default:
|
||||
std::cerr << __PRETTY_FUNCTION__ << " Unknown serial job: "
|
||||
|
@ -194,8 +195,9 @@ struct RsTypeSerializer
|
|||
to_JSON(member_name, type_id, member, ctx.mJson);
|
||||
break;
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
ctx.mOk = ctx.mOk &&
|
||||
from_JSON(member_name, type_id, member, ctx.mJson);
|
||||
ctx.mOk &=
|
||||
(ctx.mOk || ctx.mFlags & RsGenericSerializer::SERIALIZATION_FLAG_YIELDING)
|
||||
&& from_JSON(member_name, type_id, member, ctx.mJson);
|
||||
break;
|
||||
default:
|
||||
std::cerr << __PRETTY_FUNCTION__ << " Unknown serial job: "
|
||||
|
@ -287,15 +289,11 @@ struct RsTypeSerializer
|
|||
{
|
||||
// Use same allocator to avoid deep copy
|
||||
RsGenericSerializer::SerializeContext kCtx(
|
||||
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE,
|
||||
&allocator );
|
||||
nullptr, 0, ctx.mFlags, &allocator );
|
||||
serial_process<T>(j, kCtx, const_cast<T&>(kv.first), "key");
|
||||
|
||||
RsGenericSerializer::SerializeContext vCtx(
|
||||
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE,
|
||||
&allocator );
|
||||
nullptr, 0, ctx.mFlags, &allocator );
|
||||
serial_process<U>(j, vCtx, const_cast<U&>(kv.second), "value");
|
||||
|
||||
if(kCtx.mOk && vCtx.mOk)
|
||||
|
@ -316,7 +314,7 @@ struct RsTypeSerializer
|
|||
{
|
||||
using namespace rapidjson;
|
||||
|
||||
bool& ok(ctx.mOk);
|
||||
bool ok = ctx.mOk || ctx.mFlags & RsGenericSerializer::SERIALIZATION_FLAG_YIELDING;
|
||||
Document& jDoc(ctx.mJson);
|
||||
Document::AllocatorType& allocator = jDoc.GetAllocator();
|
||||
|
||||
|
@ -336,9 +334,7 @@ struct RsTypeSerializer
|
|||
if (!ok) break;
|
||||
|
||||
RsGenericSerializer::SerializeContext kCtx(
|
||||
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE,
|
||||
&allocator );
|
||||
nullptr, 0, ctx.mFlags, &allocator );
|
||||
if(ok)
|
||||
kCtx.mJson.AddMember("key", kvEl["key"], allocator);
|
||||
|
||||
|
@ -346,9 +342,7 @@ struct RsTypeSerializer
|
|||
ok = ok && (serial_process(j, kCtx, key, "key"), kCtx.mOk);
|
||||
|
||||
RsGenericSerializer::SerializeContext vCtx(
|
||||
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE,
|
||||
&allocator );
|
||||
nullptr, 0, ctx.mFlags, &allocator );
|
||||
if(ok)
|
||||
vCtx.mJson.AddMember("value", kvEl["value"], allocator);
|
||||
|
||||
|
@ -356,14 +350,20 @@ struct RsTypeSerializer
|
|||
ok = ok && ( serial_process(j, vCtx, value, "value"),
|
||||
vCtx.mOk );
|
||||
|
||||
ctx.mOk &= ok;
|
||||
if(ok) v.insert(std::pair<T,U>(key,value));
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.mOk = false;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
default:
|
||||
std::cerr << __PRETTY_FUNCTION__ << " Unknown serial job: "
|
||||
<< static_cast<std::underlying_type<decltype(j)>::type>(j)
|
||||
<< std::endl;
|
||||
exit(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -566,7 +566,9 @@ struct RsTypeSerializer
|
|||
case RsGenericSerializer::FROM_JSON:
|
||||
{
|
||||
uint32_t f;
|
||||
ctx.mOk = from_JSON(memberName, f, ctx.mJson);
|
||||
ctx.mOk &=
|
||||
(ctx.mOk || ctx.mFlags & RsGenericSerializer::SERIALIZATION_FLAG_YIELDING)
|
||||
&& from_JSON(memberName, f, ctx.mJson);
|
||||
v = t_RsFlags32<N>(f);
|
||||
break;
|
||||
}
|
||||
|
@ -623,9 +625,7 @@ struct RsTypeSerializer
|
|||
|
||||
// Reuse allocator to avoid deep copy later
|
||||
RsGenericSerializer::SerializeContext lCtx(
|
||||
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE,
|
||||
&allocator );
|
||||
nullptr, 0, ctx.mFlags, &allocator );
|
||||
|
||||
member.serial_process(j, lCtx);
|
||||
|
||||
|
@ -642,28 +642,32 @@ struct RsTypeSerializer
|
|||
}
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
{
|
||||
rapidjson::Document& jDoc(ctx.mJson);
|
||||
RsJson& jDoc(ctx.mJson);
|
||||
const char* mName = memberName.c_str();
|
||||
ctx.mOk = ctx.mOk && jDoc.HasMember(mName);
|
||||
bool hasMember = jDoc.HasMember(mName);
|
||||
bool yielding = ctx.mFlags &
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_YIELDING;
|
||||
|
||||
if(!ctx.mOk)
|
||||
if(!hasMember)
|
||||
{
|
||||
std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName
|
||||
<< "\" not found in JSON:" << std::endl
|
||||
<< jDoc << std::endl << std::endl;
|
||||
print_stacktrace();
|
||||
if(!yielding)
|
||||
{
|
||||
std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName
|
||||
<< "\" not found in JSON:" << std::endl
|
||||
<< jDoc << std::endl << std::endl;
|
||||
print_stacktrace();
|
||||
}
|
||||
ctx.mOk = false;
|
||||
break;
|
||||
}
|
||||
|
||||
rapidjson::Value& v = jDoc[mName];
|
||||
|
||||
RsGenericSerializer::SerializeContext lCtx(
|
||||
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE );
|
||||
RsGenericSerializer::SerializeContext lCtx(nullptr, 0, ctx.mFlags);
|
||||
lCtx.mJson.SetObject() = v; // Beware of move semantic!!
|
||||
|
||||
member.serial_process(j, lCtx);
|
||||
ctx.mOk = ctx.mOk && lCtx.mOk;
|
||||
ctx.mOk &= lCtx.mOk;
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,18 @@ sLibs =
|
|||
mLibs = $$RS_SQL_LIB ssl crypto $$RS_THREAD_LIB $$RS_UPNP_LIB
|
||||
dLibs =
|
||||
|
||||
rs_jsonapi {
|
||||
RS_SRC_PATH=$$system_path($$clean_path($${PWD}/../../))
|
||||
RS_BUILD_PATH=$$system_path($$clean_path($${OUT_PWD}/../../))
|
||||
RESTBED_SRC_PATH=$$system_path($$clean_path($${RS_SRC_PATH}/supportlibs/restbed))
|
||||
RESTBED_BUILD_PATH=$$system_path($$clean_path($${RS_BUILD_PATH}/supportlibs/restbed))
|
||||
|
||||
INCLUDEPATH *= $$system_path($$clean_path($${RESTBED_BUILD_PATH}/include/))
|
||||
QMAKE_LIBDIR *= $$system_path($$clean_path($${RESTBED_BUILD_PATH}/library/))
|
||||
# Using sLibs would fail as librestbed.a is generated at compile-time
|
||||
LIBS *= -L$$system_path($$clean_path($${RESTBED_BUILD_PATH}/library/)) -lrestbed
|
||||
}
|
||||
|
||||
linux-* {
|
||||
mLibs += dl
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue