Implement GXS group base64 public data export

Link to GXS group is a concept that is useful for almost all GXS based
  services, gen exchange now provides method to facilitate the
  implementation of group links at service layer.
Move waitToken in token service interface.
This commit is contained in:
Gioacchino Mazzurco 2019-10-28 15:07:50 +01:00
parent a9510da61b
commit 6f3d842d30
No known key found for this signature in database
GPG Key ID: A1FBCA3872E87051
5 changed files with 173 additions and 52 deletions

View File

@ -21,6 +21,7 @@
* *
*******************************************************************************/
#include <unistd.h>
#include <algorithm>
#include "pqi/pqihash.h"
#include "rsgenexchange.h"
@ -38,8 +39,7 @@
#include "rsgxsutil.h"
#include "rsserver/p3face.h"
#include "retroshare/rsevents.h"
#include <algorithm>
#include "util/radix64.h"
#define PUB_GRP_MASK 0x000f
#define RESTR_GRP_MASK 0x00f0
@ -3445,6 +3445,71 @@ bool RsGenExchange::localSearch( const std::string& matchString,
return mNetService->search(matchString, results);
}
bool RsGenExchange::exportGroupBase64(
std::string& radix, const RsGxsGroupId& groupId, std::string& errMsg )
{
constexpr auto fname = __PRETTY_FUNCTION__;
const auto failure = [&](const std::string& err)
{
errMsg = err;
RsErr() << fname << " " << err << std::endl;
return false;
};
if(groupId.isNull()) return failure("groupId cannot be null");
const std::list<RsGxsGroupId> groupIds({groupId});
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA;
uint32_t token;
mDataAccess->requestGroupInfo(
token, RS_TOKREQ_ANSTYPE_DATA, opts, groupIds);
RsTokenService::GxsRequestStatus wtStatus = mDataAccess->waitToken(token);
if(wtStatus != RsTokenService::COMPLETE)
return failure( "waitToken(...) failed with: " +
std::to_string(wtStatus) );
uint8_t* buf = nullptr;
uint32_t size;
RsGxsGroupId grpId;
if(!getSerializedGroupData(token, grpId, buf, size))
return failure("failed retrieving GXS data");
Radix64::encode(buf, static_cast<int>(size), radix);
free(buf);
return true;
}
bool RsGenExchange::importGroupBase64(
const std::string& radix, RsGxsGroupId& groupId,
std::string& errMsg )
{
constexpr auto fname = __PRETTY_FUNCTION__;
const auto failure = [&](const std::string& err)
{
errMsg = err;
RsErr() << fname << " " << err << std::endl;
return false;
};
if(radix.empty()) return failure("radix is empty");
std::vector<uint8_t> mem = Radix64::decode(radix);
if(mem.empty()) return failure("radix seems corrupted");
// On success this also import the group as pending validation
if(!deserializeGroupData(
mem.data(), static_cast<uint32_t>(mem.size()),
reinterpret_cast<RsGxsGroupId*>(&groupId) ))
return failure("failed deserializing group");
return true;
}
RsGxsChanges::RsGxsChanges() :
RsEvent(RsEventType::GXS_CHANGES), mServiceType(RsServiceType::NONE),
mService(nullptr) {}
RsGxsIface::~RsGxsIface() = default;
RsGxsGroupSummary::~RsGxsGroupSummary() = default;

View File

