diff --git a/libretroshare/src/retroshare/rsgxsifacehelper.h b/libretroshare/src/retroshare/rsgxsifacehelper.h index e48d0cb23..a6680afc6 100644 --- a/libretroshare/src/retroshare/rsgxsifacehelper.h +++ b/libretroshare/src/retroshare/rsgxsifacehelper.h @@ -1,561 +1,561 @@ -/******************************************************************************* - * libretroshare/src/retroshare: rsgxsifacehelper.h * - * * - * libretroshare: retroshare core library * - * * - * Copyright (C) 2011 Christopher Evi-Parker * - * Copyright (C) 2018-2021 Gioacchino Mazzurco * - * Copyright (C) 2019-2021 AsociaciĆ³n Civil Altermundi * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with this program. If not, see . * - * * - *******************************************************************************/ -#pragma once - -#include -#include - -#include "retroshare/rsgxsiface.h" -#include "retroshare/rsservicecontrol.h" -#include "retroshare/rsreputations.h" -#include "rsgxsflags.h" -#include "util/rsdeprecate.h" -#include "util/rsdebug.h" - -/*! - * This class only make method of internal members visible tu upper level to - * offer a more friendly API. - * This is just a workaround to awkward GXS API design, do not take it as an - * example for your coding. - * To properly fix the API design many changes with the implied chain reactions - * are necessary, so at this point this workaround seems acceptable. - */ - -//================================== -// #define DEBUG_GXSIFACEHELPER 1 -//================================== - -enum class TokenRequestType: uint8_t -{ - __NONE = 0x00, /// Used to detect uninitialized - GROUP_DATA = 0x01, - GROUP_META = 0x02, - GROUP_IDS = 0x03, - POSTS = 0x04, - ALL_POSTS = 0x05, - MSG_RELATED_INFO = 0x06, - GROUP_STATISTICS = 0x07, - SERVICE_STATISTICS = 0x08, - NO_KILL_TYPE = 0x09, - __MAX /// Used to detect out of range -}; - -class RsGxsIfaceHelper -{ -public: - /*! - * @param gxs handle to RsGenExchange instance of service (Usually the - * service class itself) - */ - explicit RsGxsIfaceHelper(RsGxsIface& gxs) : - mGxs(gxs), mTokenService(*gxs.getTokenService()), mMtx("GxsIfaceHelper") - {} - - ~RsGxsIfaceHelper() = default; - -#ifdef TO_REMOVE - /*! - * Gxs services should call this for automatic handling of - * changes, send - * @param changes - */ - void receiveChanges(std::vector &changes) - { - mGxs.receiveChanges(changes); - } -#endif - - /* Generic Lists */ - - /*! - * Retrieve list of group ids associated to a request token - * @param token token to be redeemed for this request - * @param groupIds the ids return for given request token - * @return false if request token is invalid, check token status for error report - */ - bool getGroupList(const uint32_t &token, std::list &groupIds) - { - return mGxs.getGroupList(token, groupIds); - } - - /*! - * Retrieves list of msg ids associated to a request token - * @param token token to be redeemed for this request - * @param msgIds the ids return for given request token - * @return false if request token is invalid, check token status for error report - */ - bool getMsgList(const uint32_t &token, - GxsMsgIdResult& msgIds) - { - return mGxs.getMsgList(token, msgIds); - } - - /*! - * Retrieves list of msg related ids associated to a request token - * @param token token to be redeemed for this request - * @param msgIds the ids return for given request token - * @return false if request token is invalid, check token status for error report - */ - bool getMsgRelatedList(const uint32_t &token, MsgRelatedIdResult &msgIds) - { - return mGxs.getMsgRelatedList(token, msgIds); - } - - /*! - * @param token token to be redeemed for group summary request - * @param groupInfo the ids returned for given request token - * @return false if request token is invalid, check token status for error report - */ - bool getGroupSummary(const uint32_t &token, std::list &groupInfo) - { - return mGxs.getGroupMeta(token, groupInfo); - } - - /*! - * @param token token to be redeemed for message summary request - * @param msgInfo the message metadata returned for given request token - * @return false if request token is invalid, check token status for error report - */ - bool getMsgSummary(const uint32_t &token, GxsMsgMetaMap &msgInfo) - { - return mGxs.getMsgMeta(token, msgInfo); - } - - /*! - * @param token token to be redeemed for message related summary request - * @param msgInfo the message metadata returned for given request token - * @return false if request token is invalid, check token status for error report - */ - bool getMsgRelatedSummary(const uint32_t &token, GxsMsgRelatedMetaMap &msgInfo) - { - return mGxs.getMsgRelatedMeta(token, msgInfo); - } - - /*! - * subscribes to group, and returns token which can be used - * to be acknowledged to get group Id - * @param token token to redeem for acknowledgement - * @param grpId the id of the group to subscribe to - */ - bool subscribeToGroup(uint32_t& token, const RsGxsGroupId& grpId, bool subscribe) - { - return mGxs.subscribeToGroup(token, grpId, subscribe); - } - - /*! - * This allows the client service to acknowledge that their msgs has - * been created/modified and retrieve the create/modified msg ids - * @param token the token related to modification/create request - * @param msgIds map of grpid->msgIds of message created/modified - * @return true if token exists false otherwise - */ - bool acknowledgeMsg(const uint32_t& token, std::pair& msgId) - { - return mGxs.acknowledgeTokenMsg(token, msgId); - } - - /*! - * This allows the client service to acknowledge that their grps has - * been created/modified and retrieve the create/modified grp ids - * @param token the token related to modification/create request - * @param msgIds vector of ids of groups created/modified - * @return true if token exists false otherwise - */ - bool acknowledgeGrp(const uint32_t& token, RsGxsGroupId& grpId) - { - return mGxs.acknowledgeTokenGrp(token, grpId); - } - - /*! - * Gets service statistic for a given services - * @param token value to to retrieve requested stats - * @param stats the status - * @return true if token exists false otherwise - */ - bool getServiceStatistic(const uint32_t& token, GxsServiceStatistic& stats) - { - return mGxs.getServiceStatistic(token, stats); - } - - /*! - * - * @param token to be redeemed - * @param stats the stats associated to token request - * @return true if token is false otherwise - */ - bool getGroupStatistic(const uint32_t& token, GxsGroupStatistic& stats) - { - return mGxs.getGroupStatistic(token, stats); - } - - /*! - * @brief Get default maximum storage time for GXS messages - * @jsonapi{development} - * @return storage time in seconds - */ - uint32_t getDefaultStoragePeriod() - { return mGxs.getDefaultStoragePeriod(); } - - /*! - * @brief Get maximum storage time of GXS messages for the given group - * @jsonapi{development} - * @param[in] groupId Id of the group - * @return storage time in seconds - */ - uint32_t getStoragePeriod(const RsGxsGroupId& groupId) - { return mGxs.getStoragePeriod(groupId); } - - /*! - * @brief Set GXS messages maximum storage time for the given group - * @jsonapi{development} - * @param[in] groupId Id of the group - * @param[in] storageSecs storage time in seconds - */ - void setStoragePeriod(const RsGxsGroupId& groupId, uint32_t storageSecs) - { mGxs.setStoragePeriod(groupId, storageSecs); } - - /*! - * @brief Get default maximum syncronization age for GXS messages - * @jsonapi{development} - * @return age in seconds - */ - uint32_t getDefaultSyncPeriod() - { return mGxs.getDefaultSyncPeriod(); } - - /*! - * @brief Get maximum syncronization age of GXS messages for the given group - * @jsonapi{development} - * @param[in] groupId Id of the group - * @return age in seconds - */ - uint32_t getSyncPeriod(const RsGxsGroupId& groupId) - { return mGxs.getSyncPeriod(groupId); } - - /*! - * @brief Set GXS messages maximum syncronization age for the given group - * @jsonapi{development} - * @param[in] groupId Id of the group - * @param[in] syncAge age in seconds - */ - void setSyncPeriod(const RsGxsGroupId& groupId, uint32_t syncAge) - { mGxs.setSyncPeriod(groupId, syncAge); } - - /*! - * This determines the reputation threshold messages need to surpass in order - * for it to be accepted by local user from remote source - * NOTE: threshold only enforced if service require author signature - * @param token value set to be redeemed with acknowledgement - * @param grpId group id for cutoff value to be set - * @param CutOff The cut off value to set - */ - void setGroupReputationCutOff(uint32_t& token, const RsGxsGroupId& grpId, int CutOff) - { - return mGxs.setGroupReputationCutOff(token, grpId, CutOff); - } - - RsReputationLevel minReputationForForwardingMessages( - uint32_t group_sign_flags, uint32_t identity_flags ) - { - return mGxs.minReputationForForwardingMessages(group_sign_flags,identity_flags); - } - - /// @see RsTokenService::requestGroupInfo - bool requestGroupInfo( uint32_t& token, const RsTokReqOptions& opts, const std::list &groupIds, bool high_priority_request = false ) - { - TokenRequestType token_request_type; - - switch(opts.mReqType) - { - case GXS_REQUEST_TYPE_GROUP_DATA: token_request_type = TokenRequestType::GROUP_DATA; break; - case GXS_REQUEST_TYPE_GROUP_META: token_request_type = TokenRequestType::GROUP_META; break; - case GXS_REQUEST_TYPE_GROUP_IDS: token_request_type = TokenRequestType::GROUP_IDS; break; - default: - RsErr() << __PRETTY_FUNCTION__ << "(EE) Unexpected request type " << opts.mReqType << "!!" << std::endl; - return false; - } - - cancelActiveRequestTokens(token_request_type); - - if( mTokenService.requestGroupInfo(token, 0, opts, groupIds)) - { - RS_STACK_MUTEX(mMtx); - mActiveTokens[token]=high_priority_request? (TokenRequestType::NO_KILL_TYPE) : token_request_type; -#ifdef DEBUG_GXSIFACEHELPER - locked_dumpTokens(); -#endif - return true; - } - else - return false; - } - - /// @see RsTokenService::requestGroupInfo - bool requestGroupInfo(uint32_t& token, const RsTokReqOptions& opts, bool high_priority_request = false) - { - TokenRequestType token_request_type; - - switch(opts.mReqType) - { - case GXS_REQUEST_TYPE_GROUP_DATA: token_request_type = TokenRequestType::GROUP_DATA; break; - case GXS_REQUEST_TYPE_GROUP_META: token_request_type = TokenRequestType::GROUP_META; break; - case GXS_REQUEST_TYPE_GROUP_IDS: token_request_type = TokenRequestType::GROUP_IDS; break; - default: - RsErr() << __PRETTY_FUNCTION__ << "(EE) Unexpected request type " << opts.mReqType << "!!" << std::endl; - return false; - } - - cancelActiveRequestTokens(token_request_type); - - - if( mTokenService.requestGroupInfo(token, 0, opts)) - { - RS_STACK_MUTEX(mMtx); - mActiveTokens[token]=high_priority_request? (TokenRequestType::NO_KILL_TYPE) : token_request_type; -#ifdef DEBUG_GXSIFACEHELPER - locked_dumpTokens(); -#endif - return true; - } - else - return false; - } - - /// @see RsTokenService::requestMsgInfo - bool requestMsgInfo( uint32_t& token, const RsTokReqOptions& opts, const GxsMsgReq& msgIds ) - { - if(mTokenService.requestMsgInfo(token, 0, opts, msgIds)) - { - RS_STACK_MUTEX(mMtx); - - mActiveTokens[token]= (msgIds.size()==1 && msgIds.begin()->second.size()==0) ?(TokenRequestType::ALL_POSTS):(TokenRequestType::POSTS); -#ifdef DEBUG_GXSIFACEHELPER - locked_dumpTokens(); -#endif - return true; - } - else - return false; - } - - /// @see RsTokenService::requestMsgInfo - bool requestMsgInfo( uint32_t& token, const RsTokReqOptions& opts, const std::list& grpIds ) - { - if(mTokenService.requestMsgInfo(token, 0, opts, grpIds)) - { - RS_STACK_MUTEX(mMtx); - mActiveTokens[token]=TokenRequestType::ALL_POSTS; -#ifdef DEBUG_GXSIFACEHELPER - locked_dumpTokens(); -#endif - return true; - } - else - return false; - } - - /// @see RsTokenService::requestMsgRelatedInfo - bool requestMsgRelatedInfo( - uint32_t& token, const RsTokReqOptions& opts, - const std::vector& msgIds ) - { - if( mTokenService.requestMsgRelatedInfo(token, 0, opts, msgIds)) - { - RS_STACK_MUTEX(mMtx); - mActiveTokens[token]=TokenRequestType::MSG_RELATED_INFO; -#ifdef DEBUG_GXSIFACEHELPER - locked_dumpTokens(); -#endif - return true; - } - else - return false; - } - - /** - * @jsonapi{development} - * @param[in] token - */ - RsTokenService::GxsRequestStatus requestStatus(uint32_t token) - { return mTokenService.requestStatus(token); } - - /// @see RsTokenService::requestServiceStatistic - bool requestServiceStatistic(uint32_t& token) - { - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_SERVICE_STATS; - - mTokenService.requestServiceStatistic(token,opts); - - RS_STACK_MUTEX(mMtx); - mActiveTokens[token]=TokenRequestType::SERVICE_STATISTICS; - -#ifdef DEBUG_GXSIFACEHELPER - locked_dumpTokens(); -#endif - return true; - } - - /// @see RsTokenService::requestGroupStatistic - bool requestGroupStatistic(uint32_t& token, const RsGxsGroupId& grpId) - { - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_GROUP_STATS; - - mTokenService.requestGroupStatistic(token, grpId,opts); - - RS_STACK_MUTEX(mMtx); - mActiveTokens[token]=TokenRequestType::GROUP_STATISTICS; -#ifdef DEBUG_GXSIFACEHELPER - locked_dumpTokens(); -#endif - return true; - } - - bool cancelActiveRequestTokens(TokenRequestType type) - { - RS_STACK_MUTEX(mMtx); - for(auto it = mActiveTokens.begin();it!=mActiveTokens.end();) - if(it->second == type) - { - mTokenService.cancelRequest(it->first); - it = mActiveTokens.erase(it); - } - else - ++it; - - return true; - } - - /// @see RsTokenService::cancelRequest - bool cancelRequest(uint32_t token) - { - { - RS_STACK_MUTEX(mMtx); - mActiveTokens.erase(token); - } - return mTokenService.cancelRequest(token); - } - - /** - * @deprecated - * Token service methods are already exposed by this helper, so you should - * not need to get token service pointer directly anymore. - */ - RS_DEPRECATED RsTokenService* getTokenService() { return &mTokenService; } - -protected: - /** - * Block caller while request is being processed. - * Useful for blocking API implementation. - * @param[in] token token associated to the request caller is waiting for - * @param[in] maxWait maximum waiting time in milliseconds - * @param[in] checkEvery time in millisecond between status checks - * @param[in] auto_delete_if_unsuccessful delete the request when it fails. This avoid leaving useless pending requests in the queue that would slow down additional calls. - */ - RsTokenService::GxsRequestStatus waitToken( - uint32_t token, - std::chrono::milliseconds maxWait = std::chrono::milliseconds(20000), - std::chrono::milliseconds checkEvery = std::chrono::milliseconds(100), - bool auto_delete_if_unsuccessful=true) - { -#if defined(__ANDROID__) && (__ANDROID_API__ < 24) - auto wkStartime = std::chrono::steady_clock::now(); - int maxWorkAroundCnt = 10; -LLwaitTokenBeginLabel: -#endif - auto timeout = std::chrono::steady_clock::now() + maxWait; - auto st = requestStatus(token); - - while( !(st == RsTokenService::FAILED || st >= RsTokenService::COMPLETE) - && std::chrono::steady_clock::now() < timeout ) - { - std::this_thread::sleep_for(checkEvery); - st = requestStatus(token); - } - if(st != RsTokenService::COMPLETE && auto_delete_if_unsuccessful) - cancelRequest(token); - -#if defined(__ANDROID__) && (__ANDROID_API__ < 24) - /* Work around for very slow/old android devices, we don't expect this - * to be necessary on newer devices. If it take unreasonably long - * something worser is already happening elsewere and we return anyway. - */ - if( st > RsTokenService::FAILED && st < RsTokenService::COMPLETE - && maxWorkAroundCnt-- > 0 ) - { - maxWait *= 10; - checkEvery *= 3; - Dbg3() << __PRETTY_FUNCTION__ << " Slow Android device " - << " workaround st: " << st - << " maxWorkAroundCnt: " << maxWorkAroundCnt - << " maxWait: " << maxWait.count() - << " checkEvery: " << checkEvery.count() << std::endl; - goto LLwaitTokenBeginLabel; - } - Dbg3() << __PRETTY_FUNCTION__ << " lasted: " - << std::chrono::duration_cast( - std::chrono::steady_clock::now() - wkStartime ).count() - << "ms" << std::endl; - -#endif - - { - RS_STACK_MUTEX(mMtx); - mActiveTokens.erase(token); - } - - return st; - } - -private: - RsGxsIface& mGxs; - RsTokenService& mTokenService; - RsMutex mMtx; - - std::map mActiveTokens; - -#ifdef DEBUG_GXSIFACEHELPER - void locked_dumpTokens() - { - const uint16_t service_id = mGxs.serviceType(); - const auto countSize = static_cast(TokenRequestType::__MAX); - uint32_t count[countSize] = {0}; - - RsDbg rsdbg; - rsdbg << __PRETTY_FUNCTION__ << " Service 0x" << std::hex << service_id - << " (" << rsServiceControl->getServiceName( - RsServiceInfo::RsServiceInfoUIn16ToFullServiceId(service_id) ) - << ") this=0x" << static_cast(this) - << ") Active tokens (per type): "; - - // let's count how many token of each type we've got. - for(auto& it: mActiveTokens) ++count[static_cast(it.second)]; - - for(uint32_t i=0; i < countSize; ++i) - rsdbg /* << i << ":" */ << count[i] << " "; - } -#endif // def DEBUG_GXSIFACEHELPER - - RS_SET_CONTEXT_DEBUG_LEVEL(1) -}; +/******************************************************************************* + * libretroshare/src/retroshare: rsgxsifacehelper.h * + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2011 Christopher Evi-Parker * + * Copyright (C) 2018-2021 Gioacchino Mazzurco * + * Copyright (C) 2019-2021 AsociaciĆ³n Civil Altermundi * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ +#pragma once + +#include +#include + +#include "retroshare/rsgxsiface.h" +#include "retroshare/rsservicecontrol.h" +#include "retroshare/rsreputations.h" +#include "rsgxsflags.h" +#include "util/rsdeprecate.h" +#include "util/rsdebug.h" + +/*! + * This class only make method of internal members visible tu upper level to + * offer a more friendly API. + * This is just a workaround to awkward GXS API design, do not take it as an + * example for your coding. + * To properly fix the API design many changes with the implied chain reactions + * are necessary, so at this point this workaround seems acceptable. + */ + +//================================== +// #define DEBUG_GXSIFACEHELPER 1 +//================================== + +enum class TokenRequestType: uint8_t +{ + __NONE = 0x00, /// Used to detect uninitialized + GROUP_DATA = 0x01, + GROUP_META = 0x02, + GROUP_IDS = 0x03, + POSTS = 0x04, + ALL_POSTS = 0x05, + MSG_RELATED_INFO = 0x06, + GROUP_STATISTICS = 0x07, + SERVICE_STATISTICS = 0x08, + NO_KILL_TYPE = 0x09, + __MAX /// Used to detect out of range +}; + +class RsGxsIfaceHelper +{ +public: + /*! + * @param gxs handle to RsGenExchange instance of service (Usually the + * service class itself) + */ + explicit RsGxsIfaceHelper(RsGxsIface& gxs) : + mGxs(gxs), mTokenService(*gxs.getTokenService()), mMtx("GxsIfaceHelper") + {} + + ~RsGxsIfaceHelper() = default; + +#ifdef TO_REMOVE + /*! + * Gxs services should call this for automatic handling of + * changes, send + * @param changes + */ + void receiveChanges(std::vector &changes) + { + mGxs.receiveChanges(changes); + } +#endif + + /* Generic Lists */ + + /*! + * Retrieve list of group ids associated to a request token + * @param token token to be redeemed for this request + * @param groupIds the ids return for given request token + * @return false if request token is invalid, check token status for error report + */ + bool getGroupList(const uint32_t &token, std::list &groupIds) + { + return mGxs.getGroupList(token, groupIds); + } + + /*! + * Retrieves list of msg ids associated to a request token + * @param token token to be redeemed for this request + * @param msgIds the ids return for given request token + * @return false if request token is invalid, check token status for error report + */ + bool getMsgList(const uint32_t &token, + GxsMsgIdResult& msgIds) + { + return mGxs.getMsgList(token, msgIds); + } + + /*! + * Retrieves list of msg related ids associated to a request token + * @param token token to be redeemed for this request + * @param msgIds the ids return for given request token + * @return false if request token is invalid, check token status for error report + */ + bool getMsgRelatedList(const uint32_t &token, MsgRelatedIdResult &msgIds) + { + return mGxs.getMsgRelatedList(token, msgIds); + } + + /*! + * @param token token to be redeemed for group summary request + * @param groupInfo the ids returned for given request token + * @return false if request token is invalid, check token status for error report + */ + bool getGroupSummary(const uint32_t &token, std::list &groupInfo) + { + return mGxs.getGroupMeta(token, groupInfo); + } + + /*! + * @param token token to be redeemed for message summary request + * @param msgInfo the message metadata returned for given request token + * @return false if request token is invalid, check token status for error report + */ + bool getMsgSummary(const uint32_t &token, GxsMsgMetaMap &msgInfo) + { + return mGxs.getMsgMeta(token, msgInfo); + } + + /*! + * @param token token to be redeemed for message related summary request + * @param msgInfo the message metadata returned for given request token + * @return false if request token is invalid, check token status for error report + */ + bool getMsgRelatedSummary(const uint32_t &token, GxsMsgRelatedMetaMap &msgInfo) + { + return mGxs.getMsgRelatedMeta(token, msgInfo); + } + + /*! + * subscribes to group, and returns token which can be used + * to be acknowledged to get group Id + * @param token token to redeem for acknowledgement + * @param grpId the id of the group to subscribe to + */ + bool subscribeToGroup(uint32_t& token, const RsGxsGroupId& grpId, bool subscribe) + { + return mGxs.subscribeToGroup(token, grpId, subscribe); + } + + /*! + * This allows the client service to acknowledge that their msgs has + * been created/modified and retrieve the create/modified msg ids + * @param token the token related to modification/create request + * @param msgIds map of grpid->msgIds of message created/modified + * @return true if token exists false otherwise + */ + bool acknowledgeMsg(const uint32_t& token, std::pair& msgId) + { + return mGxs.acknowledgeTokenMsg(token, msgId); + } + + /*! + * This allows the client service to acknowledge that their grps has + * been created/modified and retrieve the create/modified grp ids + * @param token the token related to modification/create request + * @param msgIds vector of ids of groups created/modified + * @return true if token exists false otherwise + */ + bool acknowledgeGrp(const uint32_t& token, RsGxsGroupId& grpId) + { + return mGxs.acknowledgeTokenGrp(token, grpId); + } + + /*! + * Gets service statistic for a given services + * @param token value to to retrieve requested stats + * @param stats the status + * @return true if token exists false otherwise + */ + bool getServiceStatistic(const uint32_t& token, GxsServiceStatistic& stats) + { + return mGxs.getServiceStatistic(token, stats); + } + + /*! + * + * @param token to be redeemed + * @param stats the stats associated to token request + * @return true if token is false otherwise + */ + bool getGroupStatistic(const uint32_t& token, GxsGroupStatistic& stats) + { + return mGxs.getGroupStatistic(token, stats); + } + + /*! + * @brief Get default maximum storage time for GXS messages + * @jsonapi{development} + * @return storage time in seconds + */ + uint32_t getDefaultStoragePeriod() + { return mGxs.getDefaultStoragePeriod(); } + + /*! + * @brief Get maximum storage time of GXS messages for the given group + * @jsonapi{development} + * @param[in] groupId Id of the group + * @return storage time in seconds + */ + uint32_t getStoragePeriod(const RsGxsGroupId& groupId) + { return mGxs.getStoragePeriod(groupId); } + + /*! + * @brief Set GXS messages maximum storage time for the given group + * @jsonapi{development} + * @param[in] groupId Id of the group + * @param[in] storageSecs storage time in seconds + */ + void setStoragePeriod(const RsGxsGroupId& groupId, uint32_t storageSecs) + { mGxs.setStoragePeriod(groupId, storageSecs); } + + /*! + * @brief Get default maximum syncronization age for GXS messages + * @jsonapi{development} + * @return age in seconds + */ + uint32_t getDefaultSyncPeriod() + { return mGxs.getDefaultSyncPeriod(); } + + /*! + * @brief Get maximum syncronization age of GXS messages for the given group + * @jsonapi{development} + * @param[in] groupId Id of the group + * @return age in seconds + */ + uint32_t getSyncPeriod(const RsGxsGroupId& groupId) + { return mGxs.getSyncPeriod(groupId); } + + /*! + * @brief Set GXS messages maximum syncronization age for the given group + * @jsonapi{development} + * @param[in] groupId Id of the group + * @param[in] syncAge age in seconds + */ + void setSyncPeriod(const RsGxsGroupId& groupId, uint32_t syncAge) + { mGxs.setSyncPeriod(groupId, syncAge); } + + /*! + * This determines the reputation threshold messages need to surpass in order + * for it to be accepted by local user from remote source + * NOTE: threshold only enforced if service require author signature + * @param token value set to be redeemed with acknowledgement + * @param grpId group id for cutoff value to be set + * @param CutOff The cut off value to set + */ + void setGroupReputationCutOff(uint32_t& token, const RsGxsGroupId& grpId, int CutOff) + { + return mGxs.setGroupReputationCutOff(token, grpId, CutOff); + } + + RsReputationLevel minReputationForForwardingMessages( + uint32_t group_sign_flags, uint32_t identity_flags ) + { + return mGxs.minReputationForForwardingMessages(group_sign_flags,identity_flags); + } + + /// @see RsTokenService::requestGroupInfo + bool requestGroupInfo( uint32_t& token, const RsTokReqOptions& opts, const std::list &groupIds, bool high_priority_request = false ) + { + TokenRequestType token_request_type; + + switch(opts.mReqType) + { + case GXS_REQUEST_TYPE_GROUP_DATA: token_request_type = TokenRequestType::GROUP_DATA; break; + case GXS_REQUEST_TYPE_GROUP_META: token_request_type = TokenRequestType::GROUP_META; break; + case GXS_REQUEST_TYPE_GROUP_IDS: token_request_type = TokenRequestType::GROUP_IDS; break; + default: + RsErr() << __PRETTY_FUNCTION__ << "(EE) Unexpected request type " << opts.mReqType << "!!" << std::endl; + return false; + } + + cancelActiveRequestTokens(token_request_type); + + if( mTokenService.requestGroupInfo(token, 0, opts, groupIds)) + { + RS_STACK_MUTEX(mMtx); + mActiveTokens[token]=high_priority_request? (TokenRequestType::NO_KILL_TYPE) : token_request_type; +#ifdef DEBUG_GXSIFACEHELPER + locked_dumpTokens(); +#endif + return true; + } + else + return false; + } + + /// @see RsTokenService::requestGroupInfo + bool requestGroupInfo(uint32_t& token, const RsTokReqOptions& opts, bool high_priority_request = false) + { + TokenRequestType token_request_type; + + switch(opts.mReqType) + { + case GXS_REQUEST_TYPE_GROUP_DATA: token_request_type = TokenRequestType::GROUP_DATA; break; + case GXS_REQUEST_TYPE_GROUP_META: token_request_type = TokenRequestType::GROUP_META; break; + case GXS_REQUEST_TYPE_GROUP_IDS: token_request_type = TokenRequestType::GROUP_IDS; break; + default: + RsErr() << __PRETTY_FUNCTION__ << "(EE) Unexpected request type " << opts.mReqType << "!!" << std::endl; + return false; + } + + cancelActiveRequestTokens(token_request_type); + + + if( mTokenService.requestGroupInfo(token, 0, opts)) + { + RS_STACK_MUTEX(mMtx); + mActiveTokens[token]=high_priority_request? (TokenRequestType::NO_KILL_TYPE) : token_request_type; +#ifdef DEBUG_GXSIFACEHELPER + locked_dumpTokens(); +#endif + return true; + } + else + return false; + } + + /// @see RsTokenService::requestMsgInfo + bool requestMsgInfo( uint32_t& token, const RsTokReqOptions& opts, const GxsMsgReq& msgIds ) + { + if(mTokenService.requestMsgInfo(token, 0, opts, msgIds)) + { + RS_STACK_MUTEX(mMtx); + + mActiveTokens[token]= (msgIds.size()==1 && msgIds.begin()->second.size()==0) ?(TokenRequestType::ALL_POSTS):(TokenRequestType::POSTS); +#ifdef DEBUG_GXSIFACEHELPER + locked_dumpTokens(); +#endif + return true; + } + else + return false; + } + + /// @see RsTokenService::requestMsgInfo + bool requestMsgInfo( uint32_t& token, const RsTokReqOptions& opts, const std::list& grpIds ) + { + if(mTokenService.requestMsgInfo(token, 0, opts, grpIds)) + { + RS_STACK_MUTEX(mMtx); + mActiveTokens[token]=TokenRequestType::ALL_POSTS; +#ifdef DEBUG_GXSIFACEHELPER + locked_dumpTokens(); +#endif + return true; + } + else + return false; + } + + /// @see RsTokenService::requestMsgRelatedInfo + bool requestMsgRelatedInfo( + uint32_t& token, const RsTokReqOptions& opts, + const std::vector& msgIds ) + { + if( mTokenService.requestMsgRelatedInfo(token, 0, opts, msgIds)) + { + RS_STACK_MUTEX(mMtx); + mActiveTokens[token]=TokenRequestType::MSG_RELATED_INFO; +#ifdef DEBUG_GXSIFACEHELPER + locked_dumpTokens(); +#endif + return true; + } + else + return false; + } + + /** + * @jsonapi{development} + * @param[in] token + */ + RsTokenService::GxsRequestStatus requestStatus(uint32_t token) + { return mTokenService.requestStatus(token); } + + /// @see RsTokenService::requestServiceStatistic + bool requestServiceStatistic(uint32_t& token) + { + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_SERVICE_STATS; + + mTokenService.requestServiceStatistic(token,opts); + + RS_STACK_MUTEX(mMtx); + mActiveTokens[token]=TokenRequestType::SERVICE_STATISTICS; + +#ifdef DEBUG_GXSIFACEHELPER + locked_dumpTokens(); +#endif + return true; + } + + /// @see RsTokenService::requestGroupStatistic + bool requestGroupStatistic(uint32_t& token, const RsGxsGroupId& grpId) + { + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_GROUP_STATS; + + mTokenService.requestGroupStatistic(token, grpId,opts); + + RS_STACK_MUTEX(mMtx); + mActiveTokens[token]=TokenRequestType::GROUP_STATISTICS; +#ifdef DEBUG_GXSIFACEHELPER + locked_dumpTokens(); +#endif + return true; + } + + bool cancelActiveRequestTokens(TokenRequestType type) + { + RS_STACK_MUTEX(mMtx); + for(auto it = mActiveTokens.begin();it!=mActiveTokens.end();) + if(it->second == type) + { + mTokenService.cancelRequest(it->first); + it = mActiveTokens.erase(it); + } + else + ++it; + + return true; + } + + /// @see RsTokenService::cancelRequest + bool cancelRequest(uint32_t token) + { + { + RS_STACK_MUTEX(mMtx); + mActiveTokens.erase(token); + } + return mTokenService.cancelRequest(token); + } + + /** + * @deprecated + * Token service methods are already exposed by this helper, so you should + * not need to get token service pointer directly anymore. + */ + RS_DEPRECATED RsTokenService* getTokenService() { return &mTokenService; } + +protected: + /** + * Block caller while request is being processed. + * Useful for blocking API implementation. + * @param[in] token token associated to the request caller is waiting for + * @param[in] maxWait maximum waiting time in milliseconds + * @param[in] checkEvery time in millisecond between status checks + * @param[in] auto_delete_if_unsuccessful delete the request when it fails. This avoid leaving useless pending requests in the queue that would slow down additional calls. + */ + RsTokenService::GxsRequestStatus waitToken( + uint32_t token, + std::chrono::milliseconds maxWait = std::chrono::milliseconds(20000), + std::chrono::milliseconds checkEvery = std::chrono::milliseconds(100), + bool auto_delete_if_unsuccessful=true) + { +#if defined(__ANDROID__) && (__ANDROID_API__ < 24) + auto wkStartime = std::chrono::steady_clock::now(); + int maxWorkAroundCnt = 10; +LLwaitTokenBeginLabel: +#endif + auto timeout = std::chrono::steady_clock::now() + maxWait; + auto st = requestStatus(token); + + while( !(st == RsTokenService::FAILED || st >= RsTokenService::COMPLETE) + && std::chrono::steady_clock::now() < timeout ) + { + std::this_thread::sleep_for(checkEvery); + st = requestStatus(token); + } + if(st != RsTokenService::COMPLETE && auto_delete_if_unsuccessful) + cancelRequest(token); + +#if defined(__ANDROID__) && (__ANDROID_API__ < 24) + /* Work around for very slow/old android devices, we don't expect this + * to be necessary on newer devices. If it take unreasonably long + * something worser is already happening elsewere and we return anyway. + */ + if( st > RsTokenService::FAILED && st < RsTokenService::COMPLETE + && maxWorkAroundCnt-- > 0 ) + { + maxWait *= 10; + checkEvery *= 3; + Dbg3() << __PRETTY_FUNCTION__ << " Slow Android device " + << " workaround st: " << st + << " maxWorkAroundCnt: " << maxWorkAroundCnt + << " maxWait: " << maxWait.count() + << " checkEvery: " << checkEvery.count() << std::endl; + goto LLwaitTokenBeginLabel; + } + Dbg3() << __PRETTY_FUNCTION__ << " lasted: " + << std::chrono::duration_cast( + std::chrono::steady_clock::now() - wkStartime ).count() + << "ms" << std::endl; + +#endif + + { + RS_STACK_MUTEX(mMtx); + mActiveTokens.erase(token); + } + + return st; + } + +private: + RsGxsIface& mGxs; + RsTokenService& mTokenService; + RsMutex mMtx; + + std::map mActiveTokens; + +#ifdef DEBUG_GXSIFACEHELPER + void locked_dumpTokens() + { + const uint16_t service_id = mGxs.serviceType(); + const auto countSize = static_cast(TokenRequestType::__MAX); + uint32_t count[countSize] = {0}; + + RsDbg rsdbg; + rsdbg << __PRETTY_FUNCTION__ << " Service 0x" << std::hex << service_id + << " (" << rsServiceControl->getServiceName( + RsServiceInfo::RsServiceInfoUIn16ToFullServiceId(service_id) ) + << ") this=0x" << static_cast(this) + << ") Active tokens (per type): "; + + // let's count how many token of each type we've got. + for(auto& it: mActiveTokens) ++count[static_cast(it.second)]; + + for(uint32_t i=0; i < countSize; ++i) + rsdbg /* << i << ":" */ << count[i] << " "; + } +#endif // def DEBUG_GXSIFACEHELPER + + RS_SET_CONTEXT_DEBUG_LEVEL(1) +};