From 598521d1ac162500f470790dd47688c127069eca Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Thu, 14 Feb 2019 18:52:35 -0300 Subject: [PATCH] Implement JSON API for circles --- libretroshare/src/retroshare/rsgxscircles.h | 255 +++++++++++++----- .../src/retroshare/rsgxsifacetypes.h | 4 +- libretroshare/src/services/p3gxscircles.cc | 137 ++++++++-- libretroshare/src/services/p3gxscircles.h | 25 +- retroshare.pri | 1 + 5 files changed, 324 insertions(+), 98 deletions(-) diff --git a/libretroshare/src/retroshare/rsgxscircles.h b/libretroshare/src/retroshare/rsgxscircles.h index f01e92ef3..d5f3543d0 100644 --- a/libretroshare/src/retroshare/rsgxscircles.h +++ b/libretroshare/src/retroshare/rsgxscircles.h @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2012-2012 by Robert Fernie * + * Copyright (C) 2012 Robert Fernie * + * Copyright (C) 2018 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,34 +20,31 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef RETROSHARE_GXSCIRCLES_INTERFACE_H -#define RETROSHARE_GXSCIRCLES_INTERFACE_H +#pragma once -#include +#include #include #include #include #include "retroshare/rstypes.h" - -//typedef std::string RsGxsCircleId; -//typedef RsPgpId RsPgpId; -//typedef std::string RsCircleInternalId; - #include "retroshare/rstokenservice.h" #include "retroshare/rsgxsifacehelper.h" - #include "retroshare/rsidentity.h" +#include "serialiser/rsserializable.h" -/* The Main Interface Class - for information about your Peers */ class RsGxsCircles; -extern RsGxsCircles *rsGxsCircles; -typedef RsPgpId RsPgpId; +/** + * Pointer to global instance of RsGxsCircles service implementation + * @jsonapi{development} + */ +extern RsGxsCircles* rsGxsCircles; + +// TODO: convert to enum /// The meaning of the different circle types is: -/// TODO: convert to enum static const uint32_t GXS_CIRCLE_TYPE_UNKNOWN = 0x0000 ; /// Used to detect uninizialized values. static const uint32_t GXS_CIRCLE_TYPE_PUBLIC = 0x0001 ; // not restricted to a circle static const uint32_t GXS_CIRCLE_TYPE_EXTERNAL = 0x0002 ; // restricted to an external circle, made of RsGxsId @@ -62,90 +60,207 @@ static const uint32_t GXS_EXTERNAL_CIRCLE_FLAGS_ALLOWED = 0x0007 ;// user static const uint32_t GXS_CIRCLE_FLAGS_IS_EXTERNAL = 0x0008 ;// user is allowed -/* Permissions is part of GroupMetaData */ -class GxsPermissions +struct RsGxsCircleGroup : RsSerializable { -public: - uint32_t mCircleType; // PUBLIC, EXTERNAL or YOUREYESONLY. - RsGxsCircleId mCircleId; // If EXTERNAL, otherwise Blank. + virtual ~RsGxsCircleGroup() {} - // BELOW IS NOT SERIALISED - BUT MUST BE STORED LOCALLY BY GXS. (If YOUREYESONLY) - RsPeerId mOriginator; - RsGxsCircleId mInternalCircle; // if Originator == ownId, otherwise blank. + RsGroupMetaData mMeta; + + std::set mLocalFriends; + std::set mInvitedMembers; + std::set mSubCircles; +#ifdef V07_NON_BACKWARD_COMPATIBLE_CHANGE_UNNAMED +# error "Add description, and multiple owners/administrators to circles" + // or better in general to GXS groups +#endif + + /// @see RsSerializable + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) override + { + RS_SERIAL_PROCESS(mMeta); + RS_SERIAL_PROCESS(mLocalFriends); + RS_SERIAL_PROCESS(mInvitedMembers); + RS_SERIAL_PROCESS(mSubCircles); + } }; -class RsGxsCircleGroup +struct RsGxsCircleMsg : RsSerializable { - public: - RsGroupMetaData mMeta; // includes GxsPermissions, for control of group distribution. + virtual ~RsGxsCircleMsg() {} - std::set mLocalFriends; - std::set mInvitedMembers; - std::set mSubCircles; - - // Not Serialised. - // Internally inside rsCircles, this will be turned into: - // std::list mAllowedFriends; -}; - -class RsGxsCircleMsg -{ - public: RsMsgMetaData mMeta; - // Signature by user signifying that they want to be part of the group. - // maybe Phase 3. +#ifndef V07_NON_BACKWARD_COMPATIBLE_CHANGE_UNNAMED + /* This is horrible and should be changed into yet to be defined something + * reasonable in next non retrocompatible version */ std::string stuff; +#endif + + /// @see RsSerializable + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) override + { + RS_SERIAL_PROCESS(mMeta); + RS_SERIAL_PROCESS(stuff); + } }; -class RsGxsCircleDetails +struct RsGxsCircleDetails : RsSerializable { - public: - RsGxsCircleDetails() : mCircleType(GXS_CIRCLE_TYPE_EXTERNAL), mAmIAllowed(false) {} - - RsGxsCircleId mCircleId; - std::string mCircleName; + RsGxsCircleDetails() : + mCircleType(GXS_CIRCLE_TYPE_EXTERNAL), mAmIAllowed(false) {} + ~RsGxsCircleDetails() {} - uint32_t mCircleType; - RsGxsCircleId mRestrictedCircleId; - - bool mAmIAllowed ; // true when one of load GXS ids belong to the circle allowed list (admin list & subscribed list). + RsGxsCircleId mCircleId; + std::string mCircleName; - std::set mAllowedGxsIds; // This crosses admin list and subscribed list - std::set mAllowedNodes; - - std::map mSubscriptionFlags ; // subscription flags for all ids + uint32_t mCircleType; + RsGxsCircleId mRestrictedCircleId; + + /** true when one of load GXS ids belong to the circle allowed list (admin + * list & subscribed list). */ + bool mAmIAllowed; + + /// This crosses admin list and subscribed list + std::set mAllowedGxsIds; + std::set mAllowedNodes; + + /// subscription flags for all ids + std::map mSubscriptionFlags; + + /// @see RsSerializable + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) override + { + RS_SERIAL_PROCESS(mCircleId); + RS_SERIAL_PROCESS(mCircleName); + RS_SERIAL_PROCESS(mCircleType); + RS_SERIAL_PROCESS(mRestrictedCircleId); + RS_SERIAL_PROCESS(mAmIAllowed); + RS_SERIAL_PROCESS(mAllowedGxsIds); + RS_SERIAL_PROCESS(mAllowedNodes); + RS_SERIAL_PROCESS(mSubscriptionFlags); + } }; class RsGxsCircles: public RsGxsIfaceHelper { public: - RsGxsCircles(RsGxsIface& gxs) :RsGxsIfaceHelper(gxs) {} + RsGxsCircles(RsGxsIface& gxs) : RsGxsIfaceHelper(gxs) {} virtual ~RsGxsCircles() {} - /* External Interface (Cached stuff) */ - virtual bool getCircleDetails(const RsGxsCircleId &id, RsGxsCircleDetails &details) = 0; - virtual bool getCircleExternalIdList(std::list &circleIds) = 0; - virtual bool getCirclePersonalIdList(std::list &circleIds) = 0; + /** + * @brief Create new circle + * @jsonapi{development} + * @param[inout] cData input name and flags of the circle, storage for + * generated circle data id etc. + * @return false if something failed, true otherwhise + */ + virtual bool createCircle(RsGxsCircleGroup& cData) = 0; - /* membership management for external circles */ + /** + * @brief Edit own existing circle + * @jsonapi{development} + * @param[inout] cData Circle data with modifications, storage for data + * updatedad during the operation. + * @return false if something failed, true otherwhise + */ + virtual bool editCircle(RsGxsCircleGroup& cData) = 0; - virtual bool requestCircleMembership(const RsGxsId& own_gxsid,const RsGxsCircleId& circle_id)=0 ; - virtual bool cancelCircleMembership(const RsGxsId& own_gxsid,const RsGxsCircleId& circle_id)=0 ; + /** + * @brief Get circle details. Memory cached + * @jsonapi{development} + * @param[in] id Id of the circle + * @param[out] details Storage for the circle details + * @return false if something failed, true otherwhise + */ + virtual bool getCircleDetails( + const RsGxsCircleId& id, RsGxsCircleDetails& details ) = 0; - /* standard load */ - virtual bool getGroupData(const uint32_t &token, std::vector &groups) = 0; - virtual bool getMsgData(const uint32_t &token, std::vector &msgs) = 0; + /** + * @brief Get list of known external circles ids. Memory cached + * @jsonapi{development} + * @param[in] circleIds Storage for circles id list + * @return false if something failed, true otherwhise + */ + virtual bool getCircleExternalIdList( + std::list& circleIds ) = 0; - /* make new group */ + /** + * @brief Get circles summaries list. + * @jsonapi{development} + * @param[out] circles list where to store the circles summaries + * @return false if something failed, true otherwhise + */ + virtual bool getCirclesSummaries(std::list& circles) = 0; + + /** + * @brief Get circles information + * @jsonapi{development} + * @param[in] circlesIds ids of the circles of which to get the informations + * @param[out] circlesInfo storage for the circles informations + * @return false if something failed, true otherwhise + */ + virtual bool getCirclesInfo( + const std::list& circlesIds, + std::vector& circlesInfo ) = 0; + + /** + * @brief Get circle requests + * @jsonapi{development} + * @param[in] circleId id of the circle of which the requests are requested + * @param[out] requests storage for the circle requests + * @return false if something failed, true otherwhise + */ + virtual bool getCircleRequests( const RsGxsGroupId& circleId, + std::vector& requests ) = 0; + + /** + * @brief Invite identities to circle + * @jsonapi{development} + * @param[in] identities ids of the identities to invite + * @param[in] circleId Id of the circle you own and want to invite ids in + * @return false if something failed, true otherwhise + */ + virtual bool inviteIdsToCircle( const std::set& identities, + const RsGxsCircleId& circleId ) = 0; + + /** + * @brief Request circle membership, or accept circle invitation + * @jsonapi{development} + * @param[in] ownGxsId Id of own identity to introduce to the circle + * @param[in] circleId Id of the circle to which ask for inclusion + * @return false if something failed, true otherwhise + */ + virtual bool requestCircleMembership( + const RsGxsId& ownGxsId, const RsGxsCircleId& circleId ) = 0; + + /** + * @brief Leave given circle + * @jsonapi{development} + * @param[in] ownGxsId Own id to remove from the circle + * @param[in] circleId Id of the circle to leave + * @return false if something failed, true otherwhise + */ + virtual bool cancelCircleMembership( + const RsGxsId& ownGxsId, const RsGxsCircleId& circleId ) = 0; + + RS_DEPRECATED_FOR("getCirclesSummaries getCirclesInfo") + virtual bool getGroupData( + const uint32_t& token, std::vector& groups ) = 0; + + RS_DEPRECATED_FOR(getCirclesRequests) + virtual bool getMsgData( + const uint32_t& token, std::vector& msgs ) = 0; + + /// make new group + RS_DEPRECATED_FOR(createCircle) virtual void createGroup(uint32_t& token, RsGxsCircleGroup &group) = 0; - /* update an existing group */ + /// update an existing group + RS_DEPRECATED_FOR("editCircle, inviteIdsToCircle") virtual void updateGroup(uint32_t &token, RsGxsCircleGroup &group) = 0; }; - - - -#endif diff --git a/libretroshare/src/retroshare/rsgxsifacetypes.h b/libretroshare/src/retroshare/rsgxsifacetypes.h index c80ce3afa..d5a9d8d7d 100644 --- a/libretroshare/src/retroshare/rsgxsifacetypes.h +++ b/libretroshare/src/retroshare/rsgxsifacetypes.h @@ -90,7 +90,9 @@ struct RsGroupMetaData : RsSerializable rstime_t mLastPost; // Timestamp for last message. Not used yet. uint32_t mGroupStatus; - std::string mServiceString; // Service Specific Free-Form extra storage. + + /// Service Specific Free-Form local (non-synced) extra storage. + std::string mServiceString; RsPeerId mOriginator; RsGxsCircleId mInternalCircle; diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index ebf979fe7..ed5dc74ff 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -153,7 +153,118 @@ RsServiceInfo p3GxsCircles::getServiceInfo() GXS_CIRCLES_MIN_MINOR_VERSION); } +bool p3GxsCircles::createCircle(RsGxsCircleGroup& cData) +{ + uint32_t token; + createGroup(token, cData); + if(waitToken(token) != RsTokenService::COMPLETE) + { + std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed." + << std::endl; + return false; + } + + if(!RsGenExchange::getPublishedGroupMeta(token, cData.mMeta)) + { + std::cerr << __PRETTY_FUNCTION__ << "Error! Failure getting created" + << " group data." << std::endl; + return false; + } + + return true; +} + +bool p3GxsCircles::editCircle(RsGxsCircleGroup& cData) +{ + uint32_t token; + updateGroup(token, cData); + + if(waitToken(token) != RsTokenService::COMPLETE) + { + std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed." + << std::endl; + return false; + } + + if(!RsGenExchange::getPublishedGroupMeta(token, cData.mMeta)) + { + std::cerr << __PRETTY_FUNCTION__ << "Error! Failure getting updated" + << " group data." << std::endl; + return false; + } + + return true; +} + +bool p3GxsCircles::getCirclesSummaries(std::list& circles) +{ + uint32_t token; + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_GROUP_META; + if( !requestGroupInfo(token, opts) + || waitToken(token) != RsTokenService::COMPLETE ) return false; + return getGroupSummary(token, circles); +} + +bool p3GxsCircles::getCirclesInfo( const std::list& circlesIds, + std::vector& circlesInfo ) +{ + uint32_t token; + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; + if( !requestGroupInfo(token, opts, circlesIds) + || waitToken(token) != RsTokenService::COMPLETE ) return false; + return getGroupData(token, circlesInfo); +} + +bool p3GxsCircles::getCircleRequests( const RsGxsGroupId& circleId, + std::vector& requests ) +{ + uint32_t token; + std::list grpIds { circleId }; + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; + + if( !requestMsgInfo(token, opts, grpIds) || + waitToken(token) != RsTokenService::COMPLETE ) return false; + + return getMsgData(token, requests); +} + +bool p3GxsCircles::inviteIdsToCircle( const std::set& identities, + const RsGxsCircleId& circleId ) +{ + const std::list circlesIds{ RsGxsGroupId(circleId) }; + std::vector circlesInfo; + + if(!getCirclesInfo(circlesIds, circlesInfo)) + { + std::cerr << __PRETTY_FUNCTION__ << "Error! Failure getting group data." + << std::endl; + return false; + } + + if(circlesInfo.empty()) + { + std::cerr << __PRETTY_FUNCTION__ << "Error! Circle: " + << circleId.toStdString() << " not found!" << std::endl; + return false; + } + + RsGxsCircleGroup& circleGrp = circlesInfo[0]; + + if(!(circleGrp.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN)) + { + std::cerr << __PRETTY_FUNCTION__ << "Error! Attempt to edit non-own " + << "circle: " << circleId.toStdString() << std::endl; + return false; + } + + circleGrp.mInvitedMembers.insert(identities.begin(), identities.end()); + + return editCircle(circleGrp); +} uint32_t p3GxsCircles::circleAuthenPolicy() { @@ -320,32 +431,6 @@ bool p3GxsCircles:: getCircleDetails(const RsGxsCircleId &id, RsGxsCircleDetails return false; } - -bool p3GxsCircles:: getCirclePersonalIdList(std::list &circleIds) -{ -#ifdef DEBUG_CIRCLES - std::cerr << "p3GxsCircles::getCircleIdList()"; - std::cerr << std::endl; -#endif // DEBUG_CIRCLES - - RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ - if (circleIds.empty()) - { - circleIds = mCirclePersonalIdList; - } - else - { - std::list::const_iterator it; - for(it = mCirclePersonalIdList.begin(); it != mCirclePersonalIdList.begin(); ++it) - { - circleIds.push_back(*it); - } - } - - return true; -} - - bool p3GxsCircles:: getCircleExternalIdList(std::list &circleIds) { #ifdef DEBUG_CIRCLES diff --git a/libretroshare/src/services/p3gxscircles.h b/libretroshare/src/services/p3gxscircles.h index 8b8cef4a8..a23ecbd88 100644 --- a/libretroshare/src/services/p3gxscircles.h +++ b/libretroshare/src/services/p3gxscircles.h @@ -179,9 +179,30 @@ virtual RsServiceInfo getServiceInfo(); /*********** External Interface ***************/ + /// @see RsGxsCircles + bool createCircle(RsGxsCircleGroup& cData) override; + + /// @see RsGxsCircles + bool editCircle(RsGxsCircleGroup& cData) override; + + /// @see RsGxsCircles + bool getCirclesSummaries(std::list& circles) override; + + /// @see RsGxsCircles + bool getCirclesInfo( + const std::list& circlesIds, + std::vector& circlesInfo ) override; + + /// @see RsGxsCircles + bool getCircleRequests( const RsGxsGroupId& circleId, + std::vector& requests ) override; + + /// @see RsGxsCircles + bool inviteIdsToCircle( const std::set& identities, + const RsGxsCircleId& circleId ) override; + virtual bool getCircleDetails(const RsGxsCircleId &id, RsGxsCircleDetails &details); virtual bool getCircleExternalIdList(std::list &circleIds); - virtual bool getCirclePersonalIdList(std::list &circleIds); virtual bool isLoaded(const RsGxsCircleId &circleId); virtual bool loadCircle(const RsGxsCircleId &circleId); @@ -257,6 +278,8 @@ virtual RsServiceInfo getServiceInfo(); // put a circle id into the external or personal circle id list // this function locks the mutex // if the id is already in the list, it will not be added again + // G10h4ck: this is terrible, an std::set instead of a list should be used + // to guarantee uniqueness void addCircleIdToList(const RsGxsCircleId& circleId, uint32_t circleType); RsMutex mCircleMtx; /* Locked Below Here */ diff --git a/retroshare.pri b/retroshare.pri index be9951915..df632f031 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -241,6 +241,7 @@ rs_v07_changes { DEFINES += V07_NON_BACKWARD_COMPATIBLE_CHANGE_001 DEFINES += V07_NON_BACKWARD_COMPATIBLE_CHANGE_002 DEFINES += V07_NON_BACKWARD_COMPATIBLE_CHANGE_003 + DEFINES += V07_NON_BACKWARD_COMPATIBLE_CHANGE_UNNAMED } ################################################################################