@ -95,7 +95,8 @@ typedef std::map<RsGxsGrpMsgIdPair, std::vector<RsGxsMsgItem*> > GxsMsgRelatedDa
class RsGixs;
class RsGenExchange : public RsNxsObserver, public RsTickingThread, public RsGxsIface
class RsGenExchange : public RsNxsObserver, public RsTickingThread,
public RsGxsIface
{
public:
@ -325,6 +326,19 @@ public:
bool localSearch( const std::string& matchString,
std::list<RsGxsGroupSummary>& results );
/// @see RsGxsIface
bool exportGroupBase64(
std::string& radix, const RsGxsGroupId& groupId,
std::string& errMsg = RS_DEFAULT_STORAGE_PARAM(std::string)
) override;
/// @see RsGxsIface
bool importGroupBase64(
const std::string& radix,
RsGxsGroupId& groupId = RS_DEFAULT_STORAGE_PARAM(RsGxsGroupId),
std::string& errMsg = RS_DEFAULT_STORAGE_PARAM(std::string)
) override;
protected:
bool messagePublicationTest(const RsGxsMsgMetaData&) ;

View File

@ -68,6 +68,8 @@ struct RsGxsGroupSummary : RsSerializable
RS_SERIAL_PROCESS(mPopularity);
RS_SERIAL_PROCESS(mSearchContext);
}
~RsGxsGroupSummary();
};
@ -108,8 +110,6 @@ struct RsGxsChanges : RsEvent
*/
struct RsGxsIface
{
virtual ~RsGxsIface() {}
/*!
* Gxs services should call this for automatic handling of
* changes, send
@ -238,4 +238,32 @@ struct RsGxsIface
virtual RsReputationLevel minReputationForForwardingMessages(
uint32_t group_sign_flags,uint32_t identity_flags ) = 0;
/**
* @brief Export group public data in base64 format
* @jsonapi{development}
* @param[out] radix storage for the generated base64 data
* @param[in] groupId Id of the group of which to output the data
* @param[out] errMsg optional storage for error message, meaningful only in
* case of failure
* @return false if something failed, true otherwhise
*/
virtual bool exportGroupBase64(
std::string& radix, const RsGxsGroupId& groupId,
std::string& errMsg = RS_DEFAULT_STORAGE_PARAM(std::string) ) = 0;
/**
* @brief Import group public data from base64 string
* @param[in] radix group invite in radix format
* @param[out] groupId optional storage for imported group id
* @param[out] errMsg optional storage for error message, meaningful only in
* case of failure
* @return false if some error occurred, true otherwise
*/
virtual bool importGroupBase64(
const std::string& radix,
RsGxsGroupId& groupId = RS_DEFAULT_STORAGE_PARAM(RsGxsGroupId),
std::string& errMsg = RS_DEFAULT_STORAGE_PARAM(std::string) ) = 0;
virtual ~RsGxsIface();
};

View File

@ -296,47 +296,7 @@ protected:
uint32_t token,
std::chrono::milliseconds maxWait = std::chrono::milliseconds(500),
std::chrono::milliseconds checkEvery = std::chrono::milliseconds(2))
{
#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 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;
std::cerr << __PRETTY_FUNCTION__ << " Slow Android device "
<< " workaround st: " << st
<< " maxWorkAroundCnt: " << maxWorkAroundCnt
<< " maxWait: " << maxWait.count()
<< " checkEvery: " << checkEvery.count() << std::endl;
goto LLwaitTokenBeginLabel;
}
std::cerr << __PRETTY_FUNCTION__ << " lasted: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - wkStartime ).count()
<< "ms" << std::endl;
#endif
return st;
}
{ return mTokenService.waitToken(token, maxWait, checkEvery); }
private:
RsGxsIface& mGxs;

View File

@ -3,7 +3,9 @@
* *
* libretroshare: retroshare core library *
* *
* Copyright 2012-2012 by Robert Fernie, Chris Evi-Parker *
* Copyright (C) 2012 Chris Evi-Parker *
* Copyright (C) 2012 Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
* *
* 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,8 +21,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#ifndef RSTOKENSERVICE_H
#define RSTOKENSERVICE_H
#pragma once
#include <inttypes.h>
#include <string>
@ -28,6 +29,7 @@
#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
@ -113,7 +115,6 @@ struct RsTokReqOptions
*/
class RsTokenService
{
public:
enum GxsRequestStatus : uint8_t
@ -220,6 +221,59 @@ public:
* @return false if unusuccessful in cancelling request, true if successful
*/
virtual bool cancelRequest(const uint32_t &token) = 0;
};
#endif // RSTOKENSERVICE_H
/**
* 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(500),
std::chrono::milliseconds checkEvery = std::chrono::milliseconds(2))
{
#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 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::milliseconds>(
std::chrono::steady_clock::now() - wkStartime ).count()
<< "ms" << std::endl;
#endif
return st;
}
RS_SET_CONTEXT_DEBUG_LEVEL(2)
};