/******************************************************************************* * libretroshare/src/retroshare: rstokenservice.h * * * * libretroshare: retroshare core library * * * * Copyright (C) 2012 Chris Evi-Parker * * Copyright (C) 2012 Robert Fernie * * Copyright (C) 2018-2019 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 * * 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 #include "retroshare/rsgxsifacetypes.h" #include "util/rsdeprecate.h" #include "util/rsdebug.h" // TODO CLEANUP: GXS_REQUEST_TYPE_* should be an inner enum of RsTokReqOptions #define GXS_REQUEST_TYPE_GROUP_DATA 0x00010000 #define GXS_REQUEST_TYPE_GROUP_META 0x00020000 #define GXS_REQUEST_TYPE_GROUP_IDS 0x00040000 #define GXS_REQUEST_TYPE_MSG_DATA 0x00080000 #define GXS_REQUEST_TYPE_MSG_META 0x00100000 #define GXS_REQUEST_TYPE_MSG_IDS 0x00200000 #define GXS_REQUEST_TYPE_MSG_RELATED_DATA 0x00400000 #define GXS_REQUEST_TYPE_MSG_RELATED_META 0x00800000 #define GXS_REQUEST_TYPE_MSG_RELATED_IDS 0x01000000 #define GXS_REQUEST_TYPE_GROUP_STATS 0x01600000 #define GXS_REQUEST_TYPE_SERVICE_STATS 0x03200000 #define GXS_REQUEST_TYPE_GROUP_SERIALIZED_DATA 0x04000000 // TODO CLEANUP: RS_TOKREQOPT_MSG_* should be an inner enum of RsTokReqOptions #define RS_TOKREQOPT_MSG_VERSIONS 0x0001 // MSGRELATED: Returns All MsgIds with OrigMsgId = MsgId. #define RS_TOKREQOPT_MSG_ORIGMSG 0x0002 // MSGLIST: All Unique OrigMsgIds in a Group. #define RS_TOKREQOPT_MSG_LATEST 0x0004 // MSGLIST: All Latest MsgIds in Group. MSGRELATED: Latest MsgIds for Input Msgs. #define RS_TOKREQOPT_MSG_THREAD 0x0010 // MSGRELATED: All Msgs in Thread. MSGLIST: All Unique Thread Ids in Group. #define RS_TOKREQOPT_MSG_PARENT 0x0020 // MSGRELATED: All Children Msgs. #define RS_TOKREQOPT_MSG_AUTHOR 0x0040 // MSGLIST: Messages from this AuthorId /* TODO CLEANUP: RS_TOKREQ_ANSTYPE_* values are meaningless and not used by * RsTokenService or its implementation, and may be arbitrarly defined by each * GXS client as they are of no usage, their use is deprecated, up until the * definitive cleanup is done new code must use RS_DEPRECATED_TOKREQ_ANSTYPE for * easier cleanup. */ #ifndef RS_NO_WARN_DEPRECATED # warning RS_TOKREQ_ANSTYPE_* macros are deprecated! #endif #define RS_DEPRECATED_TOKREQ_ANSTYPE 0x0000 #define RS_TOKREQ_ANSTYPE_LIST 0x0001 #define RS_TOKREQ_ANSTYPE_SUMMARY 0x0002 #define RS_TOKREQ_ANSTYPE_DATA 0x0003 #define RS_TOKREQ_ANSTYPE_ACK 0x0004 /*! * This class provides useful generic support for GXS style services. * I expect much of this will be incorporated into the base GXS. */ struct RsTokReqOptions { RsTokReqOptions() : mOptions(0), mStatusFilter(0), mStatusMask(0), mMsgFlagMask(0), mMsgFlagFilter(0), mReqType(0), mSubscribeFilter(0), mSubscribeMask(0), mBefore(0), mAfter(0),mPriority(GxsRequestPriority::NORMAL) {} /** * Can be one or multiple RS_TOKREQOPT_* * TODO: cleanup this should be made with proper flags instead of macros */ uint32_t mOptions; // Request specific matches with Group / Message Status. // Should be usable with any Options... applied afterwards. uint32_t mStatusFilter; uint32_t mStatusMask; // use uint32_t mMsgFlagMask, mMsgFlagFilter; /** * Must be one of GXS_REQUEST_TYPE_* * TODO: cleanup this should be made an enum instead of macros */ uint32_t mReqType; uint32_t mSubscribeFilter, mSubscribeMask; // Only for Groups. // Time range... again applied after Options. rstime_t mBefore; rstime_t mAfter; GxsRequestPriority mPriority; }; /*! * A proxy class for requesting generic service data for GXS * This seperates the request mechanism from the actual retrieval of data */ class RsTokenService { public: enum GxsRequestStatus : uint8_t { FAILED = 0, PENDING = 1, PARTIAL = 2, COMPLETE = 3, DONE = 4, /// Once all data has been retrived CANCELLED = 5 }; RsTokenService() {} virtual ~RsTokenService() {} /* Data Requests */ /*! * Use this to request group related information * @param token The token returned for the request, store this value to poll for request completion * @param ansType The type of result (e.g. group data, meta, ids) * @param opts Additional option that affect outcome of request. Please see specific services, for valid values * @param groupIds group id to request info for * @return */ virtual bool requestGroupInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const std::list &groupIds) = 0; /*! * Use this to request all group related info * @param token The token returned for the request, store this value to poll for request completion * @param ansType The type of result (e.g. group data, meta, ids) * @param opts Additional option that affect outcome of request. Please see specific services, for valid values * @return */ virtual bool requestGroupInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts) = 0; /*! * Use this to get msg related information, store this value to poll for request completion * @param token The token returned for the request * @param ansType The type of result wanted * @param opts Additional option that affect outcome of request. Please see specific services, for valid values * @param groupIds The ids of the groups to get, second entry of map empty to query for all msgs * @return true if request successful false otherwise */ virtual bool requestMsgInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const GxsMsgReq& msgIds) = 0; /*! * Use this to get msg related information, store this value to poll for request completion * @param token The token returned for the request * @param ansType The type of result wanted * @param opts Additional option that affect outcome of request. Please see specific services, for valid values * @param groupIds The ids of the groups to get, this retrieves all the msgs info for each grpId in list * @return true if request successful false otherwise */ virtual bool requestMsgInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const std::list& grpIds) = 0; /*! * For requesting msgs related to a given msg id within a group * @param token The token returned for the request * @param ansType The type of result wanted * @param opts Additional option that affect outcome of request. Please see specific services, for valid values * @param groupIds The ids of the groups to get, second entry of map empty to query for all msgs * @return true if request successful false otherwise */ virtual bool requestMsgRelatedInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const std::vector& msgIds) = 0; /*! * This request statistics on amount of data held * number of groups * number of groups subscribed * number of messages * size of db store * total size of messages * total size of groups * @param token */ virtual void requestServiceStatistic(uint32_t& token, const RsTokReqOptions &opts) = 0; /*! * To request statistic on a group * @param token set to value to be redeemed to get statistic * @param grpId the id of the group */ virtual void requestGroupStatistic(uint32_t& token, const RsGxsGroupId& grpId, const RsTokReqOptions &opts) = 0; /* Poll */ /*! * Request the status of ongoing request. * Please use this for polling as much cheaper * than polling the specific service as they might * not return intermediate status information * @param token value of token to check status for * @return the current status of request */ virtual GxsRequestStatus requestStatus(const uint32_t token) = 0; /*! * @brief Cancel Request * If this function returns false, it may be that the request has completed * already. Useful for very expensive request. * @param token the token of the request to cancel * @return false if unusuccessful in cancelling request, true if successful */ virtual bool cancelRequest(const uint32_t &token) = 0; #ifdef TO_REMOVE /** * 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 */ RsTokenService::GxsRequestStatus waitToken( uint32_t token, std::chrono::milliseconds maxWait = std::chrono::milliseconds(10000), std::chrono::milliseconds checkEvery = std::chrono::milliseconds(20), 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 return st; } #endif RS_SET_CONTEXT_DEBUG_LEVEL(2) };