diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..c7a51f9c5 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,49 @@ +image: docker:stable + +services: + - docker:stable-dind + +workflow: + rules: + - if: $CI_MERGE_REQUEST_ID + - if: $CI_COMMIT_BRANCH + +build-and-test: + script: + - > + if [ -n "$CI_MERGE_REQUEST_ID" ]; then + MR_ARGS="--build-arg REPO_URL=$CI_MERGE_REQUEST_SOURCE_PROJECT_URL" ; + MR_ARGS="$MR_ARGS --build-arg REPO_BRANCH=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME" ; + export MR_ARGS ; + fi + - mkdir Dockercontext + - > + docker build -t retroshare:testing $MR_ARGS + --file $CI_PROJECT_DIR/build_scripts/GitlabCI/gitlabCI.Dockerfile + Dockercontext + - > + docker run --name retroshare --detach --tty retroshare:testing + retroshare-service --jsonApiPort 9092 + - apk add jq + - > + docker exec retroshare + curl --verbose http://127.0.0.1:9092/rsJsonApi/version | jq + - > + docker exec retroshare + curl --verbose http://127.0.0.1:9092/rsLoginHelper/getLocations | jq + - > + docker exec retroshare + curl --verbose --data + '{ "location":{ "mLocationName":"Test 1", "mPgpName":"Test2" }, + "password":"Test 3", "caller_data":"Test 5" }' + http://127.0.0.1:9092/rsLoginHelper/createLocation | jq + - > + docker exec retroshare + curl --verbose http://127.0.0.1:9092/rsLoginHelper/getLocations | jq + - > + docker exec retroshare + curl --verbose http://127.0.0.1:9092/rsLoginHelper/isLoggedIn | jq + - > + docker exec retroshare + curl --verbose http://127.0.0.1:9092/rsMsgs/getChatLobbyList | jq + - docker container stop retroshare diff --git a/README.asciidoc b/README.asciidoc index 28a3309e8..734c3d083 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -9,6 +9,7 @@ RetroShare provides file sharing, chat, messages, forums, channels and more. .Build Status |=============================================================================== +|GNU/Linux (via Gitlab CI) | image:https://gitlab.com/RetroShare/RetroShare/badges/master/pipeline.svg[link="https://gitlab.com/RetroShare/RetroShare/-/commits/master",title="pipeline status"] |GNU/Linux, macOS, (via Travis CI) | image:https://travis-ci.org/RetroShare/RetroShare.svg?branch=master[link="https://travis-ci.org/RetroShare/RetroShare"] |Windows (via AppVeyor) | image:https://ci.appveyor.com/api/projects/status/github/RetroShare/RetroShare?svg=true[link="https://ci.appveyor.com/project/RetroShare58622/retroshare"] |=============================================================================== diff --git a/build_scripts/GitlabCI/base.Dockerfile b/build_scripts/GitlabCI/base.Dockerfile new file mode 100644 index 000000000..f4cf610db --- /dev/null +++ b/build_scripts/GitlabCI/base.Dockerfile @@ -0,0 +1,43 @@ +## Add +--build-arg FRESHCLONE=$(date +%s)+ to docker build commandline to +## force cloning a new + +## To prepare an image suitable as base for Gitlab CI use +# docker build -t "${CI_REGISTRY_IMAGE}:base" --build-arg KEEP_SOURCE=true --build-arg REPO_DEPTH="" -f base.Dockerfile . + +## Now you need to tag it so you can later push it +# docker tag ${ID_OF_THE_CREATED_IMAGE} registry.gitlab.com/retroshare/${CI_REGISTRY_IMAGE}:base + +## To push it to gitlab CI registry you need first to login and the to push +# docker login registry.gitlab.com +# docker push registry.gitlab.com/retroshare/${CI_REGISTRY_IMAGE}:base + + +## To run the container +# docker run -it -p 127.0.0.1:9092:9092 "${CI_REGISTRY_IMAGE}:base" retroshare-service --jsonApiPort 9092 --jsonApiBindAddress 0.0.0.0 + +FROM ubuntu + +ARG CACHEBUST=0 +RUN \ + apt-get update -y && apt-get upgrade -y && \ + apt-get install -y build-essential libssl-dev libbz2-dev libsqlite3-dev \ + libsqlcipher-dev libupnp-dev pkg-config libz-dev \ + qt5-default libxapian-dev qttools5-dev doxygen rapidjson-dev \ + git cmake curl + +ARG FRESHCLONE=0 +ARG REPO_URL=https://gitlab.com/RetroShare/RetroShare.git +ARG REPO_BRANCH=master +ARG REPO_DEPTH="--depth 2000" +ARG KEEP_SOURCE=false +RUN apt-get update -y && apt-get upgrade -y +RUN git clone $REPO_DEPTH $REPO_URL -b $REPO_BRANCH && cd RetroShare && \ + git fetch --tags && cd .. +RUN \ + mkdir RetroShare-build && cd RetroShare-build && \ + qmake ../RetroShare \ + CONFIG+=no_retroshare_plugins CONFIG+=ipv6 \ + CONFIG+=retroshare_service CONFIG+=no_retroshare_gui \ + CONFIG+=rs_jsonapi CONFIG+=rs_deep_search && \ + (make -j$(nproc) || make -j$(nproc) || make) && make install && \ + cd .. && rm -rf RetroShare-build && ($KEEP_SOURCE || rm -rf RetroShare) diff --git a/build_scripts/GitlabCI/gitlabCI.Dockerfile b/build_scripts/GitlabCI/gitlabCI.Dockerfile new file mode 100644 index 000000000..87d064de1 --- /dev/null +++ b/build_scripts/GitlabCI/gitlabCI.Dockerfile @@ -0,0 +1,17 @@ +FROM registry.gitlab.com/retroshare/retroshare:base + +RUN apt-get update -y && apt-get upgrade -y + +ARG REPO_URL=https://gitlab.com/RetroShare/RetroShare.git +ARG REPO_BRANCH=master +RUN \ + cd RetroShare && git remote add testing $REPO_URL && \ + git fetch --tags testing $REPO_BRANCH && \ + git reset --hard testing/$REPO_BRANCH +RUN \ + mkdir RetroShare-build && cd RetroShare-build && \ + qmake ../RetroShare CONFIG+=no_retroshare_gui \ + CONFIG+=retroshare_service \ + CONFIG+=rs_jsonapi CONFIG+=rs_deep_search && \ + (make -j$(nproc) || make -j$(nproc) || make) && make install && \ + cd .. && rm -rf RetroShare-build diff --git a/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc index bee4c9b59..97d552c0a 100644 --- a/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc +++ b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc @@ -37,6 +37,7 @@ RsItem *RsDiscSerialiser::create_item( { case RsGossipDiscoveryItemType::PGP_LIST: return new RsDiscPgpListItem(); case RsGossipDiscoveryItemType::PGP_CERT_BINARY: return new RsDiscPgpKeyItem(); + case RsGossipDiscoveryItemType::PGP_CERT: return new RsDiscPgpCertItem(); // deprecated, hanlde to suppress "unkown item" warning case RsGossipDiscoveryItemType::CONTACT: return new RsDiscContactItem(); case RsGossipDiscoveryItemType::IDENTITY_LIST: return new RsDiscIdentityListItem(); default: diff --git a/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h index f5e219b95..0a1874539 100644 --- a/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h +++ b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h @@ -97,6 +97,27 @@ public: uint32_t bin_len; }; +class RS_DEPRECATED_FOR(RsDiscPgpKeyItem) RsDiscPgpCertItem: public RsDiscItem +{ +public: + RsDiscPgpCertItem() : RsDiscItem(RsGossipDiscoveryItemType::PGP_CERT) + { setPriorityLevel(QOS_PRIORITY_RS_DISC_PGP_CERT); } + + void clear() override + { + pgpId.clear(); + pgpCert.clear(); + } + void serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx) override + { + RsTypeSerializer::serial_process(j,ctx,pgpId,"pgpId") ; + RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_STR_PGPCERT,pgpCert,"pgpCert") ; + } + + RsPgpId pgpId; + std::string pgpCert; +}; + class RsDiscContactItem: public RsDiscItem { public: diff --git a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc index 81dd097e0..77c0fd491 100644 --- a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc +++ b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc @@ -260,6 +260,7 @@ int p3discovery2::handleIncoming() { RsDiscPgpListItem* pgplist = nullptr; RsDiscPgpKeyItem* pgpkey = nullptr; + RsDiscPgpCertItem* pgpcert = nullptr; // deprecated, hanlde for retro compability RsDiscContactItem* contact = nullptr; RsDiscIdentityListItem* gxsidlst = nullptr; @@ -282,6 +283,9 @@ int p3discovery2::handleIncoming() } else if((pgpkey = dynamic_cast(item)) != nullptr) recvPGPCertificate(item->PeerId(), pgpkey); + else if((pgpcert = dynamic_cast(item)) != nullptr) + // sink + delete pgpcert; else if((pgplist = dynamic_cast(item)) != nullptr) { if (pgplist->mode == RsGossipDiscoveryPgpListMode::FRIENDS) diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index c7c274fa4..af4a02fcd 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -1193,7 +1193,7 @@ bool RsGenExchange::getGroupList(const uint32_t &token, std::list bool RsGenExchange::getMsgList(const uint32_t &token, GxsMsgIdResult &msgIds) { - return mDataAccess->getMsgList(token, msgIds); + return mDataAccess->getMsgIdList(token, msgIds); } bool RsGenExchange::getMsgRelatedList(const uint32_t &token, MsgRelatedIdResult &msgIds) @@ -1692,7 +1692,7 @@ void RsGenExchange::notifyChangedGroupStats(const RsGxsGroupId &grpId) { RS_STACK_MUTEX(mGenMtx); - RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_PROCESSED, false); + RsGxsGroupChange* gc = new RsGxsGroupChange(RsGxsNotify::TYPE_STATISTICS_CHANGED, false); gc->mGrpIdList.push_back(grpId); mNotifications.push_back(gc); } diff --git a/libretroshare/src/gxs/rsgxsdataaccess.cc b/libretroshare/src/gxs/rsgxsdataaccess.cc index dd41f9237..30904d701 100644 --- a/libretroshare/src/gxs/rsgxsdataaccess.cc +++ b/libretroshare/src/gxs/rsgxsdataaccess.cc @@ -30,27 +30,29 @@ * #define DATA_DEBUG 1 **********/ +bool operator<(const std::pair& p1,const std::pair& p2) +{ + return p1.second->Options.mPriority <= p2.second->Options.mPriority ; // <= so that new elements with same priority are inserted before +} + RsGxsDataAccess::RsGxsDataAccess(RsGeneralDataService* ds) : mDataStore(ds), mDataMutex("RsGxsDataAccess"), mNextToken(0) {} RsGxsDataAccess::~RsGxsDataAccess() { - for(std::map::const_iterator it(mRequests.begin());it!=mRequests.end();++it) - delete it->second ; + for(auto& it:mRequestQueue) + delete it.second; } -bool RsGxsDataAccess::requestGroupInfo( - uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, - const std::list &groupIds ) +bool RsGxsDataAccess::requestGroupInfo( uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const std::list &groupIds ) { if(groupIds.empty()) { - std::cerr << __PRETTY_FUNCTION__ << " (WW) Group Id list is empty!" - << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " (WW) Group Id list is empty!" << std::endl; return false; } - GxsRequest* req = NULL; + GxsRequest* req = nullptr; uint32_t reqType = opts.mReqType; if(reqType & GXS_REQUEST_TYPE_GROUP_META) @@ -80,16 +82,14 @@ bool RsGxsDataAccess::requestGroupInfo( if(!req) { - std::cerr << __PRETTY_FUNCTION__ << " request type not recognised, " - << "reqType: " << reqType << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " request type not recognised, " << "reqType: " << reqType << std::endl; return false; } generateToken(token); #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::requestGroupInfo() gets token: " << token - << std::endl; + RsErr() << "RsGxsDataAccess::requestGroupInfo() gets token: " << token << std::endl; #endif setReq(req, token, ansType, opts); @@ -101,7 +101,7 @@ bool RsGxsDataAccess::requestGroupInfo( bool RsGxsDataAccess::requestGroupInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts) { - GxsRequest* req = NULL; + GxsRequest* req = nullptr; uint32_t reqType = opts.mReqType; if(reqType & GXS_REQUEST_TYPE_GROUP_META) @@ -114,14 +114,13 @@ bool RsGxsDataAccess::requestGroupInfo(uint32_t &token, uint32_t ansType, const req = new GroupSerializedDataReq(); else { - std::cerr << "RsGxsDataAccess::requestGroupInfo() request type not recognised, type " - << reqType << std::endl; + RsErr() << "RsGxsDataAccess::requestGroupInfo() request type not recognised, type " << reqType << std::endl; return false; } generateToken(token); #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::requestGroupInfo() gets Token: " << token << std::endl; + RsErr() << "RsGxsDataAccess::requestGroupInfo() gets Token: " << token << std::endl; #endif setReq(req, token, ansType, opts); @@ -137,11 +136,10 @@ void RsGxsDataAccess::generateToken(uint32_t &token) } -bool RsGxsDataAccess::requestMsgInfo(uint32_t &token, uint32_t ansType, - const RsTokReqOptions &opts, const GxsMsgReq &msgIds) +bool RsGxsDataAccess::requestMsgInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const GxsMsgReq &msgIds) { - GxsRequest* req = NULL; + GxsRequest* req = nullptr; uint32_t reqType = opts.mReqType; // remove all empty grpId entries @@ -181,16 +179,15 @@ bool RsGxsDataAccess::requestMsgInfo(uint32_t &token, uint32_t ansType, } - if(req == NULL) + if(req == nullptr) { - std::cerr << "RsGxsDataAccess::requestMsgInfo() request type not recognised, type " - << reqType << std::endl; + RsErr() << "RsGxsDataAccess::requestMsgInfo() request type not recognised, type " << reqType << std::endl; return false; }else { generateToken(token); #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::requestMsgInfo() gets Token: " << token << std::endl; + RsErr() << "RsGxsDataAccess::requestMsgInfo() gets Token: " << token << std::endl; #endif } @@ -199,10 +196,9 @@ bool RsGxsDataAccess::requestMsgInfo(uint32_t &token, uint32_t ansType, return true; } -bool RsGxsDataAccess::requestMsgInfo(uint32_t &token, uint32_t ansType, - const RsTokReqOptions &opts, const std::list& grpIds) +bool RsGxsDataAccess::requestMsgInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const std::list& grpIds) { - GxsRequest* req = NULL; + GxsRequest* req = nullptr; uint32_t reqType = opts.mReqType; std::list::const_iterator lit = grpIds.begin(); @@ -235,16 +231,15 @@ bool RsGxsDataAccess::requestMsgInfo(uint32_t &token, uint32_t ansType, req = mir; } - if(req == NULL) + if(req == nullptr) { - std::cerr << "RsGxsDataAccess::requestMsgInfo() request type not recognised, type " - << reqType << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " request type not recognised, type " << reqType << std::endl; return false; }else { generateToken(token); #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::requestMsgInfo() gets Token: " << token << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " gets Token: " << token << std::endl; #endif } @@ -254,33 +249,40 @@ bool RsGxsDataAccess::requestMsgInfo(uint32_t &token, uint32_t ansType, } -void RsGxsDataAccess::requestServiceStatistic(uint32_t& token) +void RsGxsDataAccess::requestServiceStatistic(uint32_t& token,const RsTokReqOptions& opts) { ServiceStatisticRequest* req = new ServiceStatisticRequest(); generateToken(token); - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_SERVICE_STATS; + if(opts.mReqType != GXS_REQUEST_TYPE_SERVICE_STATS) + { + RsErr() << "Expected opts.mReqType to be GXS_REQUEST_TYPE_SERVICE_STATS requestServiceStatistic()" << std::endl; + return; + } + setReq(req, token, 0, opts); storeRequest(req); } -void RsGxsDataAccess::requestGroupStatistic(uint32_t& token, const RsGxsGroupId& grpId) +void RsGxsDataAccess::requestGroupStatistic(uint32_t& token, const RsGxsGroupId& grpId,const RsTokReqOptions& opts) { GroupStatisticRequest* req = new GroupStatisticRequest(); req->mGrpId = grpId; + if(opts.mReqType != GXS_REQUEST_TYPE_GROUP_STATS) + { + RsErr() << "Expected opts.mReqType to be GXS_REQUEST_TYPE_SERVICE_STATS requestServiceStatistic()" << std::endl; + return; + } + generateToken(token); - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_GROUP_STATS; - setReq(req, token, 0, opts); + setReq(req, token,0, opts); storeRequest(req); } -bool RsGxsDataAccess::requestMsgRelatedInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, - const std::vector &msgIds) +bool RsGxsDataAccess::requestMsgRelatedInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const std::vector &msgIds) { MsgRelatedInfoReq* req = new MsgRelatedInfoReq(); @@ -298,7 +300,7 @@ bool RsGxsDataAccess::requestMsgRelatedInfo(uint32_t &token, uint32_t ansType, c void RsGxsDataAccess::setReq(GxsRequest* req, uint32_t token, uint32_t ansType, const RsTokReqOptions& opts) const { req->token = token; - req->ansType = ansType; + req->clientAnswerType = ansType; req->Options = opts; return; } @@ -306,8 +308,18 @@ void RsGxsDataAccess::storeRequest(GxsRequest* req) { RS_STACK_MUTEX(mDataMutex); req->status = PENDING; - req->reqTime = time(NULL); - mRequests[req->token] = req; + req->reqTime = time(nullptr); + + mRequestQueue.insert(std::make_pair(req->token,req)); + mPublicToken[req->token] = PENDING; + +#ifdef DATA_DEBUG + RsErr() << "Stored request token=" << req->token << " priority = " << static_cast(req->Options.mPriority) << " Current request Queue is:" ; + for(auto it(mRequestQueue.begin());it!=mRequestQueue.end();++it) + RsErr() << it->first << " (p=" << static_cast(req->Options.mPriority) << ") "; + std::cerr << std::endl; + RsErr() << "Completed requests waiting for client: " << mCompletedRequests.size() << std::endl; +#endif } RsTokenService::GxsRequestStatus RsGxsDataAccess::requestStatus(uint32_t token) @@ -317,14 +329,6 @@ RsTokenService::GxsRequestStatus RsGxsDataAccess::requestStatus(uint32_t token) uint32_t anstype; rstime_t ts; - { - RS_STACK_MUTEX(mDataMutex); - - // first check public tokens - if(mPublicToken.find(token) != mPublicToken.end()) - return mPublicToken[token]; - } - if (!checkRequestStatus(token, status, reqtype, anstype, ts)) return RsTokenService::FAILED; @@ -335,7 +339,7 @@ bool RsGxsDataAccess::cancelRequest(const uint32_t& token) { RsStackMutex stack(mDataMutex); /****** LOCKED *****/ - GxsRequest* req = locked_retrieveRequest(token); + GxsRequest* req = locked_retrieveCompetedRequest(token); if (!req) { return false; @@ -348,58 +352,52 @@ bool RsGxsDataAccess::cancelRequest(const uint32_t& token) bool RsGxsDataAccess::clearRequest(const uint32_t& token) { - RsStackMutex stack(mDataMutex); /****** LOCKED *****/ + RS_STACK_MUTEX(mDataMutex); + return locked_clearRequest(token); +} - std::map::iterator it; +bool RsGxsDataAccess::locked_clearRequest(const uint32_t& token) +{ + auto it = mCompletedRequests.find(token); - it = mRequests.find(token); - if (it == mRequests.end()) - { - return false; - } + if(it == mCompletedRequests.end()) + return false; - delete it->second; - mRequests.erase(it); + delete it->second; + mCompletedRequests.erase(it); - return true; + auto it2 = mPublicToken.find(token); + if(it2 != mPublicToken.end()) + mPublicToken.erase(it2); + + return true; } bool RsGxsDataAccess::getGroupSummary(const uint32_t& token, std::list& groupInfo) { - RS_STACK_MUTEX(mDataMutex); - GxsRequest* req = locked_retrieveRequest(token); + GxsRequest* req = locked_retrieveCompetedRequest(token); - if(req == NULL) + if(req == nullptr) { - std::cerr << "RsGxsDataAccess::getGroupSummary() Unable to retrieve " - << "group summary" << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " Unable to retrieve group summary" << std::endl; return false; } - else if(req->status == COMPLETE) - { - GroupMetaReq* gmreq = dynamic_cast(req); - if(gmreq) - { - groupInfo = gmreq->mGroupMetaData; - gmreq->mGroupMetaData.clear(); - locked_updateRequestStatus(token, DONE); - } - else - { - std::cerr << "RsGxsDataAccess::getGroupSummary() Req found, failed" - << "cast" << std::endl; - return false; - } + GroupMetaReq* gmreq = dynamic_cast(req); + + if(gmreq) + { + groupInfo = gmreq->mGroupMetaData; + gmreq->mGroupMetaData.clear(); } else { - std::cerr << "RsGxsDataAccess::getGroupSummary() Req not ready" - << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " Req found, failed cast" << std::endl; return false; } + locked_clearRequest(token); return true; } @@ -408,44 +406,33 @@ bool RsGxsDataAccess::getGroupData(const uint32_t& token, std::list& { RS_STACK_MUTEX(mDataMutex); - GxsRequest* req = locked_retrieveRequest(token); + GxsRequest* req = locked_retrieveCompetedRequest(token); - if(req == NULL) + if(req == nullptr) { - std::cerr << "RsGxsDataAccess::getGroupData() Unable to retrieve group" - << "data" << std::endl; + RsErr() << "RsGxsDataAccess::getGroupData() Unable to retrieve group data" << std::endl; return false; } - else if(req->status == COMPLETE) + + GroupDataReq* gmreq = dynamic_cast(req); + GroupSerializedDataReq* gsreq = dynamic_cast(req); + + if(gsreq) { - GroupDataReq* gmreq = dynamic_cast(req); - GroupSerializedDataReq* gsreq = dynamic_cast(req); - - if(gsreq) - { - grpData.swap(gsreq->mGroupData); - gsreq->mGroupData.clear(); - - locked_updateRequestStatus(token, DONE); - } - else if(gmreq) - { - grpData.swap(gmreq->mGroupData); - gmreq->mGroupData.clear(); - locked_updateRequestStatus(token, DONE); - } - else - { - std::cerr << "RsGxsDataAccess::getGroupData() Req found, failed cast" - << " req->reqType: " << req->reqType << std::endl; - return false; - } + grpData.swap(gsreq->mGroupData); + gsreq->mGroupData.clear(); + } + else if(gmreq) + { + grpData.swap(gmreq->mGroupData); + gmreq->mGroupData.clear(); } else { - std::cerr << "RsGxsDataAccess::getGroupData() Req not ready" << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " Req found, failed cast req->reqType: " << req->reqType << std::endl; return false; } + locked_clearRequest(token); return true; } @@ -455,32 +442,29 @@ bool RsGxsDataAccess::getMsgData(const uint32_t& token, NxsMsgDataResult& msgDat RsStackMutex stack(mDataMutex); - GxsRequest* req = locked_retrieveRequest(token); + GxsRequest* req = locked_retrieveCompetedRequest(token); - if(req == NULL){ + if(req == nullptr) + { - std::cerr << "RsGxsDataAccess::getMsgData() Unable to retrieve group data" << std::endl; - return false; - }else if(req->status == COMPLETE){ - - MsgDataReq* mdreq = dynamic_cast(req); - - if(mdreq) - { - msgData.swap(mdreq->mMsgData); - mdreq->mMsgData.clear(); - locked_updateRequestStatus(token, DONE); - } - else - { - std::cerr << "RsGxsDataAccess::getMsgData() Req found, failed caste" << std::endl; - return false; - } - }else{ - std::cerr << "RsGxsDataAccess::getMsgData() Req not ready" << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " Unable to retrieve group data" << std::endl; return false; } + MsgDataReq* mdreq = dynamic_cast(req); + + if(mdreq) + { + msgData.swap(mdreq->mMsgData); + mdreq->mMsgData.clear(); + } + else + { + RsErr() << "RsGxsDataAccess::getMsgData() Req found, failed caste" << std::endl; + return false; + } + locked_clearRequest(token); + return true; } @@ -489,34 +473,30 @@ bool RsGxsDataAccess::getMsgRelatedData(const uint32_t &token, NxsMsgRelatedData RsStackMutex stack(mDataMutex); - GxsRequest* req = locked_retrieveRequest(token); + GxsRequest* req = locked_retrieveCompetedRequest(token); - if(req == NULL){ + if(req == nullptr) + { + RsErr() << __PRETTY_FUNCTION__ << " Unable to retrieve group data" << std::endl; + return false; + } + MsgRelatedInfoReq* mrireq = dynamic_cast(req); - std::cerr << "RsGxsDataAccess::getMsgRelatedData() Unable to retrieve group data" << std::endl; - return false; - }else if(req->status == COMPLETE){ + if(req->Options.mReqType != GXS_REQUEST_TYPE_MSG_RELATED_DATA) + return false; - MsgRelatedInfoReq* mrireq = dynamic_cast(req); + if(mrireq) + { + msgData.swap(mrireq->mMsgDataResult); + mrireq->mMsgDataResult.clear(); + } + else + { + RsErr() << __PRETTY_FUNCTION__ << " Req found, failed caste" << std::endl; + return false; + } - if(req->Options.mReqType != GXS_REQUEST_TYPE_MSG_RELATED_DATA) - return false; - - if(mrireq) - { - msgData.swap(mrireq->mMsgDataResult); - mrireq->mMsgDataResult.clear(); - locked_updateRequestStatus(token, DONE); - } - else - { - std::cerr << "RsGxsDataAccess::getMsgRelatedData() Req found, failed caste" << std::endl; - return false; - } - }else{ - std::cerr << "RsGxsDataAccess::getMsgRelatedData() Req not ready" << std::endl; - return false; - } + locked_clearRequest(token); return true; } @@ -526,144 +506,114 @@ bool RsGxsDataAccess::getMsgSummary(const uint32_t& token, GxsMsgMetaResult& msg RsStackMutex stack(mDataMutex); - GxsRequest* req = locked_retrieveRequest(token); + GxsRequest* req = locked_retrieveCompetedRequest(token); - if(req == NULL){ - - std::cerr << "RsGxsDataAccess::getMsgSummary() Unable to retrieve group data" << std::endl; - return false; - }else if(req->status == COMPLETE){ - - MsgMetaReq* mmreq = dynamic_cast(req); - - if(mmreq) - { - msgInfo.swap(mmreq->mMsgMetaData); - mmreq->mMsgMetaData.clear(); - locked_updateRequestStatus(token, DONE); - - } - else - { - std::cerr << "RsGxsDataAccess::getMsgSummary() Req found, failed caste" << std::endl; - return false; - } - }else{ - std::cerr << "RsGxsDataAccess::getMsgSummary() Req not ready" << std::endl; + if(req == nullptr) + { + RsErr() << __PRETTY_FUNCTION__ << " Unable to retrieve group data" << std::endl; return false; } + MsgMetaReq* mmreq = dynamic_cast(req); + if(mmreq) + { + msgInfo.swap(mmreq->mMsgMetaData); + mmreq->mMsgMetaData.clear(); + } + else + { + RsErr() << " Req found, failed caste" << std::endl; + return false; + } + locked_clearRequest(token); return true; } bool RsGxsDataAccess::getMsgRelatedSummary(const uint32_t &token, MsgRelatedMetaResult &msgMeta) { + RsStackMutex stack(mDataMutex); - RsStackMutex stack(mDataMutex); + GxsRequest* req = locked_retrieveCompetedRequest(token); - GxsRequest* req = locked_retrieveRequest(token); + if(req == nullptr) + { + RsErr() << __PRETTY_FUNCTION__ << " Unable to retrieve message summary" << std::endl; + return false; + } + if(req->Options.mReqType != GXS_REQUEST_TYPE_MSG_RELATED_META) + return false; + MsgRelatedInfoReq* mrireq = dynamic_cast(req); - - if(req == NULL){ - - std::cerr << "RsGxsDataAccess::getMsgRelatedSummary() Unable to retrieve message summary" << std::endl; - return false; - }else if(req->status == COMPLETE){ - - if(req->Options.mReqType != GXS_REQUEST_TYPE_MSG_RELATED_META) - return false; - - MsgRelatedInfoReq* mrireq = dynamic_cast(req); - - if(mrireq) - { - msgMeta.swap(mrireq->mMsgMetaResult); - mrireq->mMsgMetaResult.clear(); - locked_updateRequestStatus(token, DONE); - } - else - { - std::cerr << "RsGxsDataAccess::getMsgRelatedSummary() Req found, failed caste" << std::endl; - return false; - } - } - else - { - std::cerr << "RsGxsDataAccess::getMsgRelatedSummary() Req not ready" << std::endl; - return false; - } - - return true; + if(mrireq) + { + msgMeta.swap(mrireq->mMsgMetaResult); + mrireq->mMsgMetaResult.clear(); + } + else + { + RsErr() << __PRETTY_FUNCTION__ << " Req found, failed caste" << std::endl; + return false; + } + locked_clearRequest(token); + return true; } bool RsGxsDataAccess::getMsgRelatedList(const uint32_t &token, MsgRelatedIdResult &msgIds) { - RsStackMutex stack(mDataMutex); + RsStackMutex stack(mDataMutex); - GxsRequest* req = locked_retrieveRequest(token); + GxsRequest* req = locked_retrieveCompetedRequest(token); - if(req == NULL){ + if(req == nullptr) + { + RsErr() << __PRETTY_FUNCTION__ << " Unable to retrieve message data" << std::endl; + return false; + } + if(req->Options.mReqType != GXS_REQUEST_TYPE_MSG_RELATED_IDS) + return false; - std::cerr << "RsGxsDataAccess::getMsgRelatedList() Unable to retrieve message data" << std::endl; - return false; - }else if(req->status == COMPLETE){ + MsgRelatedInfoReq* mrireq = dynamic_cast(req); - if(req->Options.mReqType != GXS_REQUEST_TYPE_MSG_RELATED_IDS) - return false; - - MsgRelatedInfoReq* mrireq = dynamic_cast(req); - - if(mrireq) - { - msgIds.swap(mrireq->mMsgIdResult); - mrireq->mMsgIdResult.clear(); - locked_updateRequestStatus(token, DONE); - } - else{ - std::cerr << "RsGxsDataAccess::getMsgRelatedList() Req found, failed caste" << std::endl; - return false; - } - } - else - { - std::cerr << "RsGxsDataAccess::getMsgRelatedList() Req not ready" << std::endl; - return false; - } - - return true; + if(mrireq) + { + msgIds.swap(mrireq->mMsgIdResult); + mrireq->mMsgIdResult.clear(); + } + else + { + RsErr() << __PRETTY_FUNCTION__ << " Req found, failed caste" << std::endl; + return false; + } + locked_clearRequest(token); + return true; } -bool RsGxsDataAccess::getMsgList(const uint32_t& token, GxsMsgIdResult& msgIds) +bool RsGxsDataAccess::getMsgIdList(const uint32_t& token, GxsMsgIdResult& msgIds) { RsStackMutex stack(mDataMutex); - GxsRequest* req = locked_retrieveRequest(token); + GxsRequest* req = locked_retrieveCompetedRequest(token); - if(req == NULL){ - - std::cerr << "RsGxsDataAccess::getMsgList() Unable to retrieve msg Ids" << std::endl; - return false; - }else if(req->status == COMPLETE){ - - MsgIdReq* mireq = dynamic_cast(req); - - if(mireq) - { - msgIds.swap(mireq->mMsgIdResult); - mireq->mMsgIdResult.clear(); - locked_updateRequestStatus(token, DONE); - } - else{ - std::cerr << "RsGxsDataAccess::getMsgList() Req found, failed caste" << std::endl; - return false; - } - }else{ - std::cerr << "RsGxsDataAccess::getMsgList() Req not ready" << std::endl; + if(req == nullptr) + { + RsErr() << __PRETTY_FUNCTION__ << " Unable to retrieve msg Ids" << std::endl; return false; } + MsgIdReq* mireq = dynamic_cast(req); + if(mireq) + { + msgIds.swap(mireq->mMsgIdResult); + mireq->mMsgIdResult.clear(); + } + else + { + RsErr() << __PRETTY_FUNCTION__ << " Req found, failed cast" << std::endl; + return false; + } + locked_clearRequest(token); return true; } @@ -671,127 +621,135 @@ bool RsGxsDataAccess::getGroupList(const uint32_t& token, std::liststatus == COMPLETE){ - - GroupIdReq* gireq = dynamic_cast(req); - - if(gireq) - { - groupIds.swap(gireq->mGroupIdResult); - gireq->mGroupIdResult.clear(); - locked_updateRequestStatus(token, DONE); - - }else{ - std::cerr << "RsGxsDataAccess::getGroupList() Req found, failed caste" << std::endl; - return false; - } - }else{ - std::cerr << "RsGxsDataAccess::getGroupList() Req not ready" << std::endl; + if(req == nullptr) + { + RsErr() << __PRETTY_FUNCTION__ << " Unable to retrieve group Ids, Request does not exist" << std::endl; return false; } + GroupIdReq* gireq = dynamic_cast(req); + if(gireq) + { + groupIds.swap(gireq->mGroupIdResult); + gireq->mGroupIdResult.clear(); + } + else + { + RsErr() << __PRETTY_FUNCTION__ << " Req found, failed caste" << std::endl; + return false; + } + locked_clearRequest(token); return true; } -GxsRequest* RsGxsDataAccess::locked_retrieveRequest(const uint32_t& token) +bool RsGxsDataAccess::getGroupStatistic(const uint32_t &token, GxsGroupStatistic &grpStatistic) { + RsStackMutex stack(mDataMutex); - if(mRequests.find(token) == mRequests.end()) return NULL; + GxsRequest* req = locked_retrieveCompetedRequest(token); - GxsRequest* req = mRequests[token]; + if(req == nullptr) + { + RsErr() << "RsGxsDataAccess::getGroupStatistic() Unable to retrieve grp stats" << std::endl; + return false; + } + GroupStatisticRequest* gsreq = dynamic_cast(req); - return req; + if(gsreq) + grpStatistic = gsreq->mGroupStatistic; + else + { + RsErr() << __PRETTY_FUNCTION__ << " Req found, failed caste" << std::endl; + return false; + } + locked_clearRequest(token); + return true; +} + +bool RsGxsDataAccess::getServiceStatistic(const uint32_t &token, GxsServiceStatistic &servStatistic) +{ + RsStackMutex stack(mDataMutex); + + GxsRequest* req = locked_retrieveCompetedRequest(token); + + if(req == nullptr) + { + RsErr() << __PRETTY_FUNCTION__ << " Unable to retrieve service stats" << std::endl; + return false; + } + ServiceStatisticRequest* ssreq = dynamic_cast(req); + + if(ssreq) + servStatistic = ssreq->mServiceStatistic; + else + { + RsErr() << __PRETTY_FUNCTION__ << " Req found, failed caste" << std::endl; + return false; + } + locked_clearRequest(token); + return true; +} +GxsRequest* RsGxsDataAccess::locked_retrieveCompetedRequest(const uint32_t& token) +{ + auto it = mCompletedRequests.find(token) ; + + if(it == mCompletedRequests.end()) + return nullptr; + + return it->second; } #define MAX_REQUEST_AGE 120 // 2 minutes void RsGxsDataAccess::processRequests() { - std::list toClear; - rstime_t now = time(NULL); - std::map::iterator it; - - { - RsStackMutex stack(mDataMutex); /******* LOCKED *******/ - - // process status of the requests - for (it = mRequests.begin(); it != mRequests.end(); ++it) - { - GxsRequest* req = it->second; - - switch (req->status) - { - case PENDING: - // process request later - break; - case PARTIAL: - // should not happen - req->status = COMPLETE; - break; - case DONE: -#ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::processrequests() Clearing Done Request Token: " << req->token; - std::cerr << std::endl; -#endif - toClear.push_back(req->token); - break; - case CANCELLED: -#ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::processrequests() Clearing Cancelled Request Token: " << req->token; - std::cerr << std::endl; -#endif - toClear.push_back(req->token); - break; - default: - if (now - req->reqTime > MAX_REQUEST_AGE) - { -#ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::processrequests() Clearing Old Request Token: " << req->token; - std::cerr << std::endl; -#endif - toClear.push_back(req->token); - } - } - } - } // END OF MUTEX. - - // clear requests - std::list::iterator cit; - for (cit = toClear.begin(); cit != toClear.end(); ++cit) - { - clearRequest(*cit); - } - // process requests - while (true) + + while (!mRequestQueue.empty()) { - GxsRequest* req = NULL; + // Extract the first elements from the request queue. cleanup all other elements marked at terminated. + + GxsRequest* req = nullptr; { RsStackMutex stack(mDataMutex); /******* LOCKED *******/ + rstime_t now = time(nullptr); // this is ok while in the loop below - // get the first pending request - for (it = mRequests.begin(); it != mRequests.end(); ++it) - { - GxsRequest* reqCheck = it->second; - if (reqCheck->status == PENDING) - { - req = reqCheck; + while(!mRequestQueue.empty() && req == nullptr) + { + if(now > mRequestQueue.begin()->second->reqTime + MAX_REQUEST_AGE) + { + mRequestQueue.erase(mRequestQueue.begin()); + continue; + } + + switch( mRequestQueue.begin()->second->status ) + { + case PARTIAL: + RsErr() << "Found partial request in mRequestQueue. This is a bug." << std::endl; // fallthrough + case COMPLETE: + case DONE: + case FAILED: + case CANCELLED: +#ifdef DATA_DEBUG + RsDbg() << " request " << mRequestQueue.begin()->second->token << ": status = " << mRequestQueue.begin()->second->status << ": removing from the RequestQueue" << std::endl; +#endif + mRequestQueue.erase(mRequestQueue.begin()); + continue; + break; + case PENDING: + req = mRequestQueue.begin()->second; req->status = PARTIAL; - break; - } - } - } // END OF MUTEX. + mRequestQueue.erase(mRequestQueue.begin()); // remove it right away from the waiting queue. + break; + } - if (!req) { + } + } + + if (!req) break; - } GroupMetaReq* gmr; GroupDataReq* gdr; @@ -806,132 +764,85 @@ void RsGxsDataAccess::processRequests() ServiceStatisticRequest* ssr; #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::processRequests() Processing Token: " << req->token << " Status: " - << req->status << " ReqType: " << req->reqType << " Age: " - << now - req->reqTime << std::endl; + RsDbg() << "Processing request: " << req->token << " Status: " << req->status << " ReqType: " << req->reqType << " Age: " << time(nullptr) - req->reqTime << std::endl; #endif /* PROCESS REQUEST! */ bool ok = false; - if((gmr = dynamic_cast(req)) != NULL) + if((gmr = dynamic_cast(req)) != nullptr) { ok = getGroupSummary(gmr); } - else if((gdr = dynamic_cast(req)) != NULL) + else if((gdr = dynamic_cast(req)) != nullptr) { ok = getGroupData(gdr); } - else if((gir = dynamic_cast(req)) != NULL) + else if((gir = dynamic_cast(req)) != nullptr) { ok = getGroupList(gir); } - else if((mmr = dynamic_cast(req)) != NULL) + else if((mmr = dynamic_cast(req)) != nullptr) { ok = getMsgSummary(mmr); } - else if((mdr = dynamic_cast(req)) != NULL) + else if((mdr = dynamic_cast(req)) != nullptr) { ok = getMsgData(mdr); } - else if((mir = dynamic_cast(req)) != NULL) + else if((mir = dynamic_cast(req)) != nullptr) { - ok = getMsgList(mir); + ok = getMsgIdList(mir); } - else if((mri = dynamic_cast(req)) != NULL) + else if((mri = dynamic_cast(req)) != nullptr) { ok = getMsgRelatedInfo(mri); } - else if((gsr = dynamic_cast(req)) != NULL) + else if((gsr = dynamic_cast(req)) != nullptr) { ok = getGroupStatistic(gsr); } - else if((ssr = dynamic_cast(req)) != NULL) + else if((ssr = dynamic_cast(req)) != nullptr) { ok = getServiceStatistic(ssr); } - else if((grr = dynamic_cast(req)) != NULL) + else if((grr = dynamic_cast(req)) != nullptr) { ok = getGroupSerializedData(grr); } - else - { - std::cerr << "RsGxsDataAccess::processRequests() Failed to process request, token: " - << req->token << std::endl; - } + RsErr() << __PRETTY_FUNCTION__ << " Failed to process request, token: " << req->token << std::endl; + // We cannot easily remove the request here because the queue may have more elements now and mRequestQueue.begin() is not necessarily the same element. + // but we mark it as COMPLETE/FAILED so that it will be removed in the next loop. { RsStackMutex stack(mDataMutex); /******* LOCKED *******/ - if (req->status == PARTIAL) - { - req->status = ok ? COMPLETE : FAILED; - } - } // END OF MUTEX. - } -} -bool RsGxsDataAccess::getGroupStatistic(const uint32_t &token, GxsGroupStatistic &grpStatistic) -{ - RsStackMutex stack(mDataMutex); + if(ok) + { + // When the request is complete, we move it to the complete list, so that the caller can easily retrieve the request data - GxsRequest* req = locked_retrieveRequest(token); - - if(req == NULL){ - - std::cerr << "RsGxsDataAccess::getGroupStatistic() Unable to retrieve grp stats" << std::endl; - return false; - }else if(req->status == COMPLETE){ - - GroupStatisticRequest* gsreq = dynamic_cast(req); - - if(gsreq) - { - grpStatistic = gsreq->mGroupStatistic; - locked_updateRequestStatus(token, DONE); - } - else{ - std::cerr << "RsGxsDataAccess::getGroupStatistic() Req found, failed caste" << std::endl; - return false; +#ifdef DATA_DEBUG + RsDbg() << " Request completed successfully. Marking as COMPLETE." << std::endl; +#endif + req->status = COMPLETE ; + mCompletedRequests[req->token] = req; + mPublicToken[req->token] = COMPLETE; + } + else + { + req->status = FAILED; + mPublicToken[req->token] = FAILED; +#ifdef DATA_DEBUG + RsDbg() << " Request failed. Marking as FAILED." << std::endl; +#endif + } } - }else{ - std::cerr << "RsGxsDataAccess::getGroupStatistic() Req not ready" << std::endl; - return false; - } - return true; + } // END OF MUTEX. } -bool RsGxsDataAccess::getServiceStatistic(const uint32_t &token, GxsServiceStatistic &servStatistic) -{ - RsStackMutex stack(mDataMutex); - GxsRequest* req = locked_retrieveRequest(token); - - if(req == NULL){ - - std::cerr << "RsGxsDataAccess::getServiceStatistic() Unable to retrieve service stats" << std::endl; - return false; - }else if(req->status == COMPLETE){ - - ServiceStatisticRequest* ssreq = dynamic_cast(req); - - if(ssreq) - { - servStatistic = ssreq->mServiceStatistic; - locked_updateRequestStatus(token, DONE); - } - else{ - std::cerr << "RsGxsDataAccess::getServiceStatistic() Req found, failed caste" << std::endl; - return false; - } - }else{ - std::cerr << "RsGxsDataAccess::getServiceStatistic() Req not ready" << std::endl; - return false; - } - - return true; -} bool RsGxsDataAccess::getGroupSerializedData(GroupSerializedDataReq* req) { @@ -945,7 +856,7 @@ bool RsGxsDataAccess::getGroupSerializedData(GroupSerializedDataReq* req) for(std::list::iterator lit = grpIdsOut.begin();lit != grpIdsOut.end();++lit) - grpData[*lit] = NULL; + grpData[*lit] = nullptr; bool ok = mDataStore->retrieveNxsGrps(grpData, true, true); req->mGroupData.clear(); @@ -972,7 +883,7 @@ bool RsGxsDataAccess::getGroupData(GroupDataReq* req) for(; lit != lit_end; ++lit) { - grpData[*lit] = NULL; + grpData[*lit] = nullptr; } bool ok = mDataStore->retrieveNxsGrps(grpData, true, true); @@ -998,7 +909,7 @@ bool RsGxsDataAccess::getGroupSummary(GroupMetaReq* req) std::list::const_iterator lit = grpIdsOut.begin(); for(; lit != grpIdsOut.end(); ++lit) - grpMeta[*lit] = NULL; + grpMeta[*lit] = nullptr; mDataStore->retrieveGxsGrpMetaData(grpMeta); @@ -1037,7 +948,7 @@ bool RsGxsDataAccess::getMsgData(MsgDataReq* req) const RsTokReqOptions& opts(req->Options); // filter based on options - getMsgList(req->mMsgIds, opts, msgIdOut); + getMsgIdList(req->mMsgIds, opts, msgIdOut); // If the list is empty because of filtering do not retrieve from DB if((opts.mMsgFlagMask || opts.mStatusMask) && msgIdOut.empty()) @@ -1055,24 +966,21 @@ bool RsGxsDataAccess::getMsgSummary(MsgMetaReq* req) const RsTokReqOptions& opts(req->Options); // filter based on options - getMsgList(req->mMsgIds, opts, msgIdOut); + getMsgMetaDataList(req->mMsgIds, opts, req->mMsgMetaData); - // If the list is empty because of filtering do not retrieve from DB - if((opts.mMsgFlagMask || opts.mStatusMask) && msgIdOut.empty()) - return true; - - mDataStore->retrieveGxsMsgMetaData(msgIdOut, req->mMsgMetaData); +// // If the list is empty because of filtering do not retrieve from DB +// if((opts.mMsgFlagMask || opts.mStatusMask) && msgIdOut.empty()) +// return true; +// +// mDataStore->retrieveGxsMsgMetaData(msgIdOut, req->mMsgMetaData); return true; } - -bool RsGxsDataAccess::getMsgList( - const GxsMsgReq& msgIds, const RsTokReqOptions& opts, - GxsMsgReq& msgIdsOut ) +bool RsGxsDataAccess::getMsgMetaDataList( const GxsMsgReq& msgIds, const RsTokReqOptions& opts, GxsMsgMetaResult& result ) { - GxsMsgMetaResult result; - + // First get all message metas, then filter out the ones we want to keep. + result.clear(); mDataStore->retrieveGxsMsgMetaData(msgIds, result); /* CASEs this handles. @@ -1081,8 +989,7 @@ bool RsGxsDataAccess::getMsgList( * */ #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgList()"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgList()" << std::endl; #endif bool onlyOrigMsgs = false; @@ -1093,16 +1000,14 @@ bool RsGxsDataAccess::getMsgList( if (opts.mOptions & RS_TOKREQOPT_MSG_ORIGMSG) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgList() MSG_ORIGMSG"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgList() MSG_ORIGMSG" << std::endl; #endif onlyOrigMsgs = true; } else if (opts.mOptions & RS_TOKREQOPT_MSG_LATEST) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgList() MSG_LATEST"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgList() MSG_LATEST" << std::endl; #endif onlyLatestMsgs = true; } @@ -1110,130 +1015,176 @@ bool RsGxsDataAccess::getMsgList( if (opts.mOptions & RS_TOKREQOPT_MSG_THREAD) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgList() MSG_THREAD"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgList() MSG_THREAD" << std::endl; #endif onlyThreadHeadMsgs = true; } GxsMsgMetaResult::iterator meta_it; - MsgMetaFilter metaFilter; for(meta_it = result.begin(); meta_it != result.end(); ++meta_it) { const RsGxsGroupId& grpId = meta_it->first; - metaFilter[grpId] = std::map(); + //auto& filter( metaFilter[grpId] ); // does the initialization of metaFilter[grpId] and avoids further O(log(n)) calls - const std::vector& metaV = meta_it->second; - if (onlyLatestMsgs) // THIS ONE IS HARD -> LOTS OF COMP. + std::vector& metaV = meta_it->second; + + if (onlyLatestMsgs) // if we only consider latest messages, we need to first filter out messages with "children" { - std::vector::const_iterator vit = metaV.begin(); + // The strategy is the following: for each msg we only know its direct ancestor. So we build a map to be able to find for a given message + // which messages derive from it. + // Then when this map is fuly build, we follow this map and every message that has no direct follow up will be kept. + // Because msgs are stored in a std::vector we build a map to convert each vector to its position in metaV. + std::vector keep(metaV.size(),true); // this vector will tell wether we keep or not a given Meta + std::map index_in_metaV; // holds the index of each group Id in metaV + + for(uint32_t i=0;imMsgId] = i; + + // Now loop once over message Metas and see if they have a parent. If yes, then mark the parent to be discarded. + + for(uint32_t i=0;imParentId.isNull() && metaV[i]->mParentId != metaV[i]->mMsgId) // this one is a follow up + { + auto it = index_in_metaV.find(metaV[i]->mParentId); + + if(it != index_in_metaV.end()) + keep[it->second] = false; + else + std::cerr << "Found a msg that has a parent that is not locally known. Not an error anyway." << std::endl; + + } + + // Finally we just discard the messages for which the keep flag has been set to false. + + for(uint32_t i=0;i TS. std::map > origMsgTs; - std::map >::iterator oit; - for(; vit != metaV.end(); ++vit) + for(uint32_t i=0;imParentId.isNull())) { - if (!(msgMeta->mParentId.isNull())) + delete msgMeta; + metaV[i] = nullptr; + continue; + } + + auto oit = origMsgTs.find(msgMeta->mOrigMsgId); + + bool addMsg = false; + if (oit != origMsgTs.end()) + { + if(oit->second.second > msgMeta->mPublishTs) { - continue; +#ifdef DATA_DEBUG + std::cerr << "RsGxsDataAccess::getMsgList() Found New OrigMsgId: "; + std::cerr << msgMeta->mOrigMsgId; + std::cerr << " MsgId: " << msgMeta->mMsgId; + std::cerr << " TS: " << msgMeta->mPublishTs; + std::cerr << std::endl; +#endif + origMsgTs[msgMeta->mOrigMsgId] = std::make_pair(msgMeta->mMsgId, msgMeta->mPublishTs); // add as latest. (overwriting if necessary) } } - - - oit = origMsgTs.find(msgMeta->mOrigMsgId); - bool addMsg = false; - if (oit == origMsgTs.end()) + else { -#ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgList() Found New OrigMsgId: "; - std::cerr << msgMeta->mOrigMsgId; - std::cerr << " MsgId: " << msgMeta->mMsgId; - std::cerr << " TS: " << msgMeta->mPublishTs; - std::cerr << std::endl; -#endif - - addMsg = true; - } - // check timestamps. - else if (oit->second.second < msgMeta->mPublishTs) - { -#ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgList() Found Later Msg. OrigMsgId: "; - std::cerr << msgMeta->mOrigMsgId; - std::cerr << " MsgId: " << msgMeta->mMsgId; - std::cerr << " TS: " << msgMeta->mPublishTs; -#endif - - addMsg = true; + delete msgMeta; + metaV[i] = nullptr; + continue; } - if (addMsg) - { - // add as latest. (overwriting if necessary) - origMsgTs[msgMeta->mOrigMsgId] = std::make_pair(msgMeta->mMsgId, msgMeta->mPublishTs); - metaFilter[grpId].insert(std::make_pair(msgMeta->mMsgId, msgMeta)); - } + } // Add the discovered Latest Msgs. - for(oit = origMsgTs.begin(); oit != origMsgTs.end(); ++oit) + for(auto oit = origMsgTs.begin(); oit != origMsgTs.end(); ++oit) { - msgIdsOut[grpId].insert(oit->second.first); + msgIdsOut[grpId].insert(oit->second.first); } +#endif - } - else // ALL OTHER CASES. - { - std::vector::const_iterator vit = metaV.begin(); + for(uint32_t i=0;imParentId.isNull()) + { + delete msgMeta; + metaV[i] = nullptr; + continue; + } - /* if we are grabbing thread Head... then parentId == empty. */ - if (onlyThreadHeadMsgs) - { - if (!(msgMeta->mParentId.isNull())) - { - continue; - } - } - - - if (onlyOrigMsgs) - { - if (msgMeta->mMsgId == msgMeta->mOrigMsgId) - { - add = true; - } - } - else - { - add = true; - } - - if (add) - { - msgIdsOut[grpId].insert(msgMeta->mMsgId); - metaFilter[grpId].insert(std::make_pair(msgMeta->mMsgId, msgMeta)); - } - - } - } + if (onlyOrigMsgs && !msgMeta->mOrigMsgId.isNull() && msgMeta->mMsgId != msgMeta->mOrigMsgId) + { + delete msgMeta; + metaV[i] = nullptr; + continue; + } + } } - filterMsgList(msgIdsOut, opts, metaFilter); + // collapse results while keeping the order, eliminating empty slots - metaFilter.clear(); + for(auto it(result.begin());it!=result.end();++it) + { + uint32_t j=0; // j is the end of the cleaned-up tab, at the first available place + + for(uint32_t i=0;isecond.size();++i) // i is the index in the tab possibly containing nullptr's + if(it->second[i] != nullptr) + { + it->second[j] = it->second[i]; // move the pointer to the first available place + ++j; + } + + it->second.resize(j); // normally all pointers have been moved forward so there is nothing to delete here. + } + + // filterMsgIdList(msgIdsOut, opts, metaFilter); // this call is absurd: we already have in metaFilter the content we want. + + //metaFilter.clear(); + + // delete meta data + //cleanseMsgMetaMap(result); + + return true; +} + +bool RsGxsDataAccess::getMsgIdList( const GxsMsgReq& msgIds, const RsTokReqOptions& opts, GxsMsgReq& msgIdsOut ) +{ + GxsMsgMetaResult result; + + getMsgMetaDataList( msgIds, opts, result ); + + // extract MessageIds + + msgIdsOut.clear(); + + for(auto it(result.begin());it!=result.end();++it) + { + auto& id_set(msgIdsOut[it->first]); + + for(uint32_t i=0;isecond.size();++i) + id_set.insert(it->second[i]->mMsgId); + } // delete meta data cleanseMsgMetaMap(result); @@ -1248,8 +1199,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) * 1) No Flags => return nothing */ #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgRelatedList()"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgRelatedList()" << std::endl; #endif const RsTokReqOptions& opts = req->Options; @@ -1262,16 +1212,14 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) if (opts.mOptions & RS_TOKREQOPT_MSG_LATEST) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgRelatedList() MSG_LATEST"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgRelatedList() MSG_LATEST" << std::endl; #endif onlyLatestMsgs = true; } else if (opts.mOptions & RS_TOKREQOPT_MSG_VERSIONS) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgRelatedList() MSG_VERSIONS"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgRelatedList() MSG_VERSIONS" << std::endl; #endif onlyAllVersions = true; } @@ -1279,8 +1227,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) if (opts.mOptions & RS_TOKREQOPT_MSG_PARENT) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgRelatedList() MSG_PARENTS"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgRelatedList() MSG_PARENTS" << std::endl; #endif onlyChildMsgs = true; } @@ -1288,8 +1235,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) if (opts.mOptions & RS_TOKREQOPT_MSG_THREAD) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgRelatedList() MSG_THREAD"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgRelatedList() MSG_THREAD" << std::endl; #endif onlyThreadMsgs = true; } @@ -1297,8 +1243,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) if (onlyAllVersions && onlyChildMsgs) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgRelatedList() ERROR Incompatible FLAGS (VERSIONS & PARENT)"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgRelatedList() ERROR Incompatible FLAGS (VERSIONS & PARENT)" << std::endl; #endif return false; @@ -1307,8 +1252,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) if (onlyAllVersions && onlyThreadMsgs) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgRelatedList() ERROR Incompatible FLAGS (VERSIONS & THREAD)"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgRelatedList() ERROR Incompatible FLAGS (VERSIONS & THREAD)" << std::endl; #endif return false; @@ -1317,8 +1261,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) if ((!onlyLatestMsgs) && onlyChildMsgs) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgRelatedList() ERROR Incompatible FLAGS (!LATEST & PARENT)"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgRelatedList() ERROR Incompatible FLAGS (!LATEST & PARENT)" << std::endl; #endif return false; @@ -1327,8 +1270,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) if ((!onlyLatestMsgs) && onlyThreadMsgs) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgRelatedList() ERROR Incompatible FLAGS (!LATEST & THREAD)"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgRelatedList() ERROR Incompatible FLAGS (!LATEST & THREAD)" << std::endl; #endif return false; @@ -1337,8 +1279,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) if (onlyChildMsgs && onlyThreadMsgs) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgRelatedList() ERROR Incompatible FLAGS (PARENT & THREAD)"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgRelatedList() ERROR Incompatible FLAGS (PARENT & THREAD)" << std::endl; #endif return false; @@ -1349,8 +1290,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) if ((!onlyLatestMsgs) && (!onlyAllVersions) && (!onlyChildMsgs) && (!onlyThreadMsgs)) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgRelatedList() FALLBACK -> NO FLAGS -> SIMPLY RETURN nothing"; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgRelatedList() FALLBACK -> NO FLAGS -> SIMPLY RETURN nothing" << std::endl; #endif return true; @@ -1379,7 +1319,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) std::set outMsgIds; - RsGxsMsgMetaData* origMeta = NULL; + RsGxsMsgMetaData* origMeta = nullptr; for(vit_meta = metaV.begin(); vit_meta != metaV.end(); ++vit_meta) { RsGxsMsgMetaData* meta = *vit_meta; @@ -1394,7 +1334,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) if(!origMeta) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgRelatedInfo(): Cannot find meta of msgId (to relate to)!" + RsDbg() << "RsGxsDataAccess::getMsgRelatedInfo(): Cannot find meta of msgId (to relate to)!" << std::endl; #endif cleanseMsgMetaMap(result); @@ -1439,11 +1379,11 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) if (oit == origMsgTs.end()) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgRelatedList() Found New OrigMsgId: "; - std::cerr << meta->mOrigMsgId; - std::cerr << " MsgId: " << meta->mMsgId; - std::cerr << " TS: " << meta->mPublishTs; - std::cerr << std::endl; + RsDbg() << "RsGxsDataAccess::getMsgRelatedList() Found New OrigMsgId: " + << meta->mOrigMsgId + << " MsgId: " << meta->mMsgId + << " TS: " << meta->mPublishTs + << std::endl; #endif addMsg = true; @@ -1452,10 +1392,11 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) else if (oit->second.second < meta->mPublishTs) { #ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::getMsgRelatedList() Found Later Msg. OrigMsgId: "; - std::cerr << meta->mOrigMsgId; - std::cerr << " MsgId: " << meta->mMsgId; - std::cerr << " TS: " << meta->mPublishTs; + RsDbg() << "RsGxsDataAccess::getMsgRelatedList() Found Later Msg. OrigMsgId: " + << meta->mOrigMsgId + << " MsgId: " << meta->mMsgId + << " TS: " << meta->mPublishTs + << std::endl; #endif addMsg = true; @@ -1481,7 +1422,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) /* first guess is potentially better than Orig (can't be worse!) */ rstime_t latestTs = 0; RsGxsMessageId latestMsgId; - RsGxsMsgMetaData* latestMeta=NULL; + RsGxsMsgMetaData* latestMeta=nullptr; for(vit_meta = metaV.begin(); vit_meta != metaV.end(); ++vit_meta) { @@ -1517,7 +1458,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) GxsMsgIdResult filteredOutMsgIds; filteredOutMsgIds[grpId] = outMsgIds; - filterMsgList(filteredOutMsgIds, opts, filterMap); + filterMsgIdList(filteredOutMsgIds, opts, filterMap); if(!filteredOutMsgIds[grpId].empty()) { @@ -1555,7 +1496,7 @@ bool RsGxsDataAccess::getGroupStatistic(GroupStatisticRequest *req) GxsMsgMetaResult metaResult; mDataStore->retrieveGxsMsgMetaData(metaReq, metaResult); - std::vector& msgMetaV = metaResult[req->mGrpId]; + const std::vector& msgMetaV = metaResult[req->mGrpId]; req->mGroupStatistic.mGrpId = req->mGrpId; req->mGroupStatistic.mNumMsgs = msgMetaV.size(); @@ -1647,7 +1588,7 @@ bool RsGxsDataAccess::getServiceStatistic(ServiceStatisticRequest *req) return true; } -bool RsGxsDataAccess::getMsgList(MsgIdReq* req) +bool RsGxsDataAccess::getMsgIdList(MsgIdReq* req) { GxsMsgMetaResult result; @@ -1675,7 +1616,7 @@ bool RsGxsDataAccess::getMsgList(MsgIdReq* req) GxsMsgReq msgIdOut; // filter based on options - getMsgList(req->mMsgIdResult, req->Options, msgIdOut); + getMsgIdList(req->mMsgIdResult, req->Options, msgIdOut); req->mMsgIdResult = msgIdOut; return true; @@ -1700,12 +1641,9 @@ void RsGxsDataAccess::cleanseMsgMetaMap(GxsMsgMetaResult& result) return; } -void RsGxsDataAccess::filterMsgList( - GxsMsgIdResult& resultsMap, const RsTokReqOptions& opts, - const MsgMetaFilter& msgMetas ) const +void RsGxsDataAccess::filterMsgIdList( GxsMsgIdResult& resultsMap, const RsTokReqOptions& opts, const MsgMetaFilter& msgMetas ) const { - for( GxsMsgIdResult::iterator grpIt = resultsMap.begin(); - grpIt != resultsMap.end(); ++grpIt ) + for( GxsMsgIdResult::iterator grpIt = resultsMap.begin(); grpIt != resultsMap.end(); ++grpIt ) { const RsGxsGroupId& groupId(grpIt->first); std::set& msgsIdSet(grpIt->second); @@ -1713,13 +1651,12 @@ void RsGxsDataAccess::filterMsgList( MsgMetaFilter::const_iterator cit = msgMetas.find(groupId); if(cit == msgMetas.end()) continue; #ifdef DATA_DEBUG - std::cerr << __PRETTY_FUNCTION__ << " " << msgsIdSet.size() + RsDbg() << __PRETTY_FUNCTION__ << " " << msgsIdSet.size() << " for group: " << groupId << " before filtering" << std::endl; #endif - for( std::set::iterator msgIdIt = msgsIdSet.begin(); - msgIdIt != msgsIdSet.end(); ) + for( std::set::iterator msgIdIt = msgsIdSet.begin(); msgIdIt != msgsIdSet.end(); ) { const RsGxsMessageId& msgId(*msgIdIt); const std::map& msgsMetaMap = @@ -1733,12 +1670,14 @@ void RsGxsDataAccess::filterMsgList( keep = checkMsgFilter(opts, msgsMetaMapIt->second); } - if(keep) ++msgIdIt; - else msgIdIt = msgsIdSet.erase(msgIdIt); + if(keep) + ++msgIdIt; + else + msgIdIt = msgsIdSet.erase(msgIdIt); } #ifdef DATA_DEBUG - std::cerr << __PRETTY_FUNCTION__ << " " << msgsIdSet.size() + RsDbg() << __PRETTY_FUNCTION__ << " " << msgsIdSet.size() << " for group: " << groupId << " after filtering" << std::endl; #endif @@ -1772,23 +1711,44 @@ void RsGxsDataAccess::filterGrpList(std::list &grpIds, const RsTok } -bool RsGxsDataAccess::checkRequestStatus( - uint32_t token, GxsRequestStatus& status, uint32_t& reqtype, - uint32_t& anstype, rstime_t& ts ) +bool RsGxsDataAccess::checkRequestStatus( uint32_t token, GxsRequestStatus& status, uint32_t& reqtype, uint32_t& anstype, rstime_t& ts ) { RS_STACK_MUTEX(mDataMutex); - GxsRequest* req = locked_retrieveRequest(token); + GxsRequest* req = locked_retrieveCompetedRequest(token); - if (req == NULL || req->status == CANCELLED) - return false; +#ifdef DATA_DEBUG + RsDbg() << "CheckRequestStatus: token=" << token ; +#endif - anstype = req->ansType; - reqtype = req->reqType; - status = req->status; - ts = req->reqTime; + if(req != nullptr) + { + anstype = req->clientAnswerType; + reqtype = req->reqType; + status = COMPLETE; + ts = req->reqTime; +#ifdef DATA_DEBUG + RsDbg() << __PRETTY_FUNCTION__ << " Returning status = COMPLETE" << std::endl; +#endif + return true; + } - return true; + auto it = mPublicToken.find(token); + + if(it != mPublicToken.end()) + { + status = it->second; +#ifdef DATA_DEBUG + RsDbg() << __PRETTY_FUNCTION__ << " Returning status = " << status << std::endl; +#endif + return true; + } + + status = FAILED; +#ifdef DATA_DEBUG + RsDbg() << " Token not found. Returning FAILED" << std::endl; +#endif + return false; } bool RsGxsDataAccess::addGroupData(RsNxsGrp* grp) { @@ -1815,7 +1775,7 @@ bool RsGxsDataAccess::getGroupData(const RsGxsGroupId& grpId, RsNxsGrp *& grp_da std::map grps ; - grps[grpId] = NULL ; + grps[grpId] = nullptr ; if(mDataStore->retrieveNxsGrps(grps, false, true)) // the false here is very important: it removes the private key parts. { @@ -1842,18 +1802,16 @@ void RsGxsDataAccess::tokenList(std::list& tokens) RsStackMutex stack(mDataMutex); - std::map::iterator mit = mRequests.begin(); + for(auto& it:mRequestQueue) + tokens.push_back(it.second->token); - for(; mit != mRequests.end(); ++mit) - { - tokens.push_back(mit->first); - } + for(auto& it:mCompletedRequests) + tokens.push_back(it.first); } -bool RsGxsDataAccess::locked_updateRequestStatus( - uint32_t token, RsTokenService::GxsRequestStatus status ) +bool RsGxsDataAccess::locked_updateRequestStatus( uint32_t token, RsTokenService::GxsRequestStatus status ) { - GxsRequest* req = locked_retrieveRequest(token); + GxsRequest* req = locked_retrieveCompetedRequest(token); if(req) req->status = status; else return false; @@ -1868,7 +1826,7 @@ uint32_t RsGxsDataAccess::generatePublicToken() { RS_STACK_MUTEX(mDataMutex); - mPublicToken[token] = RsTokenService::PENDING; + mPublicToken[token] = PENDING ; } return token; @@ -1876,15 +1834,19 @@ uint32_t RsGxsDataAccess::generatePublicToken() -bool RsGxsDataAccess::updatePublicRequestStatus( - uint32_t token, RsTokenService::GxsRequestStatus status ) +bool RsGxsDataAccess::updatePublicRequestStatus( uint32_t token, RsTokenService::GxsRequestStatus status ) { RS_STACK_MUTEX(mDataMutex); - std::map::iterator mit = - mPublicToken.find(token); - if(mit != mPublicToken.end()) mit->second = status; - else return false; - return true; + + auto mit = mPublicToken.find(token); + + if(mit != mPublicToken.end()) + { + mit->second = status; + return true; + } + else + return false; } @@ -1892,11 +1854,14 @@ bool RsGxsDataAccess::updatePublicRequestStatus( bool RsGxsDataAccess::disposeOfPublicToken(uint32_t token) { RS_STACK_MUTEX(mDataMutex); - std::map::iterator mit = - mPublicToken.find(token); - if(mit != mPublicToken.end()) mPublicToken.erase(mit); - else return false; - return true; + auto mit = mPublicToken.find(token); + if(mit != mPublicToken.end()) + { + mPublicToken.erase(mit); + return true; + } + else + return false; } bool RsGxsDataAccess::checkGrpFilter(const RsTokReqOptions &opts, const RsGxsGrpMetaData *meta) const @@ -1929,7 +1894,7 @@ bool RsGxsDataAccess::checkMsgFilter( (opts.mStatusMask & meta->mMsgStatus) ) { #ifdef DATA_DEBUG - std::cerr << __PRETTY_FUNCTION__ + RsDbg() << __PRETTY_FUNCTION__ << " Continue checking Msg as StatusMatches: " << " Mask: " << opts.mStatusMask << " StatusFilter: " << opts.mStatusFilter @@ -1940,7 +1905,7 @@ bool RsGxsDataAccess::checkMsgFilter( else { #ifdef DATA_DEBUG - std::cerr << __PRETTY_FUNCTION__ + RsDbg() << __PRETTY_FUNCTION__ << " Dropping Msg due to !StatusMatch " << " Mask: " << opts.mStatusMask << " StatusFilter: " << opts.mStatusFilter @@ -1954,7 +1919,7 @@ bool RsGxsDataAccess::checkMsgFilter( else { #ifdef DATA_DEBUG - std::cerr << __PRETTY_FUNCTION__ + RsDbg() << __PRETTY_FUNCTION__ << " Status check not requested" << " mStatusMask: " << opts.mStatusMask << " MsgId: " << meta->mMsgId << std::endl; @@ -1968,7 +1933,7 @@ bool RsGxsDataAccess::checkMsgFilter( (opts.mMsgFlagMask & meta->mMsgFlags) ) { #ifdef DATA_DEBUG - std::cerr << __PRETTY_FUNCTION__ + RsDbg() << __PRETTY_FUNCTION__ << " Accepting Msg as FlagMatches: " << " Mask: " << opts.mMsgFlagMask << " FlagFilter: " << opts.mMsgFlagFilter @@ -1979,7 +1944,7 @@ bool RsGxsDataAccess::checkMsgFilter( else { #ifdef DATA_DEBUG - std::cerr << __PRETTY_FUNCTION__ + RsDbg() << __PRETTY_FUNCTION__ << " Dropping Msg due to !FlagMatch " << " Mask: " << opts.mMsgFlagMask << " FlagFilter: " << opts.mMsgFlagFilter @@ -1993,7 +1958,7 @@ bool RsGxsDataAccess::checkMsgFilter( else { #ifdef DATA_DEBUG - std::cerr << __PRETTY_FUNCTION__ + RsDbg() << __PRETTY_FUNCTION__ << " Flags check not requested" << " mMsgFlagMask: " << opts.mMsgFlagMask << " MsgId: " << meta->mMsgId << std::endl; diff --git a/libretroshare/src/gxs/rsgxsdataaccess.h b/libretroshare/src/gxs/rsgxsdataaccess.h index c5bfdf084..21cb89b24 100644 --- a/libretroshare/src/gxs/rsgxsdataaccess.h +++ b/libretroshare/src/gxs/rsgxsdataaccess.h @@ -22,6 +22,7 @@ #ifndef RSGXSDATAACCESS_H #define RSGXSDATAACCESS_H +#include #include "retroshare/rstokenservice.h" #include "rsgxsrequesttypes.h" #include "rsgds.h" @@ -30,6 +31,8 @@ typedef std::map< RsGxsGroupId, std::map > MsgMetaFilter; typedef std::map< RsGxsGroupId, RsGxsGrpMetaData* > GrpMetaFilter; +bool operator<(const std::pair& p1,const std::pair& p2); + class RsGxsDataAccess : public RsTokenService { public: @@ -56,7 +59,7 @@ public: * @param groupIds group id to request info for * @return */ - bool requestGroupInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const std::list &groupIds); + bool requestGroupInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const std::list &groupIds) override; /*! * Use this to request all group related info @@ -65,7 +68,7 @@ public: * @param opts Additional option that affect outcome of request. Please see specific services, for valid values * @return */ - bool requestGroupInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts); + bool requestGroupInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts) override; /*! * Use this to get msg information (id, meta, or data), store token value to poll for request completion @@ -75,7 +78,7 @@ public: * @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 */ - bool requestMsgInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const GxsMsgReq& msgIds); + bool requestMsgInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const GxsMsgReq& msgIds) override; /*! * Use this to get message information (id, meta, or data), store token value to poll for request completion @@ -86,7 +89,7 @@ public: * all messages for all groups are retrieved * @return true if request successful false otherwise */ - bool requestMsgInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const std::list& grpIds); + bool requestMsgInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const std::list& grpIds) override; /*! * For requesting msgs related to a given msg id within a group @@ -96,7 +99,7 @@ public: * @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 */ - bool requestMsgRelatedInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const std::vector &msgIds); + bool requestMsgRelatedInfo(uint32_t &token, uint32_t ansType, const RsTokReqOptions &opts, const std::vector &msgIds) override; /*! * This request statistics on amount of data held @@ -107,19 +110,20 @@ public: * total size of messages * total size of groups * @param token + * @param opts Additional option that affect outcome of request. Please see specific services, for valid values */ - void requestServiceStatistic(uint32_t& token); + void requestServiceStatistic(uint32_t& token, const RsTokReqOptions &opts) override; /*! * To request statistic on a group * @param token set to value to be redeemed to get statistic * @param grpId the id of the group + * @param opts Additional option that affect outcome of request. Please see specific services, for valid values */ - void requestGroupStatistic(uint32_t& token, const RsGxsGroupId& grpId); - + void requestGroupStatistic(uint32_t& token, const RsGxsGroupId& grpId, const RsTokReqOptions &opts) override; /* Poll */ - GxsRequestStatus requestStatus(const uint32_t token); + GxsRequestStatus requestStatus(uint32_t token); /* Cancel Request */ bool cancelRequest(const uint32_t &token); @@ -200,7 +204,8 @@ public: * @param token request token to be redeemed * @param msgIds */ - bool getMsgList(const uint32_t &token, GxsMsgIdResult &msgIds); + bool getMsgIdList(const uint32_t &token, GxsMsgIdResult &msgIds); + /*! * Retrieve msg list for a given token for message related info @@ -271,7 +276,7 @@ private: * @param token the value of the token for the request object handle wanted * @return the request associated to this token */ - GxsRequest* locked_retrieveRequest(const uint32_t& token); + GxsRequest* locked_retrieveCompetedRequest(const uint32_t& token); /*! * Add a gxs request to queue @@ -378,8 +383,18 @@ private: * @param req * @return false if unsuccessful, true otherwise */ - bool getMsgList(MsgIdReq* req); + bool getMsgIdList(MsgIdReq* req); + /*! + * Attempts to retrieve msg Meta list from data store + * Computationally/CPU-Bandwidth expensive + * + * @param msgIds List of message Ids for the Message Metas to retrieve + * @param opts GxsRequest options + * @param result Map of Meta information for messages + * + */ + bool getMsgMetaDataList( const GxsMsgReq& msgIds, const RsTokReqOptions& opts, GxsMsgMetaResult& result ); /*! * Attempts to retrieve group meta data from data store @@ -445,7 +460,7 @@ private: * @param opts the request options set by user * @param meta The accompanying meta information for msg, ids */ - void filterMsgList(GxsMsgIdResult& msgIds, const RsTokReqOptions& opts, const MsgMetaFilter& meta) const; + void filterMsgIdList(GxsMsgIdResult& msgIds, const RsTokReqOptions& opts, const MsgMetaFilter& meta) const; /*! * This filter msgs based of options supplied (at the moment just status masks) @@ -482,9 +497,10 @@ private: * @param opts the options used to parameterise the id filter * @param msgIdsOut the left overs ids after filter is applied to msgIds */ - bool getMsgList(const GxsMsgReq& msgIds, const RsTokReqOptions& opts, GxsMsgReq& msgIdsOut); + bool getMsgIdList(const GxsMsgReq& msgIds, const RsTokReqOptions& opts, GxsMsgReq& msgIdsOut); private: + bool locked_clearRequest(const uint32_t &token); RsGeneralDataService* mDataStore; @@ -492,10 +508,9 @@ private: uint32_t mNextToken; std::map mPublicToken; - std::map mRequests; - - + std::set > mRequestQueue; + std::map mCompletedRequests; }; #endif // RSGXSDATAACCESS_H diff --git a/libretroshare/src/gxs/rsgxsrequesttypes.cc b/libretroshare/src/gxs/rsgxsrequesttypes.cc index d57b4d353..6c3925974 100644 --- a/libretroshare/src/gxs/rsgxsrequesttypes.cc +++ b/libretroshare/src/gxs/rsgxsrequesttypes.cc @@ -23,6 +23,128 @@ #include "rsgxsrequesttypes.h" #include "util/rsstd.h" +std::ostream& operator<<(std::ostream& o,const GxsRequest& g) +{ + return g.print(o); +} + + +std::ostream& GroupMetaReq::print(std::ostream& o) const +{ + o << "[Request type=GroupMeta groupIds (size=" << mGroupIds.size() << "): " ; + + if(!mGroupIds.empty()) + { + o << *mGroupIds.begin() ; + + if(mGroupIds.size() > 1) + o << " ..." ; + } + + o << "]" ; + + return o; +} +std::ostream& GroupIdReq::print(std::ostream& o) const +{ + return o << "[Request type=GroupIdReq" << "]" ; +} + +std::ostream& GroupSerializedDataReq::print(std::ostream& o) const +{ + return o << "[Request type=GroupSerializedData" << "]" ; +} + +std::ostream& GroupDataReq::print(std::ostream& o) const +{ + o << "[Request type=GroupDataReq groupIds (size=" << mGroupIds.size() << "): " ; + + if(!mGroupIds.empty()) + { + o << *mGroupIds.begin() ; + + if(mGroupIds.size() > 1) + o << " ..." ; + } + + o << "]" ; + + return o; +} + +std::ostream& MsgIdReq::print(std::ostream& o) const +{ + return o << "[Request type=MsgId" << "]" ; +} + +std::ostream& MsgMetaReq::print(std::ostream& o) const +{ + o << "[Request type=MsgMetaReq groups (size=" << mMsgIds.size() << "): " ; + + if(!mMsgIds.empty()) + { + o << mMsgIds.begin()->first << " (" << mMsgIds.begin()->second.size() << " messages)"; + + if(mMsgIds.size() > 1) + o << " ..." ; + } + + o << "]" ; + + return o; +} + +std::ostream& MsgDataReq::print(std::ostream& o) const +{ + o << "[Request type=MsgDataReq groups (size=" << mMsgIds.size() << "): " ; + + if(!mMsgIds.empty()) + { + o << mMsgIds.begin()->first << " (" << mMsgIds.begin()->second.size() << " messages)"; + + if(mMsgIds.size() > 1) + o << " ..." ; + } + + o << "]" ; + + return o; +} + +std::ostream& MsgRelatedInfoReq::print(std::ostream& o) const +{ + o << "[Request type=MsgRelatedInfo msgIds (size=" << mMsgIds.size() << "): " ; + + if(!mMsgIds.empty()) + { + o << mMsgIds.begin()->first ; + + if(mMsgIds.size() > 1) + o << " ..." ; + } + + o << "]" ; + + return o; +} + +std::ostream& GroupSetFlagReq::print(std::ostream& o) const +{ + return o << "[Request type=GroupFlagSet grpId=" << grpId << "]" ; +} + + + +std::ostream& ServiceStatisticRequest::print(std::ostream& o) const +{ + return o << "[Request type=ServiceStatistics" << "]" ; +} + +std::ostream& GroupStatisticRequest::print(std::ostream& o) const +{ + return o << "[Request type=GroupStatistics grpId=" << mGrpId << "]" ; +} + GroupMetaReq::~GroupMetaReq() { //rsstd::delete_all(mGroupMetaData.begin(), mGroupMetaData.end()); // now memory ownership is kept by the cache. @@ -57,3 +179,8 @@ MsgRelatedInfoReq::~MsgRelatedInfoReq() rsstd::delete_all(dataIt->second.begin(), dataIt->second.end()); } } +std::ostream& MessageSetFlagReq::print(std::ostream& o) const +{ + return o << "[Request type=MsgFlagSet" << "]" ; +} + diff --git a/libretroshare/src/gxs/rsgxsrequesttypes.h b/libretroshare/src/gxs/rsgxsrequesttypes.h index 7af50b135..e738a1923 100644 --- a/libretroshare/src/gxs/rsgxsrequesttypes.h +++ b/libretroshare/src/gxs/rsgxsrequesttypes.h @@ -29,25 +29,30 @@ struct GxsRequest { GxsRequest() : - token(0), reqTime(0), ansType(0), reqType(0), + token(0), reqTime(0), clientAnswerType(0), reqType(0), status(RsTokenService::FAILED) {} virtual ~GxsRequest() {} uint32_t token; uint32_t reqTime; - RS_DEPRECATED uint32_t ansType; /// G10h4ck: This is of no use + uint32_t clientAnswerType; /// This is made available to the clients in order to keep track of why specific requests where sent.. uint32_t reqType; RsTokReqOptions Options; RsTokenService::GxsRequestStatus status; + + virtual std::ostream& print(std::ostream& o) const = 0; }; +std::ostream& operator<<(std::ostream& o,const GxsRequest& g); + class GroupMetaReq : public GxsRequest { public: virtual ~GroupMetaReq(); + virtual std::ostream& print(std::ostream& o) const override; public: std::list mGroupIds; std::list mGroupMetaData; @@ -56,12 +61,16 @@ public: class GroupIdReq : public GxsRequest { public: + virtual std::ostream& print(std::ostream& o) const override ; + std::list mGroupIds; std::list mGroupIdResult; }; class GroupSerializedDataReq : public GxsRequest { public: + virtual std::ostream& print(std::ostream& o) const override ; + std::list mGroupIds; std::list mGroupData; }; @@ -71,6 +80,7 @@ class GroupDataReq : public GxsRequest public: virtual ~GroupDataReq(); + virtual std::ostream& print(std::ostream& o) const override; public: std::list mGroupIds; std::list mGroupData; @@ -79,6 +89,8 @@ public: class MsgIdReq : public GxsRequest { public: + virtual std::ostream& print(std::ostream& o) const override ; + GxsMsgReq mMsgIds; GxsMsgIdResult mMsgIdResult; }; @@ -88,6 +100,8 @@ class MsgMetaReq : public GxsRequest public: virtual ~MsgMetaReq(); + virtual std::ostream& print(std::ostream& o) const override; + public: GxsMsgReq mMsgIds; GxsMsgMetaResult mMsgMetaData; @@ -98,6 +112,7 @@ class MsgDataReq : public GxsRequest public: virtual ~MsgDataReq(); + virtual std::ostream& print(std::ostream& o) const override; public: GxsMsgReq mMsgIds; NxsMsgDataResult mMsgData; @@ -106,12 +121,15 @@ public: class ServiceStatisticRequest: public GxsRequest { public: + virtual std::ostream& print(std::ostream& o) const override ; GxsServiceStatistic mServiceStatistic; }; struct GroupStatisticRequest: public GxsRequest { public: + virtual std::ostream& print(std::ostream& o) const override ; + RsGxsGroupId mGrpId; GxsGroupStatistic mGroupStatistic; }; @@ -121,6 +139,7 @@ class MsgRelatedInfoReq : public GxsRequest public: virtual ~MsgRelatedInfoReq(); + std::ostream& print(std::ostream& o) const override; public: std::vector mMsgIds; MsgRelatedIdResult mMsgIdResult; @@ -131,6 +150,8 @@ public: class GroupSetFlagReq : public GxsRequest { public: + virtual std::ostream& print(std::ostream& o) const override ; + const static uint32_t FLAG_SUBSCRIBE; const static uint32_t FLAG_STATUS; @@ -145,6 +166,7 @@ class MessageSetFlagReq : public GxsRequest public: const static uint32_t FLAG_STATUS; + virtual std::ostream& print(std::ostream& o) const override ; uint8_t type; uint32_t flag; uint32_t flagMask; diff --git a/libretroshare/src/gxstrans/p3gxstrans.cc b/libretroshare/src/gxstrans/p3gxstrans.cc index 44ecccbd1..92af56f08 100644 --- a/libretroshare/src/gxstrans/p3gxstrans.cc +++ b/libretroshare/src/gxstrans/p3gxstrans.cc @@ -43,7 +43,7 @@ p3GxsTrans::~p3GxsTrans() } } -bool p3GxsTrans::getStatistics(GxsTransStatistics& stats) +bool p3GxsTrans::getDataStatistics(GxsTransStatistics& stats) { { RS_STACK_MUTEX(mDataMutex); @@ -1335,4 +1335,53 @@ bool p3GxsTrans::acceptNewMessage(const RsGxsMsgMetaData *msgMeta,uint32_t msg_s } +bool p3GxsTrans::getGroupStatistics(std::map& stats) +{ + uint32_t token1; + + RsTokReqOptions opts1; + opts1.mReqType = GXS_REQUEST_TYPE_GROUP_META; + if( !requestGroupInfo(token1, opts1) || waitToken(token1) != RsTokenService::COMPLETE ) + return false; + + std::list group_metas; + getGroupSummary(token1,group_metas); + + for(auto& group_meta:group_metas) + { + RsGxsTransGroupStatistics& stat(stats[group_meta.mGroupId]); + + uint32_t token2; + if(!RsGxsIfaceHelper::requestGroupStatistic(token2,group_meta.mGroupId) || waitToken(token2) != RsTokenService::COMPLETE) + continue; + + RsGenExchange::getGroupStatistic(token2,stat); + + stat.popularity = group_meta.mPop ; + stat.subscribed = IS_GROUP_SUBSCRIBED(group_meta.mSubscribeFlags) ; + stat.mGrpId = group_meta.mGroupId ; + + std::vector metas; + + uint32_t token3; + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_MSG_META; + + std::list groupIds; + groupIds.push_back(group_meta.mGroupId); + + if( !requestMsgInfo(token3, opts, groupIds) || waitToken(token3, std::chrono::seconds(5)) != RsTokenService::COMPLETE ) + continue; + + GxsMsgMetaMap metaMap; + if(!RsGenExchange::getMsgMeta(token3, metaMap) || metaMap.size() != 1) + continue; + + for(auto& meta: metaMap.begin()->second) + stat.addMessageMeta(group_meta.mGroupId,meta) ; + } + + return true; +} + diff --git a/libretroshare/src/gxstrans/p3gxstrans.h b/libretroshare/src/gxstrans/p3gxstrans.h index fd2b92ee8..307492281 100644 --- a/libretroshare/src/gxstrans/p3gxstrans.h +++ b/libretroshare/src/gxstrans/p3gxstrans.h @@ -113,13 +113,21 @@ public: /*! * \brief getStatistics - * Gathers all sorts of statistics about the internals of p3GxsTrans, in order to display info about the running status, - * message transport, etc. + * Gathers all sorts of statistics about the data transported by p3GxsTrans, in order to display info about the running status, + * message transport, etc. This is a blocking call. Use it in a thread. * \param stats This structure contains all statistics information. * \return true is the call succeeds. */ - virtual bool getStatistics(GxsTransStatistics& stats); + virtual bool getDataStatistics(GxsTransStatistics& stats) override; + + /*! + * \brief getGroupStatistics + * Gathers statistics about GXS groups and messages used by GxsTrans to transport data. This is a blocking call. Use it in a thread. + * \param stats + * \return true if the data collection succeeds. + */ + virtual bool getGroupStatistics(std::map& stats) override; /** * Send an email to recipient, in the process author of the email is diff --git a/libretroshare/src/plugins/pluginmanager.cc b/libretroshare/src/plugins/pluginmanager.cc index f2a3c8b29..dcd474f8f 100644 --- a/libretroshare/src/plugins/pluginmanager.cc +++ b/libretroshare/src/plugins/pluginmanager.cc @@ -362,6 +362,7 @@ bool RsPluginManager::loadPlugin(const std::string& plugin_name,bool first_time) dlclose(handle); return false ; } +#ifdef TO_REMOVE if(pinfo.svn_revision == 0) { std::cerr << " -> No svn revision number." << std::endl; @@ -370,6 +371,7 @@ bool RsPluginManager::loadPlugin(const std::string& plugin_name,bool first_time) dlclose(handle); return false ; } +#endif // Now look for the plugin class symbol. // diff --git a/libretroshare/src/retroshare/rsgxschannels.h b/libretroshare/src/retroshare/rsgxschannels.h index 418afc670..9cc4bd33e 100644 --- a/libretroshare/src/retroshare/rsgxschannels.h +++ b/libretroshare/src/retroshare/rsgxschannels.h @@ -111,6 +111,7 @@ enum class RsChannelEventCode: uint8_t SUBSCRIBE_STATUS_CHANGED = 0x06, // subscription for channel mChannelGroupId changed. READ_STATUS_CHANGED = 0x07, // existing message has been read or set to unread RECEIVED_DISTANT_SEARCH_RESULT = 0x08, // result for the given group id available for the given turtle request id + STATISTICS_CHANGED = 0x09, // stats (nb of supplier friends, how many msgs they have etc) has changed }; struct RsGxsChannelEvent: RsEvent @@ -409,6 +410,14 @@ public: virtual bool subscribeToChannel( const RsGxsGroupId& channelId, bool subscribe ) = 0; + /** + * \brief Retrieve statistics about the channel service + * @jsonapi{development} + * \param[out] stat Statistics structure + * \return + */ + virtual bool getChannelServiceStatistics(GxsServiceStatistic& stat) =0; + /** * \brief Retrieve statistics about the given channel * @jsonapi{development} @@ -418,6 +427,7 @@ public: */ virtual bool getChannelStatistics(const RsGxsGroupId& channelId,GxsGroupStatistic& stat) =0; + /** * @brief Request remote channels search * @jsonapi{development} diff --git a/libretroshare/src/retroshare/rsgxsforums.h b/libretroshare/src/retroshare/rsgxsforums.h index 4e368792e..11a47cf7b 100644 --- a/libretroshare/src/retroshare/rsgxsforums.h +++ b/libretroshare/src/retroshare/rsgxsforums.h @@ -111,6 +111,7 @@ enum class RsForumEventCode: uint8_t UPDATED_MESSAGE = 0x04, /// existing message has been updated in a particular forum SUBSCRIBE_STATUS_CHANGED = 0x05, /// forum was subscribed or unsubscribed READ_STATUS_CHANGED = 0x06, /// msg was read or marked unread + STATISTICS_CHANGED = 0x07, /// suppliers and how many messages they have changed }; struct RsGxsForumEvent: RsEvent @@ -219,6 +220,14 @@ public: */ virtual bool getForumsSummaries(std::list& forums) = 0; + /** + * @brief returns statistics for the forum service + * @jsonapi{development} + * @param[out] stat statistics struct + * @return false if the call fails + */ + virtual bool getForumServiceStatistics(GxsServiceStatistic& stat) =0; + /** * @brief returns statistics about a particular forum * @jsonapi{development} @@ -228,6 +237,7 @@ public: */ virtual bool getForumStatistics(const RsGxsGroupId& forumId,GxsGroupStatistic& stat)=0; + /** * @brief Get forums information (description, thumbnail...). * Blocking API. diff --git a/libretroshare/src/retroshare/rsgxsifacehelper.h b/libretroshare/src/retroshare/rsgxsifacehelper.h index 9f49e76ef..e2d04f887 100644 --- a/libretroshare/src/retroshare/rsgxsifacehelper.h +++ b/libretroshare/src/retroshare/rsgxsifacehelper.h @@ -40,7 +40,9 @@ * are necessary, so at this point this workaround seems acceptable. */ -//#define DEBUG_GXSIFACEHELPER 1 +//================================== +// #define DEBUG_GXSIFACEHELPER 1 +//================================== enum class TokenRequestType: uint8_t { @@ -85,8 +87,7 @@ public: * @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) + bool getGroupList(const uint32_t &token, std::list &groupIds) { return mGxs.getGroupList(token, groupIds); } @@ -119,8 +120,7 @@ public: * @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) + bool getGroupSummary(const uint32_t &token, std::list &groupInfo) { return mGxs.getGroupMeta(token, groupInfo); } @@ -130,8 +130,7 @@ public: * @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) + bool getMsgSummary(const uint32_t &token, GxsMsgMetaMap &msgInfo) { return mGxs.getMsgMeta(token, msgInfo); } @@ -368,9 +367,12 @@ public: { return mTokenService.requestStatus(token); } /// @see RsTokenService::requestServiceStatistic - void requestServiceStatistic(uint32_t& token) + bool requestServiceStatistic(uint32_t& token) { - mTokenService.requestServiceStatistic(token); + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_SERVICE_STATS; + + mTokenService.requestServiceStatistic(token,opts); RS_STACK_MUTEX(mMtx); mActiveTokens[token]=TokenRequestType::SERVICE_STATISTICS; @@ -378,12 +380,16 @@ public: #ifdef DEBUG_GXSIFACEHELPER locked_dumpTokens(); #endif + return true; } /// @see RsTokenService::requestGroupStatistic bool requestGroupStatistic(uint32_t& token, const RsGxsGroupId& grpId) { - mTokenService.requestGroupStatistic(token, grpId); + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_GROUP_STATS; + + mTokenService.requestGroupStatistic(token, grpId,opts); RS_STACK_MUTEX(mMtx); mActiveTokens[token]=TokenRequestType::GROUP_STATISTICS; @@ -501,7 +507,7 @@ private: uint32_t count[7] = {0}; - std::cerr << "Service " << std::hex << service_id << std::dec + RsDbg() << "Service " << std::hex << service_id << std::dec << " (" << rsServiceControl->getServiceName(RsServiceInfo::RsServiceInfoUIn16ToFullServiceId(service_id)) << ") this=" << std::hex << (void*)this << std::dec << ") Active tokens (per type): " ; diff --git a/libretroshare/src/retroshare/rsgxsifacetypes.h b/libretroshare/src/retroshare/rsgxsifacetypes.h index 60111d0cc..90715dfcb 100644 --- a/libretroshare/src/retroshare/rsgxsifacetypes.h +++ b/libretroshare/src/retroshare/rsgxsifacetypes.h @@ -45,6 +45,13 @@ struct RsMsgMetaData; typedef std::map > MsgMetaResult; +enum class GxsRequestPriority { + VERY_HIGH = 0x00, + HIGH = 0x01, + NORMAL = 0x02, + LOW = 0x03, + VERY_LOW = 0x04, +}; class RsGxsGrpMetaData; class RsGxsMsgMetaData; @@ -232,7 +239,7 @@ public: mNumChildMsgsNew = 0; mNumChildMsgsUnread = 0; mSizeStore = 0; - } + } public: uint32_t mNumMsgs; diff --git a/libretroshare/src/retroshare/rsgxsservice.h b/libretroshare/src/retroshare/rsgxsservice.h index cb4fcf7eb..4739b0ec2 100644 --- a/libretroshare/src/retroshare/rsgxsservice.h +++ b/libretroshare/src/retroshare/rsgxsservice.h @@ -46,7 +46,8 @@ struct RsGxsNotify TYPE_RECEIVED_NEW = 0x02, TYPE_PROCESSED = 0x03, TYPE_RECEIVED_PUBLISHKEY = 0x04, - TYPE_RECEIVED_DISTANT_SEARCH_RESULTS = 0x05 + TYPE_RECEIVED_DISTANT_SEARCH_RESULTS = 0x05, + TYPE_STATISTICS_CHANGED = 0x06 }; virtual ~RsGxsNotify() {} diff --git a/libretroshare/src/retroshare/rsgxstrans.h b/libretroshare/src/retroshare/rsgxstrans.h index e1b8d4d8f..8cbb514a6 100644 --- a/libretroshare/src/retroshare/rsgxstrans.h +++ b/libretroshare/src/retroshare/rsgxstrans.h @@ -70,10 +70,8 @@ enum class GxsTransSendStatus : uint8_t typedef uint64_t RsGxsTransId; -class RsGxsTransGroup +class RsGxsTransGroup: public RsGxsGenericGroupData { - public: - RsGroupMetaData mMeta; }; class RsGxsTransMsg @@ -103,7 +101,34 @@ struct RsGxsTransOutgoingRecord RsGxsGroupId group_id ; }; +class RsGxsTransGroupStatistics: public GxsGroupStatistic +{ +public: + RsGxsTransGroupStatistics() + { + last_publish_TS = 0; + popularity = 0; + subscribed = false; + } + + void addMessageMeta(const RsGxsGroupId& grp,const RsMsgMetaData& meta) + { + messages_metas[meta.mMsgId] = meta ; + last_publish_TS = std::max(last_publish_TS,meta.mPublishTs) ; + mGrpId = grp ; + } + + bool subscribed ; + int popularity ; + + rstime_t last_publish_TS; + + std::map messages_metas ; +}; + + /// RetroShare GxsTrans asyncronous redundant small mail trasport on top of GXS +/// class RsGxsTrans: public RsGxsIfaceHelper { public: @@ -120,10 +145,8 @@ public: virtual ~RsGxsTrans() {} - virtual bool getStatistics(GxsTransStatistics& stats)=0; - -// virtual bool getGroupData(const uint32_t &token, std::vector &groups) = 0; -// virtual bool getPostData(const uint32_t &token, std::vector &posts) = 0; + virtual bool getDataStatistics(GxsTransStatistics& stats)=0; + virtual bool getGroupStatistics(std::map& stats) =0; }; extern RsGxsTrans *rsGxsTrans ; diff --git a/libretroshare/src/retroshare/rsinit.h b/libretroshare/src/retroshare/rsinit.h index 5c2064030..165649f16 100644 --- a/libretroshare/src/retroshare/rsinit.h +++ b/libretroshare/src/retroshare/rsinit.h @@ -313,7 +313,8 @@ extern RsAccounts* rsAccounts; class RsLoginHelper { public: - RsLoginHelper() {} + RsLoginHelper() = default; + /** * @brief Normal way to attempt login * @jsonapi{development,manualwrapper} diff --git a/libretroshare/src/retroshare/rsmsgs.h b/libretroshare/src/retroshare/rsmsgs.h index 7304e6b85..8ddba2d1c 100644 --- a/libretroshare/src/retroshare/rsmsgs.h +++ b/libretroshare/src/retroshare/rsmsgs.h @@ -987,8 +987,18 @@ virtual void getOwnAvatarData(unsigned char *& data,int& size) = 0 ; virtual uint32_t getDistantChatPermissionFlags()=0 ; virtual bool setDistantChatPermissionFlags(uint32_t flags)=0 ; - -virtual bool initiateDistantChatConnexion( + + /** + * @brief initiateDistantChatConnexion initiate a connexion for a distant chat + * @jsonapi{development} + * @param[in] to_pid RsGxsId to start the connection + * @param[in] from_pid owned RsGxsId who start the connection + * @param[out] pid distant chat id + * @param[out] error_code if the connection can't be stablished + * @param[in] notify notify remote that the connection is stablished + * @return true on success + */ + virtual bool initiateDistantChatConnexion( const RsGxsId& to_pid, const RsGxsId& from_pid, DistantChatPeerId& pid, uint32_t& error_code, bool notify = true ) = 0; @@ -1001,7 +1011,14 @@ virtual bool initiateDistantChatConnexion( * @return true on success */ virtual bool getDistantChatStatus(const DistantChatPeerId& pid, DistantChatPeerInfo& info)=0; -virtual bool closeDistantChatConnexion(const DistantChatPeerId& pid)=0; + + /** + * @brief closeDistantChatConnexion + * @jsonapi{development} + * @param[in] pid distant chat id to close the connection + * @return true on success + */ + virtual bool closeDistantChatConnexion(const DistantChatPeerId& pid)=0; /** * @brief MessageSend diff --git a/libretroshare/src/retroshare/rsposted.h b/libretroshare/src/retroshare/rsposted.h index 347419082..1a089de8e 100644 --- a/libretroshare/src/retroshare/rsposted.h +++ b/libretroshare/src/retroshare/rsposted.h @@ -114,6 +114,7 @@ enum class RsPostedEventCode: uint8_t UPDATED_POSTED_GROUP = 0x04, UPDATED_MESSAGE = 0x05, READ_STATUS_CHANGED = 0x06, + STATISTICS_CHANGED = 0x07, }; @@ -167,6 +168,8 @@ public: virtual bool getBoardStatistics(const RsGxsGroupId& boardId,GxsGroupStatistic& stat) =0; + virtual bool getBoardsServiceStatistics(GxsServiceStatistic& stat) =0; + enum RS_DEPRECATED RankType {TopRankType, HotRankType, NewRankType }; RS_DEPRECATED_FOR(getBoardsInfo) diff --git a/libretroshare/src/retroshare/rstokenservice.h b/libretroshare/src/retroshare/rstokenservice.h index 7f801927f..a0fbd7258 100644 --- a/libretroshare/src/retroshare/rstokenservice.h +++ b/libretroshare/src/retroshare/rstokenservice.h @@ -80,7 +80,7 @@ struct RsTokReqOptions { RsTokReqOptions() : mOptions(0), mStatusFilter(0), mStatusMask(0), mMsgFlagMask(0), mMsgFlagFilter(0), mReqType(0), mSubscribeFilter(0), - mSubscribeMask(0), mBefore(0), mAfter(0) {} + mSubscribeMask(0), mBefore(0), mAfter(0),mPriority(GxsRequestPriority::NORMAL) {} /** * Can be one or multiple RS_TOKREQOPT_* @@ -107,6 +107,8 @@ struct RsTokReqOptions // Time range... again applied after Options. rstime_t mBefore; rstime_t mAfter; + + GxsRequestPriority mPriority; }; /*! @@ -181,6 +183,25 @@ public: */ 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 */ @@ -194,25 +215,6 @@ public: */ virtual GxsRequestStatus requestStatus(const uint32_t token) = 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) = 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) = 0; - /*! * @brief Cancel Request * If this function returns false, it may be that the request has completed diff --git a/libretroshare/src/retroshare/rswire.h b/libretroshare/src/retroshare/rswire.h index 233befc11..03da21116 100644 --- a/libretroshare/src/retroshare/rswire.h +++ b/libretroshare/src/retroshare/rswire.h @@ -28,6 +28,7 @@ #include "retroshare/rstokenservice.h" #include "retroshare/rsgxsifacehelper.h" +#include "retroshare/rsgxscommon.h" /* The Main Interface Class - for information about your Peers */ @@ -38,6 +39,7 @@ struct RsWireGroup: RsGxsGenericGroupData { public: std::string mDescription; + RsGxsImage mIcon; }; @@ -93,9 +95,10 @@ class RsWirePlace #define WIRE_PULSE_TYPE_REPLY_MSG (0x0002) #define WIRE_PULSE_TYPE_REPLY_REFERENCE (0x0004) -#define WIRE_PULSE_TYPE_SENTIMENT_POSITIVE (0x0010) -#define WIRE_PULSE_TYPE_SENTIMENT_NEUTRAL (0x0020) -#define WIRE_PULSE_TYPE_SENTIMENT_NEGATIVE (0x0040) +#define WIRE_PULSE_SENTIMENT_NO_SENTIMENT (0x0000) +#define WIRE_PULSE_SENTIMENT_POSITIVE (0x0001) +#define WIRE_PULSE_SENTIMENT_NEUTRAL (0x0002) +#define WIRE_PULSE_SENTIMENT_NEGATIVE (0x0003) class RsWirePulse { @@ -107,6 +110,7 @@ class RsWirePulse std::string mPulseText; uint32_t mPulseType; + uint32_t mReplySentiment; // only relevant if a reply. // These Ref to the related (parent or reply) if reply (MODE_REPLY_MSG set) // Mode REPLY_MSG only REPLY_REFERENCE diff --git a/libretroshare/src/rsitems/rswireitems.cc b/libretroshare/src/rsitems/rswireitems.cc index 65360dbf4..69774ffc5 100644 --- a/libretroshare/src/rsitems/rswireitems.cc +++ b/libretroshare/src/rsitems/rswireitems.cc @@ -44,17 +44,20 @@ RsItem *RsGxsWireSerialiser::create_item(uint16_t service,uint8_t item_subtype) void RsGxsWireGroupItem::clear() { group.mDescription.clear(); + group.mIcon.clear(); } void RsGxsWireGroupItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) { RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_STR_DESCR,group.mDescription,"group.mDescription") ; + group.mIcon.serial_process(j, ctx); } void RsGxsWirePulseItem::clear() { pulse.mPulseText.clear(); pulse.mPulseType = 0; + pulse.mReplySentiment = 0; pulse.mRefGroupId.clear(); pulse.mRefGroupName.clear(); pulse.mRefOrigMsgId.clear(); @@ -66,6 +69,7 @@ void RsGxsWirePulseItem::serial_process(RsGenericSerializer::SerializeJob j,RsGe { RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_STR_MSG,pulse.mPulseText,"pulse.mPulseText") ; RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_UINT32_PARAM,pulse.mPulseType,"pulse.mPulseType") ; + RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_UINT32_PARAM,pulse.mReplySentiment,"pulse.mReplySentiment") ; RsTypeSerializer::serial_process(j,ctx,pulse.mRefGroupId,"pulse.mRefGroupId") ; RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_STR_NAME,pulse.mRefGroupName,"pulse.mRefGroupName") ; RsTypeSerializer::serial_process(j,ctx,pulse.mRefOrigMsgId,"pulse.mRefOrigMsgId") ; diff --git a/libretroshare/src/services/p3gxschannels.cc b/libretroshare/src/services/p3gxschannels.cc index 931098059..9e0072d5b 100644 --- a/libretroshare/src/services/p3gxschannels.cc +++ b/libretroshare/src/services/p3gxschannels.cc @@ -302,7 +302,6 @@ void p3GxsChannels::notifyChanges(std::vector &changes) { switch (grpChange->getType()) { - default: case RsGxsNotify::TYPE_PROCESSED: // happens when the group is subscribed { std::list &grpList = grpChange->mGrpIdList; @@ -318,6 +317,20 @@ void p3GxsChannels::notifyChanges(std::vector &changes) } break; + case RsGxsNotify::TYPE_STATISTICS_CHANGED: + { + std::list &grpList = grpChange->mGrpIdList; + std::list::iterator git; + for (git = grpList.begin(); git != grpList.end(); ++git) + { + auto ev = std::make_shared(); + ev->mChannelGroupId = *git; + ev->mChannelEventCode = RsChannelEventCode::STATISTICS_CHANGED; + rsEvents->postEvent(ev); + } + } + break; + case RsGxsNotify::TYPE_PUBLISHED: case RsGxsNotify::TYPE_RECEIVED_NEW: { @@ -356,9 +369,14 @@ void p3GxsChannels::notifyChanges(std::vector &changes) rsEvents->postEvent(ev); } + } + break; + + default: + RsErr() << " Got a GXS event of type " << grpChange->getType() << " Currently not handled." << std::endl; break; } - } + } RsGxsDistantSearchResultChange *dsrChange = dynamic_cast(*it); @@ -1062,6 +1080,15 @@ bool p3GxsChannels::getChannelStatistics(const RsGxsGroupId& channelId,GxsGroupS return RsGenExchange::getGroupStatistic(token,stat); } +bool p3GxsChannels::getChannelServiceStatistics(GxsServiceStatistic& stat) +{ + uint32_t token; + if(!RsGxsIfaceHelper::requestServiceStatistic(token) || waitToken(token) != RsTokenService::COMPLETE) + return false; + + return RsGenExchange::getServiceStatistic(token,stat); +} + bool p3GxsChannels::getContentSummaries( const RsGxsGroupId& channelId, std::vector& summaries ) { diff --git a/libretroshare/src/services/p3gxschannels.h b/libretroshare/src/services/p3gxschannels.h index e529c227b..843023fb8 100644 --- a/libretroshare/src/services/p3gxschannels.h +++ b/libretroshare/src/services/p3gxschannels.h @@ -204,6 +204,9 @@ virtual bool ExtraFileRemove(const RsFileHash &hash); /// Implementation of @see RsGxsChannels::getChannelStatistics bool getChannelStatistics(const RsGxsGroupId& channelId,GxsGroupStatistic& stat) override; + /// Iplementation of @see RsGxsChannels::getChannelServiceStatistics + bool getChannelServiceStatistics(GxsServiceStatistic& stat) override; + /// Implementation of @see RsGxsChannels::createChannelV2 bool createChannelV2( const std::string& name, const std::string& description, diff --git a/libretroshare/src/services/p3gxsforums.cc b/libretroshare/src/services/p3gxsforums.cc index c7f3fddcf..42b60fad2 100644 --- a/libretroshare/src/services/p3gxsforums.cc +++ b/libretroshare/src/services/p3gxsforums.cc @@ -246,7 +246,6 @@ void p3GxsForums::notifyChanges(std::vector &changes) { switch (grpChange->getType()) { - default: case RsGxsNotify::TYPE_PROCESSED: // happens when the group is subscribed { std::list &grpList = grpChange->mGrpIdList; @@ -260,7 +259,7 @@ void p3GxsForums::notifyChanges(std::vector &changes) } } - break; + break; case RsGxsNotify::TYPE_PUBLISHED: case RsGxsNotify::TYPE_RECEIVED_NEW: @@ -288,8 +287,26 @@ void p3GxsForums::notifyChanges(std::vector &changes) << " Not notifying already known forum " << *git << std::endl; } - break; } + break; + + case RsGxsNotify::TYPE_STATISTICS_CHANGED: + { + std::list &grpList = grpChange->mGrpIdList; + std::list::iterator git; + for (git = grpList.begin(); git != grpList.end(); ++git) + { + auto ev = std::make_shared(); + ev->mForumGroupId = *git; + ev->mForumEventCode = RsForumEventCode::STATISTICS_CHANGED; + rsEvents->postEvent(ev); + } + } + break; + default: + RsErr() << " Got a GXS event of type " << grpChange->getType() << " Currently not handled." << std::endl; + break; + #ifdef NOT_USED_YET case RsGxsNotify::TYPE_RECEIVED_PUBLISHKEY: @@ -819,6 +836,15 @@ bool p3GxsForums::createGroup(uint32_t &token, RsGxsForumGroup &group) return true; } +bool p3GxsForums::getForumServiceStatistics(GxsServiceStatistic& stat) +{ + uint32_t token; + if(!RsGxsIfaceHelper::requestServiceStatistic(token) || waitToken(token) != RsTokenService::COMPLETE) + return false; + + return RsGenExchange::getServiceStatistic(token,stat); +} + bool p3GxsForums::getForumStatistics(const RsGxsGroupId& ForumId,GxsGroupStatistic& stat) { uint32_t token; diff --git a/libretroshare/src/services/p3gxsforums.h b/libretroshare/src/services/p3gxsforums.h index c95acf447..347714acb 100644 --- a/libretroshare/src/services/p3gxsforums.h +++ b/libretroshare/src/services/p3gxsforums.h @@ -97,6 +97,9 @@ public: /// Implementation of @see RsGxsForums::getForumStatistics bool getForumStatistics(const RsGxsGroupId& ForumId,GxsGroupStatistic& stat) override; + /// Implementation of @see RsGxsForums::getForumServiceStatistics + bool getForumServiceStatistics(GxsServiceStatistic& stat) override; + /// @see RsGxsForums::getForumMsgMetaData virtual bool getForumMsgMetaData(const RsGxsGroupId& forumId, std::vector& msg_metas) ; diff --git a/libretroshare/src/services/p3postbase.cc b/libretroshare/src/services/p3postbase.cc index 8dd48c174..771103eb0 100644 --- a/libretroshare/src/services/p3postbase.cc +++ b/libretroshare/src/services/p3postbase.cc @@ -133,8 +133,7 @@ void p3PostBase::notifyChanges(std::vector &changes) #endif switch(grpChange->getType()) - { - default: + { case RsGxsNotify::TYPE_PROCESSED: // happens when the group is subscribed { std::list &grpList = grpChange->mGrpIdList; @@ -148,15 +147,30 @@ void p3PostBase::notifyChanges(std::vector &changes) } } - break; + break; - case RsGxsNotify::TYPE_PUBLISHED: - case RsGxsNotify::TYPE_RECEIVED_NEW: - { - /* group received */ - const std::list& grpList = grpChange->mGrpIdList; + case RsGxsNotify::TYPE_STATISTICS_CHANGED: + { + std::list &grpList = grpChange->mGrpIdList; + std::list::iterator git; - for (auto git = grpList.begin(); git != grpList.end(); ++git) + for (git = grpList.begin(); git != grpList.end(); ++git) + { + auto ev = std::make_shared(); + ev->mPostedGroupId = *git; + ev->mPostedEventCode = RsPostedEventCode::STATISTICS_CHANGED; + rsEvents->postEvent(ev); + } + } + break; + + case RsGxsNotify::TYPE_PUBLISHED: + case RsGxsNotify::TYPE_RECEIVED_NEW: + { + /* group received */ + const std::list& grpList = grpChange->mGrpIdList; + + for (auto git = grpList.begin(); git != grpList.end(); ++git) { if(mKnownPosted.find(*git) == mKnownPosted.end()) { @@ -178,9 +192,13 @@ void p3PostBase::notifyChanges(std::vector &changes) << " Not notifying already known forum " << *git << std::endl; } - } + } break; - } + + default: + RsErr() << " Got a GXS event of type " << grpChange->getType() << " Currently not handled." << std::endl; + break; + } } delete *it; diff --git a/libretroshare/src/services/p3posted.cc b/libretroshare/src/services/p3posted.cc index 299a990b1..db1de62ca 100644 --- a/libretroshare/src/services/p3posted.cc +++ b/libretroshare/src/services/p3posted.cc @@ -364,6 +364,16 @@ bool p3Posted::getBoardsSummaries(std::list& boards ) return getGroupSummary(token, boards); } +bool p3Posted::getBoardsServiceStatistics(GxsServiceStatistic& stat) +{ + uint32_t token; + if(!RsGxsIfaceHelper::requestServiceStatistic(token) || waitToken(token) != RsTokenService::COMPLETE) + return false; + + return RsGenExchange::getServiceStatistic(token,stat); +} + + bool p3Posted::getBoardStatistics(const RsGxsGroupId& boardId,GxsGroupStatistic& stat) { uint32_t token; diff --git a/libretroshare/src/services/p3posted.h b/libretroshare/src/services/p3posted.h index 3cc016ee7..b6f3ccee5 100644 --- a/libretroshare/src/services/p3posted.h +++ b/libretroshare/src/services/p3posted.h @@ -74,6 +74,8 @@ virtual void receiveHelperChanges(std::vector& changes) bool getBoardStatistics(const RsGxsGroupId& boardId,GxsGroupStatistic& stat) override; + bool getBoardsServiceStatistics(GxsServiceStatistic& stat) override; + bool editBoard(RsPostedGroup& board) override; bool createBoard(RsPostedGroup& board) override; diff --git a/libretroshare/src/util/rsdebug.h b/libretroshare/src/util/rsdebug.h index 1148f74f2..d4a22d84d 100644 --- a/libretroshare/src/util/rsdebug.h +++ b/libretroshare/src/util/rsdebug.h @@ -75,7 +75,8 @@ private: #else // def __ANDROID__ #include -#include +#include +#include enum class RsLoggerCategories { @@ -96,8 +97,15 @@ struct t_RsLogger template inline stream_type& operator<<(const T& val) { - return std::cerr << static_cast(CATEGORY) << " " << time(nullptr) - << " " << val; + using namespace std::chrono; + const auto now = system_clock::now(); + const auto sec = time_point_cast(now); + const auto msec = duration_cast(now - sec); + const auto tFill = std::cerr.fill(); + return std::cerr << static_cast(CATEGORY) << " " + << sec.time_since_epoch().count() << "." + << std::setfill('0') << std::setw(3) << msec.count() + << std::setfill(tFill) << " " << val; } }; #endif // def __ANDROID__ diff --git a/retroshare-gui/src/gui/ChatLobbyWidget.cpp b/retroshare-gui/src/gui/ChatLobbyWidget.cpp index 46d5116e8..25c476953 100644 --- a/retroshare-gui/src/gui/ChatLobbyWidget.cpp +++ b/retroshare-gui/src/gui/ChatLobbyWidget.cpp @@ -418,9 +418,7 @@ void ChatLobbyWidget::addChatPage(ChatLobbyDialog *d) if(_lobby_infos.find(d->id()) == _lobby_infos.end()) { - ui.stackedWidget->addWidget(d) ; - - connect(d,SIGNAL(lobbyLeave(ChatLobbyId)),this,SLOT(unsubscribeChatLobby(ChatLobbyId))) ; + connect(d,SIGNAL(dialogClose(ChatDialog*)),this,SLOT(dialogClose(ChatDialog*))); connect(d,SIGNAL(typingEventReceived(ChatLobbyId)),this,SLOT(updateTypingStatus(ChatLobbyId))) ; connect(d,SIGNAL(messageReceived(bool,ChatLobbyId,QDateTime,QString,QString)),this,SLOT(updateMessageChanged(bool,ChatLobbyId,QDateTime,QString,QString))) ; connect(d,SIGNAL(peerJoined(ChatLobbyId)),this,SLOT(updatePeerEntering(ChatLobbyId))) ; @@ -429,14 +427,33 @@ void ChatLobbyWidget::addChatPage(ChatLobbyDialog *d) ChatLobbyId id = d->id(); _lobby_infos[id].dialog = d ; _lobby_infos[id].default_icon = QIcon() ; - _lobby_infos[id].last_typing_event = time(NULL) ; + _lobby_infos[id].last_typing_event = time(nullptr) ; - ChatLobbyInfo linfo ; - if(rsMsgs->getChatLobbyInfo(id,linfo)) - _lobby_infos[id].default_icon = (linfo.lobby_flags & RS_CHAT_LOBBY_FLAGS_PUBLIC) ? QIcon(IMAGE_PUBLIC):QIcon(IMAGE_PRIVATE) ; - else - std::cerr << "(EE) cannot find info for room " << std::hex << id << std::dec << std::endl; + ChatLobbyInfo linfo ; + if(rsMsgs->getChatLobbyInfo(id,linfo)) + _lobby_infos[id].default_icon = (linfo.lobby_flags & RS_CHAT_LOBBY_FLAGS_PUBLIC) ? QIcon(IMAGE_PUBLIC):QIcon(IMAGE_PRIVATE) ; + else + std::cerr << "(EE) cannot find info for room " << std::hex << id << std::dec << std::endl; } + + ui.stackedWidget->addWidget(d) ; +} + +void ChatLobbyWidget::removeChatPage(ChatLobbyDialog *d) +{ + // check that the page already exist. + + if(_lobby_infos.find(d->id()) != _lobby_infos.end()) + { + ui.stackedWidget->removeWidget(d) ; + } +} + +void ChatLobbyWidget::dialogClose(ChatDialog* cd) +{ + ChatLobbyDialog* d = dynamic_cast(cd); + if(_lobby_infos.find(d->id()) != _lobby_infos.end()) + unsubscribeChatLobby(d->id()); } void ChatLobbyWidget::setCurrentChatPage(ChatLobbyDialog *d) @@ -708,7 +725,7 @@ void ChatLobbyWidget::createChatLobby() void ChatLobbyWidget::showLobby(QTreeWidgetItem *item) { - if (item == NULL || item->type() != TYPE_LOBBY) { + if (item == nullptr || item->type() != TYPE_LOBBY) { showBlankPage(0) ; return; } @@ -718,7 +735,11 @@ void ChatLobbyWidget::showLobby(QTreeWidgetItem *item) if(_lobby_infos.find(id) == _lobby_infos.end()) showBlankPage(id) ; else - ui.stackedWidget->setCurrentWidget(_lobby_infos[id].dialog) ; + { + _lobby_infos[id].dialog->showDialog(RS_CHAT_FOCUS); + if (_lobby_infos[id].dialog->isWindowed()) + showBlankPage(id, true); + } } // this function is for the case where we don't have any identity yet @@ -772,17 +793,17 @@ bool ChatLobbyWidget::showLobbyAnchor(ChatLobbyId id, QString anchor) { QTreeWidgetItem *item = getTreeWidgetItem(id) ; - if(item != NULL) { + if(item != nullptr) { if(item->type() == TYPE_LOBBY) { if(_lobby_infos.find(id) == _lobby_infos.end()) { showBlankPage(id) ; } else { - //ChatLobbyDialog cldChatLobby =_lobby_infos[id].dialog; - ui.stackedWidget->setCurrentWidget(_lobby_infos[id].dialog) ; - ChatLobbyDialog *cldCW=NULL ; - if (NULL != (cldCW = dynamic_cast(ui.stackedWidget->currentWidget()))) - cldCW->getChatWidget()->scrollToAnchor(anchor); + _lobby_infos[id].dialog->showDialog(RS_CHAT_FOCUS); + if (_lobby_infos[id].dialog->isWindowed()) + showBlankPage(id, true); + + _lobby_infos[id].dialog->getChatWidget()->scrollToAnchor(anchor); } ui.lobbyTreeWidget->setCurrentItem(item); @@ -857,20 +878,20 @@ void ChatLobbyWidget::autoSubscribeLobby(QTreeWidgetItem *item) subscribeChatLobbyAtItem(item); } -void ChatLobbyWidget::showBlankPage(ChatLobbyId id) +void ChatLobbyWidget::showBlankPage(ChatLobbyId id, bool subscribed /*= false*/) { // show the default blank page. ui.stackedWidget->setCurrentWidget(ui._lobby_blank_page) ; // Update information std::vector lobbies; - rsMsgs->getListOfNearbyChatLobbies(lobbies); + rsMsgs->getListOfNearbyChatLobbies(lobbies); - std::list my_ids ; - rsIdentity->getOwnIds(my_ids) ; + std::list my_ids ; + rsIdentity->getOwnIds(my_ids) ; + + trimAnonIds(my_ids) ; - trimAnonIds(my_ids) ; - for(std::vector::const_iterator it(lobbies.begin());it!=lobbies.end();++it) if( (*it).lobby_id == id) { @@ -881,8 +902,10 @@ void ChatLobbyWidget::showBlankPage(ChatLobbyId id) ui.lobbysec_lineEdit->setText( (( (*it).lobby_flags & RS_CHAT_LOBBY_FLAGS_PGP_SIGNED)?tr("No anonymous IDs"):tr("Anonymous IDs accepted")) ); ui.lobbypeers_lineEdit->setText( QString::number((*it).total_number_of_peers) ); - QString text = tr("You're not subscribed to this chat room; Double click-it to enter and chat.") ; - + QString text = tr("You're subscribed to this chat room; Double click to show window and chat.") ; + if (!subscribed) + { + text = tr("You're not subscribed to this chat room; Double click-it to enter and chat.") ; if(my_ids.empty()) { if( (*it).lobby_flags & RS_CHAT_LOBBY_FLAGS_PGP_SIGNED) @@ -890,8 +913,9 @@ void ChatLobbyWidget::showBlankPage(ChatLobbyId id) else text += "\n\n"+tr("You will need to create an identity in order to join chat rooms.") ; } + } - ui.lobbyInfoLabel->setText(text); + ui.lobbyInfoLabel->setText(text); return ; } @@ -1037,6 +1061,8 @@ void ChatLobbyWidget::unsubscribeChatLobby(ChatLobbyId id) } ui.stackedWidget->removeWidget(it->second.dialog) ; + disconnect(it->second.dialog,SIGNAL(dialogClose(ChatDialog*)),this,SLOT(dialogClose(ChatDialog*))); + it->second.dialog->leaveLobby(); _lobby_infos.erase(it) ; } diff --git a/retroshare-gui/src/gui/ChatLobbyWidget.h b/retroshare-gui/src/gui/ChatLobbyWidget.h index 8c6f07081..415c28bc2 100644 --- a/retroshare-gui/src/gui/ChatLobbyWidget.h +++ b/retroshare-gui/src/gui/ChatLobbyWidget.h @@ -38,6 +38,7 @@ class RSTreeWidgetItemCompareRole; class ChatTabWidget ; +class ChatDialog ; class ChatLobbyDialog ; class QTextBrowser ; @@ -69,6 +70,7 @@ public: void setCurrentChatPage(ChatLobbyDialog *) ; // used by ChatLobbyDialog to raise. void addChatPage(ChatLobbyDialog *) ; + void removeChatPage(ChatLobbyDialog *) ; bool showLobbyAnchor(ChatLobbyId id, QString anchor) ; uint unreadCount(); @@ -77,6 +79,7 @@ signals: void unreadCountChanged(uint unreadCount); protected slots: + void dialogClose(ChatDialog*); void lobbyChanged(); void lobbyTreeWidgetCustomPopupMenu(QPoint); void createChatLobby(); @@ -87,7 +90,7 @@ protected slots: void displayChatLobbyEvent(qulonglong lobby_id, int event_type, const RsGxsId& gxs_id, const QString& str); void readChatLobbyInvites(); void showLobby(QTreeWidgetItem *lobby_item) ; - void showBlankPage(ChatLobbyId id) ; + void showBlankPage(ChatLobbyId id, bool subscribed = false) ; void unsubscribeChatLobby(ChatLobbyId id) ; void createIdentityAndSubscribe(); void subscribeChatLobbyAs() ; diff --git a/retroshare-gui/src/gui/FileTransfer/SearchDialog.ui b/retroshare-gui/src/gui/FileTransfer/SearchDialog.ui index 47e221bf5..66992944d 100644 --- a/retroshare-gui/src/gui/FileTransfer/SearchDialog.ui +++ b/retroshare-gui/src/gui/FileTransfer/SearchDialog.ui @@ -6,8 +6,8 @@ 0 0 - 1531 - 889 + 793 + 511 @@ -26,28 +26,28 @@ - QFrame::Box + QFrame::NoFrame - QFrame::Sunken + QFrame::Plain - 2 + 3 - 2 + 3 - 2 + 3 - 2 + 3 - 0 + 2 @@ -414,7 +414,7 @@ Directory - + :/images/folder16.png:/images/folder16.png diff --git a/retroshare-gui/src/gui/Posted/PostedDialog.cpp b/retroshare-gui/src/gui/Posted/PostedDialog.cpp index cbf7426d9..a6fdda0bd 100644 --- a/retroshare-gui/src/gui/Posted/PostedDialog.cpp +++ b/retroshare-gui/src/gui/Posted/PostedDialog.cpp @@ -62,13 +62,18 @@ void PostedDialog::handleEvent_main_thread(std::shared_ptr event) case RsPostedEventCode::NEW_MESSAGE: case RsPostedEventCode::UPDATED_MESSAGE: // [[fallthrough]]; case RsPostedEventCode::READ_STATUS_CHANGED: // [[fallthrough]]; - updateMessageSummaryList(e->mPostedGroupId); + updateGroupStatisticsReal(e->mPostedGroupId); // update the list immediately break; case RsPostedEventCode::NEW_POSTED_GROUP: // [[fallthrough]]; case RsPostedEventCode::SUBSCRIBE_STATUS_CHANGED: // [[fallthrough]]; updateDisplay(true); break; + + case RsPostedEventCode::STATISTICS_CHANGED: + updateGroupStatistics(e->mPostedGroupId); + break; + default: break; } } @@ -82,7 +87,7 @@ PostedDialog::~PostedDialog() UserNotify *PostedDialog::createUserNotify(QObject *parent) { - return new PostedUserNotify(rsPosted, parent); + return new PostedUserNotify(rsPosted, this, parent); } QString PostedDialog::getHelpString() const diff --git a/retroshare-gui/src/gui/Posted/PostedUserNotify.cpp b/retroshare-gui/src/gui/Posted/PostedUserNotify.cpp index ef0cfa31d..39fddd451 100644 --- a/retroshare-gui/src/gui/Posted/PostedUserNotify.cpp +++ b/retroshare-gui/src/gui/Posted/PostedUserNotify.cpp @@ -18,18 +18,19 @@ * * *******************************************************************************/ +#include "retroshare/rsposted.h" #include "PostedUserNotify.h" #include "gui/MainWindow.h" -PostedUserNotify::PostedUserNotify(RsGxsIfaceHelper *ifaceImpl, QObject *parent) : - GxsUserNotify(ifaceImpl, parent) +PostedUserNotify::PostedUserNotify(RsGxsIfaceHelper *ifaceImpl, const GxsGroupFrameDialog *g, QObject *parent) : + GxsUserNotify(ifaceImpl, g, parent) { } bool PostedUserNotify::hasSetting(QString *name, QString *group) { - if (name) *name = tr("Posted"); - if (group) *group = "Posted"; + if (name) *name = tr("Board Post"); + if (group) *group = "Board"; return true; } diff --git a/retroshare-gui/src/gui/Posted/PostedUserNotify.h b/retroshare-gui/src/gui/Posted/PostedUserNotify.h index 11552669a..2c12ac889 100644 --- a/retroshare-gui/src/gui/Posted/PostedUserNotify.h +++ b/retroshare-gui/src/gui/Posted/PostedUserNotify.h @@ -28,7 +28,7 @@ class PostedUserNotify : public GxsUserNotify Q_OBJECT public: - PostedUserNotify(RsGxsIfaceHelper *ifaceImpl, QObject *parent = 0); + PostedUserNotify(RsGxsIfaceHelper *ifaceImpl, const GxsGroupFrameDialog *g, QObject *parent = 0); virtual bool hasSetting(QString *name, QString *group); diff --git a/retroshare-gui/src/gui/TheWire/PulseAddDialog.cpp b/retroshare-gui/src/gui/TheWire/PulseAddDialog.cpp index a23af7f54..9a493b7d0 100644 --- a/retroshare-gui/src/gui/TheWire/PulseAddDialog.cpp +++ b/retroshare-gui/src/gui/TheWire/PulseAddDialog.cpp @@ -24,6 +24,7 @@ #include "PulseAddDialog.h" +const uint32_t PULSE_MAX_SIZE = 1000; // 1k char. /** Constructor */ PulseAddDialog::PulseAddDialog(QWidget *parent) @@ -35,8 +36,9 @@ PulseAddDialog::PulseAddDialog(QWidget *parent) connect(ui.pushButton_Post, SIGNAL( clicked( void ) ), this, SLOT( postPulse( void ) ) ); connect(ui.pushButton_AddURL, SIGNAL( clicked( void ) ), this, SLOT( addURL( void ) ) ); - connect(ui.pushButton_AddTo, SIGNAL( clicked( void ) ), this, SLOT( addTo( void ) ) ); + connect(ui.pushButton_ClearDisplayAs, SIGNAL( clicked( void ) ), this, SLOT( clearDisplayAs( void ) ) ); connect(ui.pushButton_Cancel, SIGNAL( clicked( void ) ), this, SLOT( cancelPulse( void ) ) ); + connect(ui.textEdit_Pulse, SIGNAL( textChanged( void ) ), this, SLOT( pulseTextChanged( void ) ) ); } void PulseAddDialog::setGroup(RsWireGroup &group) @@ -47,11 +49,59 @@ void PulseAddDialog::setGroup(RsWireGroup &group) } +void PulseAddDialog::cleanup() +{ + if (mIsReply) + { + std::cerr << "PulseAddDialog::setReplyTo() cleaning up old replyto"; + std::cerr << std::endl; + QLayout *layout = ui.widget_replyto->layout(); + // completely delete layout and sublayouts + QLayoutItem * item; + QWidget * widget; + while ((item = layout->takeAt(0))) + { + if ((widget = item->widget()) != 0) + { + std::cerr << "PulseAddDialog::setReplyTo() removing widget"; + std::cerr << std::endl; + widget->hide(); + delete widget; + } + else + { + std::cerr << "PulseAddDialog::setReplyTo() removing item"; + std::cerr << std::endl; + delete item; + } + } + // then finally + delete layout; + mIsReply = false; + } + ui.frame_reply->setVisible(false); + ui.comboBox_sentiment->setCurrentIndex(0); + ui.lineEdit_URL->setText(""); + ui.lineEdit_DisplayAs->setText(""); + ui.textEdit_Pulse->setPlainText(""); + ui.pushButton_Post->setEnabled(false); + // disable URL until functionality finished. + ui.frame_URL->setEnabled(false); +} + +void PulseAddDialog::pulseTextChanged() +{ + std::string pulseText = ui.textEdit_Pulse->toPlainText().toStdString(); + bool enable = (pulseText.size() > 0) && (pulseText.size() < PULSE_MAX_SIZE); + ui.pushButton_Post->setEnabled(enable); +} + void PulseAddDialog::setReplyTo(RsWirePulse &pulse, std::string &groupName) { mIsReply = true; mReplyToPulse = pulse; mReplyGroupName = groupName; + ui.frame_reply->setVisible(true); { std::map replies; @@ -75,12 +125,10 @@ void PulseAddDialog::addURL() return; } - -void PulseAddDialog::addTo() +void PulseAddDialog::clearDisplayAs() { - std::cerr << "PulseAddDialog::addTo()"; + std::cerr << "PulseAddDialog::clearDisplayAs()"; std::cerr << std::endl; - return; } @@ -96,7 +144,6 @@ void PulseAddDialog::cancelPulse() return; } - void PulseAddDialog::postPulse() { std::cerr << "PulseAddDialog::postPulse()"; @@ -126,6 +173,7 @@ void PulseAddDialog::postOriginalPulse() pulse.mMeta.mOrigMsgId.clear(); pulse.mPulseType = WIRE_PULSE_TYPE_ORIGINAL_MSG; + pulse.mReplySentiment = WIRE_PULSE_SENTIMENT_NO_SENTIMENT; pulse.mPulseText = ui.textEdit_Pulse->toPlainText().toStdString(); // all mRefs should empty. @@ -136,6 +184,27 @@ void PulseAddDialog::postOriginalPulse() hide(); } +uint32_t PulseAddDialog::toPulseSentiment(int index) +{ + switch(index) + { + case 1: + return WIRE_PULSE_SENTIMENT_POSITIVE; + break; + case 2: + return WIRE_PULSE_SENTIMENT_NEUTRAL; + break; + case 3: + return WIRE_PULSE_SENTIMENT_NEGATIVE; + break; + case -1: + case 0: + default: + return WIRE_PULSE_SENTIMENT_NO_SENTIMENT; + break; + } + return 0; +} void PulseAddDialog::postReplyPulse() { @@ -151,6 +220,7 @@ void PulseAddDialog::postReplyPulse() pulse.mMeta.mOrigMsgId.clear(); pulse.mPulseType = WIRE_PULSE_TYPE_REPLY_MSG; + pulse.mReplySentiment = toPulseSentiment(ui.comboBox_sentiment->currentIndex()); pulse.mPulseText = ui.textEdit_Pulse->toPlainText().toStdString(); // mRefs refer to parent post. @@ -185,6 +255,8 @@ void PulseAddDialog::postRefPulse(RsWirePulse &pulse) refPulse.mMeta.mOrigMsgId.clear(); refPulse.mPulseType = WIRE_PULSE_TYPE_REPLY_REFERENCE; + refPulse.mReplySentiment = toPulseSentiment(ui.comboBox_sentiment->currentIndex()); + // Dont put parent PulseText into refPulse - it is available on Thread Msg. // otherwise gives impression it is correctly setup Parent / Reply... // when in fact the parent PublishTS, and AuthorId are wrong. diff --git a/retroshare-gui/src/gui/TheWire/PulseAddDialog.h b/retroshare-gui/src/gui/TheWire/PulseAddDialog.h index e48ecfeea..0ab3c826a 100644 --- a/retroshare-gui/src/gui/TheWire/PulseAddDialog.h +++ b/retroshare-gui/src/gui/TheWire/PulseAddDialog.h @@ -33,15 +33,17 @@ class PulseAddDialog : public QWidget, public TokenResponse public: PulseAddDialog(QWidget *parent = 0); + void cleanup(); void setGroup(RsWireGroup &group); void setReplyTo(RsWirePulse &pulse, std::string &groupName); private slots: void addURL(); - void addTo(); + void clearDisplayAs(); void postPulse(); void cancelPulse(); void clearDialog(); + void pulseTextChanged(); private: void postOriginalPulse(); @@ -51,6 +53,7 @@ private: void acknowledgeMessage(const uint32_t &token); void loadPulseData(const uint32_t &token); void loadRequest(const TokenQueue *queue, const TokenRequest &req); + uint32_t toPulseSentiment(int index); protected: diff --git a/retroshare-gui/src/gui/TheWire/PulseAddDialog.ui b/retroshare-gui/src/gui/TheWire/PulseAddDialog.ui index cdcbf632c..b87d02794 100644 --- a/retroshare-gui/src/gui/TheWire/PulseAddDialog.ui +++ b/retroshare-gui/src/gui/TheWire/PulseAddDialog.ui @@ -13,9 +13,67 @@ - - - + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 100 + 16777215 + + + + + 12 + 75 + true + + + + Post From: + + + + + + + GroupLabel + + + + + + + IDLabel + + + + + + + + QFrame::StyledPanel @@ -24,50 +82,74 @@ - - - - - In Reply to: - - - - - - - - 11 - 75 - true - - - - Positive / Neutral / Negative - - - - - - - Qt::Horizontal - - - - 238 - 20 - - - - - + - + + + + + + Response Sentiment: + + + + + + + + 0 + 0 + + + + + 150 + 0 + + + + + No Sentiment + + + + + Positive + + + + + Neutral + + + + + Negative + + + + + + + + Qt::Horizontal + + + + 238 + 20 + + + + + + - + QFrame::StyledPanel @@ -79,220 +161,80 @@ - - - - - - - URL Adder - - - - - - Qt::Horizontal - - - - 331 - 24 - - - - - - - - Add to Pulse - - - - - - - Display As - - - - - - - - - - URL - - - - - - - - - - - - - Cancel - - - - - - - Qt::Horizontal - - - - 298 - 24 - - - - - - - - Post Pulse to Wire - - - - - - - Qt::Vertical - - - - - 160 - 16777215 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - 12 - 75 - true - - - - Post From: - - - - - - - GroupLabel - - - - - - - IDLabel - - - - - - - - true - - - - - 0 - 0 - 150 - 423 - - - - - - - Add to Pulse - - - - - - - filter - - - - - - - true - - - - - 0 - 0 - 130 - 341 - + + + + + + + URL - - - - - Account 1 - - - - - - - Account 2 - - - - - - - Account 3 - - - - - - - Qt::Vertical - - - - 20 - 70 - - - - - - - - - - + + + + + + + + Add to Pulse + + + + + + + Display As + + + + + + + + + + Clear Display As + + + + + + + + + + + + + Cancel + + + + + + + Qt::Horizontal + + + + 298 + 24 + + + + + + + + Post Pulse to Wire + + + + + diff --git a/retroshare-gui/src/gui/TheWire/PulseDetails.cpp b/retroshare-gui/src/gui/TheWire/PulseDetails.cpp index 067b1e99e..5cdddad70 100644 --- a/retroshare-gui/src/gui/TheWire/PulseDetails.cpp +++ b/retroshare-gui/src/gui/TheWire/PulseDetails.cpp @@ -92,6 +92,10 @@ void PulseDetails::setup() label_replies->setText(""); frame_replies->setVisible(false); mHasReplies = false; + + toolButton_follow->setEnabled(false); // TODO + toolButton_rate->setEnabled(false); // TODO + toolButton_reply->setEnabled(mActions != NULL); } void PulseDetails::addReplies(std::map replies) @@ -183,18 +187,28 @@ QString PulseDetails::getSummary() void PulseDetails::follow() { // follow group. - mActions->follow(mPulse.mMeta.mGroupId); + if (mActions) + { + mActions->follow(mPulse.mMeta.mGroupId); + } } void PulseDetails::rate() { // rate author - mActions->rate(mPulse.mMeta.mAuthorId); + if (mActions) + { + mActions->rate(mPulse.mMeta.mAuthorId); + } } void PulseDetails::reply() { - mActions->reply(mPulse, mGroupName); + // reply + if (mActions) + { + mActions->reply(mPulse, mGroupName); + } } diff --git a/retroshare-gui/src/gui/TheWire/TheWire_images.qrc b/retroshare-gui/src/gui/TheWire/TheWire_images.qrc index 7919a4500..f6cf0b441 100644 --- a/retroshare-gui/src/gui/TheWire/TheWire_images.qrc +++ b/retroshare-gui/src/gui/TheWire/TheWire_images.qrc @@ -1,15 +1,5 @@ - images/kuickshow.png - images/kview_24.png - images/kview_64.png - images/album_64.png - images/album_subscribe.png - images/album_unsubscribe.png - images/album_create_64.png - images/album_default_128.png - images/my_album_48.png - images/subscribed_album_48.png - images/friends_album_48.png + images/compose.png diff --git a/retroshare-gui/src/gui/TheWire/WireDialog.cpp b/retroshare-gui/src/gui/TheWire/WireDialog.cpp index 6b1cd87ae..19baa25ac 100644 --- a/retroshare-gui/src/gui/TheWire/WireDialog.cpp +++ b/retroshare-gui/src/gui/TheWire/WireDialog.cpp @@ -40,9 +40,10 @@ #define GROUP_SET_ALL (0) #define GROUP_SET_OWN (1) #define GROUP_SET_SUBSCRIBED (2) -#define GROUP_SET_AUTO (3) -#define GROUP_SET_RECOMMENDED (4) -#define GROUP_SET_OTHERS (5) +#define GROUP_SET_OTHERS (3) +// Future Extensions. +// #define GROUP_SET_AUTO (4) +// #define GROUP_SET_RECOMMENDED (5) #define WIRE_TOKEN_TYPE_SUBSCRIBE_CHANGE 1 @@ -56,13 +57,14 @@ WireDialog::WireDialog(QWidget *parent) mAddDialog = NULL; mPulseSelected = NULL; + mGroupSelected = NULL; connect( ui.toolButton_createAccount, SIGNAL(clicked()), this, SLOT(createGroup())); connect( ui.toolButton_createPulse, SIGNAL(clicked()), this, SLOT(createPulse())); - connect( ui.pushButton_Post, SIGNAL(clicked()), this, SLOT(createPulse())); connect( ui.toolButton_refresh, SIGNAL(clicked()), this, SLOT(refreshGroups())); connect(ui.comboBox_groupSet, SIGNAL(currentIndexChanged(int)), this, SLOT(selectGroupSet(int))); + connect(ui.comboBox_filterTime, SIGNAL(currentIndexChanged(int)), this, SLOT(selectFilterTime(int))); QTimer *timer = new QTimer(this); timer->connect(timer, SIGNAL(timeout()), this, SLOT(checkUpdate())); @@ -136,6 +138,7 @@ void WireDialog::reply(RsWirePulse &pulse, std::string &groupName) // publishing group. RsWireGroup group = mOwnGroups[idx]; + mAddDialog->cleanup(); mAddDialog->setGroup(group); // establish replyTo. @@ -177,15 +180,31 @@ void WireDialog::notifyGroupSelection(WireGroupItem *item) std::cerr << "WireDialog::notifyGroupSelection() from : " << item; std::cerr << std::endl; + bool doSelection = true; if (mGroupSelected) { std::cerr << "WireDialog::notifyGroupSelection() unselecting old one : " << mGroupSelected; std::cerr << std::endl; mGroupSelected->setSelected(false); + if (mGroupSelected == item) + { + std::cerr << "WireDialog::notifyGroupSelection() current -> unselect"; + std::cerr << std::endl; + /* de-selection of current item */ + mGroupSelected = NULL; + doSelection = false; + } } - mGroupSelected = item; + if (doSelection) + { + item->setSelected(true); + mGroupSelected = item; + } + + /* update display */ + showSelectedGroups(); } @@ -229,6 +248,7 @@ void WireDialog::createPulse() RsWireGroup group = mOwnGroups[idx]; + mAddDialog->cleanup(); mAddDialog->setGroup(group); mAddDialog->show(); } @@ -320,6 +340,8 @@ void WireDialog::deleteGroups() std::cerr << "WireDialog::deleteGroups()"; std::cerr << std::endl; + mGroupSelected = NULL; + QLayout *alayout = ui.scrollAreaWidgetContents_groups->layout(); QLayoutItem *item; int i = 0; @@ -380,11 +402,39 @@ void WireDialog::selectGroupSet(int index) showGroups(); } +void WireDialog::selectFilterTime(int index) +{ + std::cerr << "WireDialog::selectFilterTime(" << index << ")"; + std::cerr << std::endl; + + showSelectedGroups(); +} + +void WireDialog::showSelectedGroups() +{ + ui.comboBox_filterTime->setEnabled(false); + if (mGroupSelected) + { + deletePulses(); + // request data. + std::list grpIds; + grpIds.push_back(mGroupSelected->groupId()); + requestPulseData(grpIds); + } + else + { + showGroups(); + } +} + void WireDialog::showGroups() { + ui.comboBox_filterTime->setEnabled(false); deleteGroups(); deletePulses(); + + /* depends on the comboBox */ std::map::const_iterator it; for (it = mAllGroups.begin(); it != mAllGroups.end(); it++) @@ -399,12 +449,6 @@ void WireDialog::showGroups() if (mGroupSet == GROUP_SET_SUBSCRIBED) { add = true; } - if (mGroupSet == GROUP_SET_AUTO) { - add = true; - } - if (mGroupSet == GROUP_SET_RECOMMENDED) { - add = true; - } } else { if (mGroupSet == GROUP_SET_OTHERS) { @@ -506,6 +550,29 @@ public: std::map replies; // publish -> replies. }; +rstime_t WireDialog::getFilterTimestamp() +{ + rstime_t filterTimestamp = time(NULL); + switch(ui.comboBox_filterTime->currentIndex()) + { + case 1: // Last 24 Hours. + filterTimestamp -= (3600 * 24); + break; + case 2: // Last 7 Days. + filterTimestamp -= (3600 * 24 * 7); + break; + case 3: // Last 30 Days. + filterTimestamp -= (3600 * 24 * 30); + break; + case 0: // All Time. + case -1: // no index. + default: + filterTimestamp = 0; // back to Epoch! effectively all. + break; + } + return filterTimestamp; +} + bool WireDialog::loadPulseData(const uint32_t &token) { std::cerr << "WireDialog::loadPulseData()"; @@ -517,6 +584,14 @@ bool WireDialog::loadPulseData(const uint32_t &token) std::list references; std::map pulseGrouping; + // setup time filtering. + uint32_t filterTimestamp; + bool filterTime = (ui.comboBox_filterTime->currentIndex() > 0); + if (filterTime) + { + filterTimestamp = getFilterTimestamp(); + } + std::vector::iterator vit = pulses.begin(); for(; vit != pulses.end(); vit++) { @@ -531,6 +606,15 @@ bool WireDialog::loadPulseData(const uint32_t &token) } else { + // Filter timestamp now. (as soon as possible). + if (filterTime && (pulse.mMeta.mPublishTs < filterTimestamp)) + { + std::cerr << "WireDialog::loadPulseData() SKipping OLD MSG: GroupId: " << pulse.mMeta.mGroupId; + std::cerr << " PulseId: " << pulse.mMeta.mMsgId; + std::cerr << std::endl; + continue; + } + RsGxsGroupId &gid = pulse.mMeta.mGroupId; std::map::iterator git = mAllGroups.find(gid); if (git != mAllGroups.end()) @@ -591,6 +675,7 @@ bool WireDialog::loadPulseData(const uint32_t &token) std::map::iterator pgit; for(pgit = pulseGrouping.begin(); pgit != pulseGrouping.end(); pgit++) { + PulseOrderedReply &msg = pulseOrdering[pgit->second.msg->mMeta.mPublishTs] = PulseOrderedReply(pgit->second.msg, pgit->second.group); std::map::iterator rmit; @@ -609,6 +694,8 @@ bool WireDialog::loadPulseData(const uint32_t &token) addPulse(poit->second.msg, poit->second.group, poit->second.replies); } + // allow filterTime to be changed again + ui.comboBox_filterTime->setEnabled(true); return true; } diff --git a/retroshare-gui/src/gui/TheWire/WireDialog.h b/retroshare-gui/src/gui/TheWire/WireDialog.h index b2a9198e0..904c09ade 100644 --- a/retroshare-gui/src/gui/TheWire/WireDialog.h +++ b/retroshare-gui/src/gui/TheWire/WireDialog.h @@ -68,6 +68,7 @@ private slots: void checkUpdate(); void refreshGroups(); void selectGroupSet(int index); + void selectFilterTime(int index); private: @@ -81,8 +82,12 @@ private: void deletePulses(); void deleteGroups(); void showGroups(); + void showSelectedGroups(); void updateGroups(std::vector &groups); + // utils. + rstime_t getFilterTimestamp(); + // Loading Data. void requestGroupData(); bool loadGroupData(const uint32_t &token); diff --git a/retroshare-gui/src/gui/TheWire/WireDialog.ui b/retroshare-gui/src/gui/TheWire/WireDialog.ui index 84f76e5b1..eb1f91d2a 100644 --- a/retroshare-gui/src/gui/TheWire/WireDialog.ui +++ b/retroshare-gui/src/gui/TheWire/WireDialog.ui @@ -19,13 +19,13 @@ - - - + + + 0 - 0 + 1 @@ -40,6 +40,13 @@ Create Account + + + :/icons/png/add.png:/icons/png/add.png + + + Qt::ToolButtonTextBesideIcon + @@ -47,19 +54,12 @@ Post Pulse - - - - - - ... + + + :/images/compose.png:/images/compose.png - - - - - - ... + + Qt::ToolButtonTextBesideIcon @@ -95,6 +95,9 @@ + + false + Settings @@ -103,243 +106,268 @@ - - - - true + + + + + 0 + 100 + - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + Qt::Horizontal - - - - 0 - 0 - 434 - 412 - + + + + 1 + 0 + - - QWidget#scrollAreaWidgetContents{border: none;} + + + 250 + 0 + - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - + + + 400 + 16777215 + + + + QFrame::StyledPanel + + + QFrame::Raised + + - - - Qt::Vertical + + + + All + + + + + Yourself + + + + + Following + + + + + Others + + + + + + + + + 10 + 75 + true + - - - 20 - 40 - + + Who to Follow - + + + + + + true + + + + + 0 + 0 + 228 + 421 + + + + + + + Qt::Vertical + + + + 20 + 116 + + + + + + + - - - - - - - - - - - Search/Filter - - - - - - - Network Wide - - - - - - - - All - - - - - Last Month - - - - - Last Week - - - - - Today - - - - - New - - - - - - - - - from - - - - - until - - - - - - - - TimeRange - - - - - - - - - - - - - 400 - 16777215 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 + + + + 3 + 0 + - - 0 + + QFrame::StyledPanel - - 0 + + QFrame::Raised - - 0 - - - 0 - - - - - true - - - - - 0 - 0 - 262 - 416 - - - + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - + - Qt::Vertical + Qt::Horizontal - 20 - 116 + 40 + 20 + + + + + 0 + 0 + + + + Show Posts from + + + + + + + + 0 + 0 + + + + + All Time + + + + + Last 24 hours + + + + + Last 7 days + + + + + Last 30 days + + + + - - - - - - - - - - All - - - - - Yourself - - - - - Subscribed - - - - - Auto - - - - - Recommended - - - - - Others - - - - - - - - Post Pulse to Wire - + + + + + true + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 0 + 0 + 431 + 443 + + + + QWidget#scrollAreaWidgetContents{border: none;} + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + diff --git a/retroshare-gui/src/gui/TheWire/WireGroupItem.cpp b/retroshare-gui/src/gui/TheWire/WireGroupItem.cpp index d1f2ae1e4..ea771df5f 100644 --- a/retroshare-gui/src/gui/TheWire/WireGroupItem.cpp +++ b/retroshare-gui/src/gui/TheWire/WireGroupItem.cpp @@ -24,6 +24,7 @@ #include #include "WireGroupItem.h" +#include "gui/gxs/GxsIdDetails.h" #include #include @@ -39,11 +40,26 @@ WireGroupItem::WireGroupItem(WireGroupHolder *holder, const RsWireGroup &grp) } +RsGxsGroupId &WireGroupItem::groupId() +{ + return mGroup.mMeta.mGroupId; +} + void WireGroupItem::setup() { label_groupName->setText(QString::fromStdString(mGroup.mMeta.mGroupName)); label_authorId->setId(mGroup.mMeta.mAuthorId); frame_details->setVisible(false); + + RsIdentityDetails idDetails ; + rsIdentity->getIdDetails(mGroup.mMeta.mAuthorId,idDetails); + + QPixmap pixmap ; + + if(idDetails.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idDetails.mAvatar.mData, idDetails.mAvatar.mSize, pixmap,GxsIdDetails::SMALL)) + pixmap = GxsIdDetails::makeDefaultIcon(mGroup.mMeta.mAuthorId,GxsIdDetails::SMALL); + + label_avatar->setPixmap(pixmap); connect(toolButton_show, SIGNAL(clicked()), this, SLOT(show())); connect(toolButton_subscribe, SIGNAL(clicked()), this, SLOT(subscribe())); @@ -59,13 +75,13 @@ void WireGroupItem::setGroupSet() } else if (mGroup.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED) { - toolButton_type->setText("Subcribed"); - toolButton_subscribe->setText("Unsubcribe"); + toolButton_type->setText("Following"); + toolButton_subscribe->setText("Unfollow"); } else { toolButton_type->setText("Other"); - toolButton_subscribe->setText("Subcribe"); + toolButton_subscribe->setText("Follow"); } } @@ -91,8 +107,28 @@ void WireGroupItem::removeItem() { } -void WireGroupItem::setSelected(bool /* on */) +void WireGroupItem::setSelected(bool on) { + mSelected = on; + // set color too + if (mSelected) + { + setBackground("red"); + } + else + { + setBackground("gray"); + } +} + + +void WireGroupItem::setBackground(QString color) +{ + QWidget *tocolor = this; + QPalette p = tocolor->palette(); + p.setColor(tocolor->backgroundRole(), QColor(color)); + tocolor->setPalette(p); + tocolor->setAutoFillBackground(true); } bool WireGroupItem::isSelected() @@ -102,20 +138,14 @@ bool WireGroupItem::isSelected() void WireGroupItem::mousePressEvent(QMouseEvent *event) { - /* We can be very cunning here? - * grab out position. - * flag ourselves as selected. - * then pass the mousePressEvent up for handling by the parent - */ - QPoint pos = event->pos(); std::cerr << "WireGroupItem::mousePressEvent(" << pos.x() << ", " << pos.y() << ")"; std::cerr << std::endl; - setSelected(true); - - QWidget::mousePressEvent(event); + // notify of selection. + // Holder will setSelected() flag. + mHolder->notifyGroupSelection(this); } const QPixmap *WireGroupItem::getPixmap() diff --git a/retroshare-gui/src/gui/TheWire/WireGroupItem.h b/retroshare-gui/src/gui/TheWire/WireGroupItem.h index 82863ea89..7f8643a7e 100644 --- a/retroshare-gui/src/gui/TheWire/WireGroupItem.h +++ b/retroshare-gui/src/gui/TheWire/WireGroupItem.h @@ -50,6 +50,7 @@ public: bool isSelected(); const QPixmap *getPixmap(); + RsGxsGroupId &groupId(); private slots: void show(); @@ -61,6 +62,7 @@ protected: private: void setup(); void setGroupSet(); + void setBackground(QString color); WireGroupHolder *mHolder; RsWireGroup mGroup; diff --git a/retroshare-gui/src/gui/TheWire/WireGroupItem.ui b/retroshare-gui/src/gui/TheWire/WireGroupItem.ui index a71e1ed23..bf1f162a4 100644 --- a/retroshare-gui/src/gui/TheWire/WireGroupItem.ui +++ b/retroshare-gui/src/gui/TheWire/WireGroupItem.ui @@ -25,6 +25,22 @@ + + + + + 32 + 32 + + + + Avatar + + + true + + + diff --git a/retroshare-gui/src/gui/TheWire/images/compose.png b/retroshare-gui/src/gui/TheWire/images/compose.png new file mode 100644 index 000000000..3a033462b Binary files /dev/null and b/retroshare-gui/src/gui/TheWire/images/compose.png differ diff --git a/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp b/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp index 88cef0d3e..d5b4a7f72 100644 --- a/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp +++ b/retroshare-gui/src/gui/WikiPoos/WikiDialog.cpp @@ -87,7 +87,6 @@ WikiDialog::WikiDialog(QWidget *parent) : RsGxsUpdateBroadcastPage(rsWiki, paren mAddGroupDialog = NULL; mEditDialog = NULL; - connect( ui.toolButton_NewGroup, SIGNAL(clicked()), this, SLOT(OpenOrShowAddGroupDialog())); connect( ui.toolButton_NewPage, SIGNAL(clicked()), this, SLOT(OpenOrShowAddPageDialog())); connect( ui.toolButton_Edit, SIGNAL(clicked()), this, SLOT(OpenOrShowEditDialog())); connect( ui.toolButton_Republish, SIGNAL(clicked()), this, SLOT(OpenOrShowRepublishDialog())); @@ -105,15 +104,22 @@ WikiDialog::WikiDialog(QWidget *parent) : RsGxsUpdateBroadcastPage(rsWiki, paren /* setup TokenQueue */ mWikiQueue = new TokenQueue(rsWiki->getTokenService(), this); - // Set initial size of the splitter - ui.listSplitter->setStretchFactor(0, 0); - ui.listSplitter->setStretchFactor(1, 1); + // Set initial size of the splitter + ui.listSplitter->setStretchFactor(0, 0); + ui.listSplitter->setStretchFactor(1, 1); /* Setup Group Tree */ mYourGroups = ui.groupTreeWidget->addCategoryItem(tr("My Groups"), QIcon(), true); mSubscribedGroups = ui.groupTreeWidget->addCategoryItem(tr("Subscribed Groups"), QIcon(), true); mPopularGroups = ui.groupTreeWidget->addCategoryItem(tr("Popular Groups"), QIcon(), false); mOtherGroups = ui.groupTreeWidget->addCategoryItem(tr("Other Groups"), QIcon(), false); + + /* Add the New Group button */ + QToolButton *newGroupButton = new QToolButton(this); + newGroupButton->setIcon(QIcon(":/icons/png/add.png")); + newGroupButton->setToolTip(tr("Create Group")); + connect(newGroupButton, SIGNAL(clicked()), this, SLOT(OpenOrShowAddGroupDialog())); + ui.groupTreeWidget->addToolButton(newGroupButton); // load settings processSettings(true); diff --git a/retroshare-gui/src/gui/WikiPoos/WikiDialog.ui b/retroshare-gui/src/gui/WikiPoos/WikiDialog.ui index edc707eff..7a86e6488 100644 --- a/retroshare-gui/src/gui/WikiPoos/WikiDialog.ui +++ b/retroshare-gui/src/gui/WikiPoos/WikiDialog.ui @@ -36,92 +36,6 @@ 0 - - - - - 16777215 - 30 - - - - QFrame::Box - - - QFrame::Sunken - - - - 2 - - - 2 - - - 2 - - - 2 - - - - - - 24 - 24 - - - - - - - :/icons/png/wiki.png - - - true - - - - - - - - 10 - 75 - true - - - - Wiki Pages - - - - - - - New Group - - - - :/icons/png/add.png:/icons/png/add.png - - - - 24 - 24 - - - - Qt::ToolButtonIconOnly - - - true - - - - - - @@ -133,7 +47,7 @@ 0 0 241 - 480 + 510 diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp index 21784401d..8b5ab7fde 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp @@ -62,7 +62,7 @@ const static uint32_t timeToInactivity = 60 * 10; // in seconds /** Default constructor */ ChatLobbyDialog::ChatLobbyDialog(const ChatLobbyId& lid, QWidget *parent, Qt::WindowFlags flags) - : ChatDialog(parent, flags), lobbyId(lid), + : ChatDialog(parent, flags), lobbyId(lid), mWindowedSetted(false), mPCWindow(nullptr), bullet_red_128(":/icons/bullet_red_128.png"), bullet_grey_128(":/icons/bullet_grey_128.png"), bullet_green_128(":/icons/bullet_green_128.png"), bullet_yellow_128(":/icons/bullet_yellow_128.png") { @@ -129,6 +129,15 @@ ChatLobbyDialog::ChatLobbyDialog(const ChatLobbyId& lid, QWidget *parent, Qt::Wi double scaler_factor = S > 25 ? 2.4 : 1.8; QSize icon_size(scaler_factor * S, scaler_factor * S); + // Add a button to undock dialog. + // + undockButton = new QToolButton; + undockButton->setText(QString()); + undockButton->setAutoRaise(true); + connect(undockButton, SIGNAL(clicked()), this , SLOT(toggleWindowed())); + + getChatWidget()->addTitleBarWidget(undockButton) ; + // Add a button to invite friends. // inviteFriendsButton = new QToolButton ; @@ -201,8 +210,12 @@ ChatLobbyDialog::ChatLobbyDialog(const ChatLobbyId& lid, QWidget *parent, Qt::Wi void ChatLobbyDialog::leaveLobby() { - emit lobbyLeave(id()) ; + emit dialogClose(this); + + if (mPCWindow) + mPCWindow = nullptr;// Windows deleted by events just before. } + void ChatLobbyDialog::inviteFriends() { std::cerr << "Inviting friends" << std::endl; @@ -404,12 +417,8 @@ void ChatLobbyDialog::init(const ChatId &/*id*/, const QString &/*title*/) lastUpdateListTime = 0; - // add to window - - ChatLobbyWidget *chatLobbyPage = dynamic_cast(MainWindow::getPage(MainWindow::ChatLobby)); - if (chatLobbyPage) { - chatLobbyPage->addChatPage(this) ; - } + // add to stacked lobby list + setWindowed(false); /** List of muted Participants */ mutedParticipants.clear() ; @@ -421,11 +430,15 @@ void ChatLobbyDialog::init(const ChatId &/*id*/, const QString &/*title*/) /** Destructor. */ ChatLobbyDialog::~ChatLobbyDialog() { - // announce leaving of lobby - + if (mPCWindow) + { + mPCWindow->removeDialog(this); + mPCWindow = nullptr; + } // check that the lobby still exists. - if (mChatId.isLobbyId()) - rsMsgs->sendLobbyStatusPeerLeaving(mChatId.toLobbyId()); + // announce leaving of lobby + if (mChatId.isLobbyId()) + rsMsgs->sendLobbyStatusPeerLeaving(mChatId.toLobbyId()); // save settings processSettings(false); @@ -910,11 +923,17 @@ void ChatLobbyDialog::showDialog(uint chatflags) { if (chatflags & RS_CHAT_FOCUS) { - MainWindow::showWindow(MainWindow::ChatLobby); - MainPage *p = MainWindow::getPage(MainWindow::ChatLobby); + if (isWindowed() && mPCWindow) { + mPCWindow->showDialog(this, chatflags); + } + else + { + MainWindow::showWindow(MainWindow::ChatLobby); + MainPage *p = MainWindow::getPage(MainWindow::ChatLobby); - if(p != NULL) - dynamic_cast(p)->setCurrentChatPage(this) ; + if(p) + dynamic_cast(p)->setCurrentChatPage(this) ; + } } } @@ -941,3 +960,54 @@ void ChatLobbyDialog::filterIds() ui.participantsList->filterItems(filterColumn, text); } + +void ChatLobbyDialog::setWindowed(bool windowed) +{ + if (mWindowedSetted && (windowed == isWindowed()) ) + { + RsErr() << __PRETTY_FUNCTION__ << " Attempt to set windowed same as last state." << std::endl; + return; + } + mWindowedSetted = true; + // just empiric values + qreal S = QFontMetricsF(font()).height(); + int size = static_cast(S > 25.0 ? 2.4 * S : 1.8 * S); + QSize icon_size(size, size); + + QIcon icon ; + // chatLobbyPage could be NULL for first autosubscribe lobby as Dialog is created before main widget + ChatLobbyWidget *chatLobbyPage = dynamic_cast(MainWindow::getPage(MainWindow::ChatLobby)); + if (!mPCWindow) + mPCWindow = PopupChatWindow::getWindow(true); + + if (windowed) + { + if (chatLobbyPage) + chatLobbyPage->removeChatPage(this); + if (mPCWindow) + mPCWindow->addDialog(this); + + undockButton->setToolTip(tr("Redock to Main window")); + icon.addPixmap(QPixmap(":/icons/png/dock.png")) ; + undockButton->setIcon(icon) ; + undockButton->setIconSize(icon_size); + } + else + { + if (mPCWindow) + { + mPCWindow->removeDialog(this); + mPCWindow = nullptr; + } + if (chatLobbyPage) + chatLobbyPage->addChatPage(this); + + undockButton->setToolTip(tr("Undock to a new window")); + icon.addPixmap(QPixmap(":/icons/png/undock.png")) ; + undockButton->setIcon(icon) ; + undockButton->setIconSize(icon_size); + } + show(); + if (chatLobbyPage)// If not defined, we are on autosubscribe loop of lobby widget constructor. So don't recall it. + showDialog(RS_CHAT_FOCUS); +} diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.h b/retroshare-gui/src/gui/chat/ChatLobbyDialog.h index 688cfb1c9..1f22284f9 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.h +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.h @@ -25,6 +25,7 @@ #include "ui_ChatLobbyDialog.h" #include "gui/common/RSTreeWidgetItem.h" #include "ChatDialog.h" +#include "PopupChatWindow.h" Q_DECLARE_METATYPE(RsGxsId) Q_DECLARE_METATYPE(QList) @@ -51,16 +52,20 @@ public: ChatLobbyId id() const { return lobbyId ;} void sortParcipants(); + inline bool isWindowed() const { return dynamic_cast(this->window()) != nullptr; } + +public slots: + void leaveLobby() ; private slots: void participantsTreeWidgetCustomPopupMenu( QPoint point ); void textBrowserAskContextMenu(QMenu* contextMnu, QString anchorForPosition, const QPoint point); void inviteFriends() ; - void leaveLobby() ; void filterChanged(const QString &text); - void showInPeopleTab(); + void showInPeopleTab(); + void toggleWindowed(){setWindowed(!isWindowed());} + void setWindowed(bool windowed); signals: - void lobbyLeave(ChatLobbyId) ; void typingEventReceived(ChatLobbyId) ; void messageReceived(bool incoming, ChatLobbyId lobby_id, QDateTime time, QString senderName, QString msg) ; void peerJoined(ChatLobbyId) ; @@ -103,9 +108,13 @@ private: RSTreeWidgetItemCompareRole *mParticipantCompareRole ; - QToolButton *inviteFriendsButton ; + QToolButton *undockButton ; + QToolButton *inviteFriendsButton ; QToolButton *unsubscribeButton ; + bool mWindowedSetted; + PopupChatWindow* mPCWindow; + /** Qt Designer generated object */ Ui::ChatLobbyDialog ui; diff --git a/retroshare-gui/src/gui/chat/ChatWidget.ui b/retroshare-gui/src/gui/chat/ChatWidget.ui index d8a4125e0..729e78143 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.ui +++ b/retroshare-gui/src/gui/chat/ChatWidget.ui @@ -324,12 +324,12 @@ border-image: url(:/images/closepressed.png) - + - QFrame::Box + QFrame::NoFrame - QFrame::Sunken + QFrame::Plain @@ -412,7 +412,7 @@ border-image: url(:/images/closepressed.png) - :/icons/png/attach-image.png:/icons/png/attach-image.png + :/icons/png/add-image.png:/icons/png/add-image.png @@ -435,7 +435,7 @@ border-image: url(:/images/closepressed.png) - :/icons/png/attach.png:/icons/png/attach.png + :/icons/png/attachements.png:/icons/png/attachements.png @@ -455,7 +455,7 @@ border-image: url(:/images/closepressed.png) - :/icons/png/settings.png:/icons/png/settings.png + :/icons/png/options2.png:/icons/png/options2.png @@ -537,24 +537,18 @@ border-image: url(:/images/closepressed.png) - - - 14 - 28 - - - - - 14 - 28 - - Qt::NoFocus - - :/images/arrow-left.png:/images/arrow-left.png + + :/icons/png/arrow-left.png:/icons/png/arrow-left.png + + + + 28 + 28 + true @@ -563,24 +557,18 @@ border-image: url(:/images/closepressed.png) - - - 14 - 28 - - - - - 14 - 28 - - Qt::NoFocus - - :/images/arrow-right.png:/images/arrow-right.png + + :/icons/png/arrow-right.png:/icons/png/arrow-right.png + + + + 28 + 28 + true @@ -711,10 +699,10 @@ border-image: url(:/images/closepressed.png) - QFrame::Box + QFrame::NoFrame - QFrame::Sunken + QFrame::Plain @@ -983,7 +971,7 @@ border-image: url(:/images/closepressed.png) - + :/icons/png/addstickers.png:/icons/png/addstickers.png diff --git a/retroshare-gui/src/gui/chat/PopupChatWindow.cpp b/retroshare-gui/src/gui/chat/PopupChatWindow.cpp index 17c2c38c3..6d6502c5f 100644 --- a/retroshare-gui/src/gui/chat/PopupChatWindow.cpp +++ b/retroshare-gui/src/gui/chat/PopupChatWindow.cpp @@ -64,15 +64,13 @@ static PopupChatWindow *instance = NULL; } /** Default constructor */ -PopupChatWindow::PopupChatWindow(bool tabbed, QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, flags) +PopupChatWindow::PopupChatWindow(bool tabbed, QWidget *parent, Qt::WindowFlags flags) + : QMainWindow(parent, flags),tabbedWindow(tabbed),firstShow(true) + , chatDialog(nullptr),mEmptyIcon(nullptr) { /* Invoke Qt Designer generated QObject setup routine */ ui.setupUi(this); - - tabbedWindow = tabbed; - firstShow = true; - chatDialog = NULL; - mEmptyIcon = NULL; + setAttribute(Qt::WA_DeleteOnClose); ui.tabWidget->setVisible(tabbedWindow); @@ -204,15 +202,16 @@ void PopupChatWindow::addDialog(ChatDialog *dialog) if (tabbedWindow) { ui.tabWidget->addDialog(dialog); } else { - ui.horizontalLayout->addWidget(dialog); + ui.chatcentralLayout->addWidget(dialog); dialog->addToParent(this); - ui.horizontalLayout->setContentsMargins(0, 0, 0, 0); - chatId = dialog->getChatId(); + ui.chatcentralLayout->setContentsMargins(0, 0, 0, 0); + chatId = dialog->getChatId(); chatDialog = dialog; calculateStyle(dialog); + calculateTitle(dialog); /* signal toggled is called */ - ui.actionSetOnTop->setChecked(PeerSettings->getPrivateChatOnTop(chatId)); + ui.actionSetOnTop->setChecked(PeerSettings->getPrivateChatOnTop(chatId)); QObject::connect(dialog, SIGNAL(dialogClose(ChatDialog*)), this, SLOT(dialogClose(ChatDialog*))); } @@ -233,14 +232,15 @@ void PopupChatWindow::removeDialog(ChatDialog *dialog) deleteLater(); } } else { - QObject::disconnect(dialog, SIGNAL(dialogClose(ChatDialog*)), this, SLOT(dialogClose(ChatDialog*))); if (chatDialog == dialog) { + QObject::disconnect(dialog, SIGNAL(dialogClose(ChatDialog*)), this, SLOT(dialogClose(ChatDialog*))); saveSettings(); dialog->removeFromParent(this); - ui.horizontalLayout->removeWidget(dialog); - chatDialog = NULL; - chatId = ChatId(); + ui.chatcentralLayout->removeWidget(dialog); + chatDialog = nullptr; + chatId = ChatId(); + close(); deleteLater(); } } diff --git a/retroshare-gui/src/gui/chat/PopupChatWindow.ui b/retroshare-gui/src/gui/chat/PopupChatWindow.ui index f85a570b6..ea6ea79af 100644 --- a/retroshare-gui/src/gui/chat/PopupChatWindow.ui +++ b/retroshare-gui/src/gui/chat/PopupChatWindow.ui @@ -17,7 +17,7 @@ MainWindow - + 5 diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp index aa9dde0ff..1245c80b2 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp @@ -59,6 +59,8 @@ #define MAX_COMMENT_TITLE 32 +static const uint32_t DELAY_BETWEEN_GROUP_STATISTICS_UPDATE = 120; // do not update group statistics more often than once every 2 mins + /* * Transformation Notes: * there are still a couple of things that the new groups differ from Old version. @@ -76,6 +78,9 @@ GxsGroupFrameDialog::GxsGroupFrameDialog(RsGxsIfaceHelper *ifaceImpl, QWidget *p ui = new Ui::GxsGroupFrameDialog(); ui->setupUi(this); + mShouldUpdateMessageSummaryList = true; + mShouldUpdateGroupStatistics = false; + mLastGroupStatisticsUpdateTs=0; mInitialized = false; mDistSyncAllowed = allow_dist_sync; mInFill = false; @@ -182,7 +187,43 @@ void GxsGroupFrameDialog::showEvent(QShowEvent *event) initUi(); } - updateDisplay( mCachedGroupMetas.empty() ); + uint32_t children = mYourGroups->childCount() + mSubscribedGroups->childCount() + mPopularGroups->childCount() + mOtherGroups->childCount(); + + bool empty = mCachedGroupMetas.empty() || children==0; + + updateDisplay( empty ); +} + +void GxsGroupFrameDialog::paintEvent(QPaintEvent *pe) +{ + if(mShouldUpdateMessageSummaryList) + { + if(!mGroupIdsSummaryToUpdate.empty()) + for(auto& group_id: mGroupIdsSummaryToUpdate) + updateMessageSummaryListReal(group_id); + else + updateMessageSummaryListReal(RsGxsGroupId()); + + mShouldUpdateMessageSummaryList = false; + mGroupIdsSummaryToUpdate.clear(); + } + + rstime_t now = time(nullptr); + + if(mShouldUpdateGroupStatistics && now > DELAY_BETWEEN_GROUP_STATISTICS_UPDATE + mLastGroupStatisticsUpdateTs) + { + // This mechanism allows to gather multiple updateGroupStatistics events at once and not send too many of them at the same time. + // it avoids re-loadign all the group everytime a friend sends new statistics. + + for(auto& groupId: mGroupStatisticsToUpdate) + updateGroupStatisticsReal(groupId); + + mShouldUpdateGroupStatistics = false; + mLastGroupStatisticsUpdateTs = time(nullptr); + mGroupStatisticsToUpdate.clear(); + } + + MainPage::paintEvent(pe); } void GxsGroupFrameDialog::processSettings(bool load) @@ -988,6 +1029,18 @@ void GxsGroupFrameDialog::insertGroupsData(const std::listgroupTreeWidget->setUnreadCount(item, mCountChildMsgs ? (stats.mNumThreadMsgsUnread + stats.mNumChildMsgsUnread) : stats.mNumThreadMsgsUnread); + mCachedGroupStats[groupId] = stats; getUserNotify()->updateIcon(); @@ -1103,6 +1163,23 @@ void GxsGroupFrameDialog::updateGroupStatistics(const RsGxsGroupId &groupId) }); } +void GxsGroupFrameDialog::getServiceStatistics(GxsServiceStatistic& stats) const +{ + stats = GxsServiceStatistic(); // clears everything + + for(auto it: mCachedGroupStats) + { + const GxsGroupStatistic& s(it.second); + + stats.mNumMsgs += s.mNumMsgs; + stats.mNumGrps += 1; + stats.mSizeOfMsgs += s.mTotalSizeOfMsgs; + stats.mNumThreadMsgsNew += s.mNumThreadMsgsNew; + stats.mNumThreadMsgsUnread += s.mNumThreadMsgsUnread; + stats.mNumChildMsgsNew += s.mNumChildMsgsNew ; + stats.mNumChildMsgsUnread += s.mNumChildMsgsUnread ; + } +} TurtleRequestId GxsGroupFrameDialog::distantSearch(const QString& search_string) // this should be overloaded in the child class { diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h index 4aef6a6b1..902e49087 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h @@ -29,7 +29,6 @@ #include -#include "util/TokenQueue.h" #include "GxsIdTreeWidgetItem.h" #include "GxsGroupDialog.h" @@ -80,8 +79,11 @@ public: virtual void getGroupList(std::map &groups) ; + void getServiceStatistics(GxsServiceStatistic& stats) const ; + protected: - virtual void showEvent(QShowEvent *event); + virtual void showEvent(QShowEvent *event) override; + virtual void paintEvent(QPaintEvent *pe) override; virtual void updateDisplay(bool complete); const RsGxsGroupId &groupId() { return mGroupId; } @@ -102,6 +104,10 @@ protected: virtual bool getGroupData(std::list& groupInfo) =0; virtual bool getGroupStatistics(const RsGxsGroupId& groupId,GxsGroupStatistic& stat) =0; + + void updateGroupStatisticsReal(const RsGxsGroupId &groupId); + void updateMessageSummaryListReal(RsGxsGroupId groupId); + private slots: void todo(); @@ -173,20 +179,13 @@ private: virtual uint32_t requestGroupSummaryType() { return GXS_REQUEST_TYPE_GROUP_META; } // request only meta data - void requestGroupStatistics(const RsGxsGroupId &groupId); - void loadGroupStatistics(const uint32_t &token); - // subscribe/unsubscribe ack. -// void acknowledgeSubscribeChange(const uint32_t &token); GxsMessageFrameWidget *messageWidget(const RsGxsGroupId &groupId, bool ownTab); GxsMessageFrameWidget *createMessageWidget(const RsGxsGroupId &groupId); GxsCommentDialog *commentWidget(const RsGxsMessageId &msgId); -// void requestGroupSummary_CurrentGroup(const RsGxsGroupId &groupId); -// void loadGroupSummary_CurrentGroup(const uint32_t &token); - protected: void updateSearchResults(); @@ -209,12 +208,23 @@ private: RsGxsGroupId mNavigatePendingGroupId; RsGxsMessageId mNavigatePendingMsgId; + // Message summary list update + + bool mShouldUpdateMessageSummaryList ; // whether we should update the counting for groups. This takes some CPU so we only do it when needed. + std::set mGroupIdsSummaryToUpdate; + + // GroupStatistics update + bool mShouldUpdateGroupStatistics; + rstime_t mLastGroupStatisticsUpdateTs; + std::set mGroupStatisticsToUpdate; + UIStateHelper *mStateHelper; /** Qt Designer generated object */ Ui::GxsGroupFrameDialog *ui; std::map mCachedGroupMetas; + std::map mCachedGroupStats; std::map mSearchGroupsItems ; std::map > mKnownGroups; diff --git a/retroshare-gui/src/gui/gxs/GxsUserNotify.cpp b/retroshare-gui/src/gui/gxs/GxsUserNotify.cpp index bca319e9a..bc1afa1c1 100644 --- a/retroshare-gui/src/gui/gxs/GxsUserNotify.cpp +++ b/retroshare-gui/src/gui/gxs/GxsUserNotify.cpp @@ -22,60 +22,35 @@ //#include "gui/gxs/RsGxsUpdateBroadcastBase.h" #include "retroshare/rsgxsifacehelper.h" +#include "util/qtthreadsutils.h" #define TOKEN_TYPE_STATISTICS 1 -GxsUserNotify::GxsUserNotify(RsGxsIfaceHelper *ifaceImpl, QObject *parent) : - UserNotify(parent), TokenResponse() +GxsUserNotify::GxsUserNotify(RsGxsIfaceHelper *ifaceImpl, const GxsGroupFrameDialog *g,QObject *parent) : UserNotify(parent), mGroupFrameDialog(g) { mNewThreadMessageCount = 0; mNewChildMessageCount = 0; mCountChildMsgs = false; - - mInterface = ifaceImpl; - mTokenService = mInterface->getTokenService(); - mTokenQueue = new TokenQueue(mInterface->getTokenService(), this); - - //mBase = new RsGxsUpdateBroadcastBase(ifaceImpl); - //connect(mBase, SIGNAL(fillDisplay(bool)), this, SLOT(updateIcon())); } -GxsUserNotify::~GxsUserNotify() -{ - if (mTokenQueue) { - delete(mTokenQueue); - } - //if (mBase) { - //delete(mBase); - //} -} +GxsUserNotify::~GxsUserNotify() {} void GxsUserNotify::startUpdate() { mNewThreadMessageCount = 0; mNewChildMessageCount = 0; - uint32_t token; - mTokenService->requestServiceStatistic(token); - mTokenQueue->queueRequest(token, 0, RS_TOKREQ_ANSTYPE_ACK, TOKEN_TYPE_STATISTICS); + + GxsServiceStatistic stats; + mGroupFrameDialog->getServiceStatistics(stats); + + /* Here it goes any code you want to be executed on the Qt Gui + * thread, for example to update the data model with new information + * after a blocking call to RetroShare API complete */ + + mNewThreadMessageCount = stats.mNumThreadMsgsNew; + mNewChildMessageCount = stats.mNumChildMsgsNew; + + update(); } -void GxsUserNotify::loadRequest(const TokenQueue *queue, const TokenRequest &req) -{ - if (queue == mTokenQueue) { - /* now switch on req */ - switch(req.mUserType) { - case TOKEN_TYPE_STATISTICS: - { - GxsServiceStatistic stats; - mInterface->getServiceStatistic(req.mToken, stats); - - mNewThreadMessageCount = stats.mNumThreadMsgsNew; - mNewChildMessageCount = stats.mNumChildMsgsNew; - - update(); - } - break; - } - } -} diff --git a/retroshare-gui/src/gui/gxs/GxsUserNotify.h b/retroshare-gui/src/gui/gxs/GxsUserNotify.h index c4dca9995..f9c5cd616 100644 --- a/retroshare-gui/src/gui/gxs/GxsUserNotify.h +++ b/retroshare-gui/src/gui/gxs/GxsUserNotify.h @@ -23,22 +23,20 @@ #include #include "gui/common/UserNotify.h" +#include "gui/gxs/GxsGroupFrameDialog.h" #include "util/TokenQueue.h" struct RsGxsIfaceHelper; class RsGxsUpdateBroadcastBase; -class GxsUserNotify : public UserNotify, public TokenResponse +class GxsUserNotify : public UserNotify { Q_OBJECT public: - GxsUserNotify(RsGxsIfaceHelper *ifaceImpl, QObject *parent = 0); + GxsUserNotify(RsGxsIfaceHelper *ifaceImpl, const GxsGroupFrameDialog *g, QObject *parent = 0); virtual ~GxsUserNotify(); - /* TokenResponse */ - virtual void loadRequest(const TokenQueue *queue, const TokenRequest &req); - protected: virtual void startUpdate(); @@ -49,10 +47,9 @@ protected: bool mCountChildMsgs; // Count new child messages? private: - RsGxsIfaceHelper *mInterface; - RsTokenService *mTokenService; - TokenQueue *mTokenQueue; RsGxsUpdateBroadcastBase *mBase; + const GxsGroupFrameDialog *mGroupFrameDialog; + unsigned int mNewThreadMessageCount; unsigned int mNewChildMessageCount; }; diff --git a/retroshare-gui/src/gui/gxs/WikiGroupDialog.cpp b/retroshare-gui/src/gui/gxs/WikiGroupDialog.cpp index 79b9548d4..a502c79bf 100644 --- a/retroshare-gui/src/gui/gxs/WikiGroupDialog.cpp +++ b/retroshare-gui/src/gui/gxs/WikiGroupDialog.cpp @@ -24,32 +24,32 @@ #include const uint32_t WikiCreateEnabledFlags = ( - GXS_GROUP_FLAGS_NAME | - // GXS_GROUP_FLAGS_ICON | - GXS_GROUP_FLAGS_DESCRIPTION | - GXS_GROUP_FLAGS_DISTRIBUTION | - // GXS_GROUP_FLAGS_PUBLISHSIGN | - GXS_GROUP_FLAGS_SHAREKEYS | - // GXS_GROUP_FLAGS_PERSONALSIGN | - // GXS_GROUP_FLAGS_COMMENTS | - 0); + GXS_GROUP_FLAGS_NAME | + // GXS_GROUP_FLAGS_ICON | + GXS_GROUP_FLAGS_DESCRIPTION | + GXS_GROUP_FLAGS_DISTRIBUTION | + // GXS_GROUP_FLAGS_PUBLISHSIGN | + GXS_GROUP_FLAGS_SHAREKEYS | + // GXS_GROUP_FLAGS_PERSONALSIGN | + // GXS_GROUP_FLAGS_COMMENTS | + 0); uint32_t WikiCreateDefaultsFlags = ( GXS_GROUP_DEFAULTS_DISTRIB_PUBLIC | - //GXS_GROUP_DEFAULTS_DISTRIB_GROUP | - //GXS_GROUP_DEFAULTS_DISTRIB_LOCAL | + //GXS_GROUP_DEFAULTS_DISTRIB_GROUP | + //GXS_GROUP_DEFAULTS_DISTRIB_LOCAL | - GXS_GROUP_DEFAULTS_PUBLISH_OPEN | - //GXS_GROUP_DEFAULTS_PUBLISH_THREADS | - //GXS_GROUP_DEFAULTS_PUBLISH_REQUIRED | - //GXS_GROUP_DEFAULTS_PUBLISH_ENCRYPTED | + GXS_GROUP_DEFAULTS_PUBLISH_OPEN | + //GXS_GROUP_DEFAULTS_PUBLISH_THREADS | + //GXS_GROUP_DEFAULTS_PUBLISH_REQUIRED | + //GXS_GROUP_DEFAULTS_PUBLISH_ENCRYPTED | - //GXS_GROUP_DEFAULTS_PERSONAL_GPG | - GXS_GROUP_DEFAULTS_PERSONAL_REQUIRED | - //GXS_GROUP_DEFAULTS_PERSONAL_IFNOPUB | + //GXS_GROUP_DEFAULTS_PERSONAL_GPG | + GXS_GROUP_DEFAULTS_PERSONAL_REQUIRED | + //GXS_GROUP_DEFAULTS_PERSONAL_IFNOPUB | - //GXS_GROUP_DEFAULTS_COMMENTS_YES | - GXS_GROUP_DEFAULTS_COMMENTS_NO | - 0); + //GXS_GROUP_DEFAULTS_COMMENTS_YES | + GXS_GROUP_DEFAULTS_COMMENTS_NO | + 0); uint32_t WikiEditDefaultsFlags = WikiCreateDefaultsFlags; uint32_t WikiEditEnabledFlags = WikiCreateEnabledFlags; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp index 3d19f00f9..70f3de04a 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp @@ -64,10 +64,10 @@ void GxsChannelDialog::handleEvent_main_thread(std::shared_ptr ev switch(e->mChannelEventCode) { - case RsChannelEventCode::NEW_MESSAGE: - case RsChannelEventCode::UPDATED_MESSAGE: // [[fallthrough]]; - case RsChannelEventCode::READ_STATUS_CHANGED: - updateMessageSummaryList(e->mChannelGroupId); + case RsChannelEventCode::NEW_MESSAGE: // [[fallthrough]]; + case RsChannelEventCode::UPDATED_MESSAGE: // [[fallthrough]]; + case RsChannelEventCode::READ_STATUS_CHANGED: // [[fallthrough]]; + updateGroupStatisticsReal(e->mChannelGroupId); // update the list immediately break; case RsChannelEventCode::RECEIVED_DISTANT_SEARCH_RESULT: @@ -80,6 +80,10 @@ void GxsChannelDialog::handleEvent_main_thread(std::shared_ptr ev updateDisplay(true); break; + case RsChannelEventCode::STATISTICS_CHANGED: + updateGroupStatistics(e->mChannelGroupId); + break; + default: break; } @@ -109,7 +113,7 @@ QString GxsChannelDialog::getHelpString() const UserNotify *GxsChannelDialog::createUserNotify(QObject *parent) { - return new GxsChannelUserNotify(rsGxsChannels, parent); + return new GxsChannelUserNotify(rsGxsChannels,this, parent); } void GxsChannelDialog::shareOnChannel(const RsGxsGroupId& channel_id,const QList& file_links) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.cpp index aa82953ed..eb54a39c3 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.cpp @@ -18,11 +18,12 @@ * * *******************************************************************************/ +#include "retroshare/rsgxschannels.h" #include "GxsChannelUserNotify.h" #include "gui/MainWindow.h" -GxsChannelUserNotify::GxsChannelUserNotify(RsGxsIfaceHelper *ifaceImpl, QObject *parent) : - GxsUserNotify(ifaceImpl, parent) +GxsChannelUserNotify::GxsChannelUserNotify(RsGxsIfaceHelper *ifaceImpl, const GxsGroupFrameDialog *g, QObject *parent) : + GxsUserNotify(ifaceImpl, g, parent) { } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.h b/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.h index d36b92bd7..df29a0202 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelUserNotify.h @@ -22,13 +22,14 @@ #define GXSCHANNELUSERNOTIFY_H #include "gui/gxs/GxsUserNotify.h" +#include "gui/gxs/GxsGroupFrameDialog.h" class GxsChannelUserNotify : public GxsUserNotify { Q_OBJECT public: - GxsChannelUserNotify(RsGxsIfaceHelper *ifaceImpl, QObject *parent = 0); + GxsChannelUserNotify(RsGxsIfaceHelper *ifaceImpl, const GxsGroupFrameDialog *g, QObject *parent = 0); virtual bool hasSetting(QString *name, QString *group); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index e126e55d4..83b7acac5 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -1214,7 +1214,7 @@ void RsGxsForumModel::setMsgReadStatus(const QModelIndex& i,bool read_status,boo if(!i.isValid()) return ; - preMods(); + // no need to call preMods()/postMods() here because we'renot changing the model void *ref = i.internalPointer(); uint32_t entry = 0; @@ -1226,34 +1226,46 @@ void RsGxsForumModel::setMsgReadStatus(const QModelIndex& i,bool read_status,boo recursSetMsgReadStatus(entry,read_status,with_children) ; recursUpdateReadStatusAndTimes(0,has_unread_below,has_read_below); - postMods(); + // Normally we should only update the parents up to the top of the tree, but it's complicated and the update here doesn't really cost, + // so we blindly update the whole widget. + + if(mTreeMode == TREE_MODE_FLAT) + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mPosts.size(),COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); + else + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mPosts[0].mChildren.size(),COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); + } void RsGxsForumModel::recursSetMsgReadStatus(ForumModelIndex i,bool read_status,bool with_children) { - if(read_status) - mPosts[i].mMsgStatus = 0; - else - mPosts[i].mMsgStatus = GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD; + int newStatus = (read_status ? mPosts[i].mMsgStatus & ~static_cast(GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD) + : mPosts[i].mMsgStatus | static_cast(GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD)); + bool bChanged = (mPosts[i].mMsgStatus != newStatus); + mPosts[i].mMsgStatus = newStatus; + //Remove Unprocessed and New flags + mPosts[i].mMsgStatus &= ~(GXS_SERV::GXS_MSG_STATUS_UNPROCESSED | GXS_SERV::GXS_MSG_STATUS_GUI_NEW); - uint32_t token; + if (bChanged) + { + //Don't recurs post versions as this should be done before, if no change. + uint32_t token; + auto s = getPostVersions(mPosts[i].mMsgId) ; - auto s = getPostVersions(mPosts[i].mMsgId) ; + if(!s.empty()) + for(auto it(s.begin());it!=s.end();++it) + { + rsGxsForums->setMessageReadStatus(token,std::make_pair( mForumGroup.mMeta.mGroupId, it->second ), read_status); + std::cerr << "Setting version " << it->second << " of post " << mPosts[i].mMsgId << " as read." << std::endl; + } + else + rsGxsForums->setMessageReadStatus(token,std::make_pair( mForumGroup.mMeta.mGroupId, mPosts[i].mMsgId ), read_status); + } - if(!s.empty()) - for(auto it(s.begin());it!=s.end();++it) - { - rsGxsForums->setMessageReadStatus(token,std::make_pair( mForumGroup.mMeta.mGroupId, it->second ), read_status); - std::cerr << "Setting version " << it->second << " of post " << mPosts[i].mMsgId << " as read." << std::endl; - } - else - rsGxsForums->setMessageReadStatus(token,std::make_pair( mForumGroup.mMeta.mGroupId, mPosts[i].mMsgId ), read_status); + if(!with_children) + return; - if(!with_children) - return; - - for(uint32_t j=0;jlineLeft->hide(); ui->by_text_label->hide(); ui->by_label->hide(); + ui->postText->setImageBlockWidget(ui->imageBlockWidget) ; + ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages()); // add/show combobox for versions, if applicable, and enable it. If no older versions of the post available, hide the combobox. @@ -1726,6 +1728,7 @@ void GxsForumThreadWidget::postForumLoading() recursRestoreExpandedItems(mThreadProxyModel->mapFromSource(mThreadModel->root()),mSavedExpandedMessages); //mUpdating = false; } + void GxsForumThreadWidget::updateGroupData() { if(groupId().isNull()) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.cpp index 8a910659a..876aa3a95 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.cpp @@ -18,11 +18,12 @@ * * *******************************************************************************/ +#include "retroshare/rsgxsforums.h" #include "GxsForumUserNotify.h" #include "gui/MainWindow.h" -GxsForumUserNotify::GxsForumUserNotify(RsGxsIfaceHelper *ifaceImpl, QObject *parent) : - GxsUserNotify(ifaceImpl, parent) +GxsForumUserNotify::GxsForumUserNotify(RsGxsIfaceHelper *ifaceImpl, const GxsGroupFrameDialog *g, QObject *parent) : + GxsUserNotify(ifaceImpl, g, parent) { mCountChildMsgs = true; } diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.h b/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.h index 190f177e7..172a327ae 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumUserNotify.h @@ -28,7 +28,7 @@ class GxsForumUserNotify : public GxsUserNotify Q_OBJECT public: - GxsForumUserNotify(RsGxsIfaceHelper *ifaceImpl, QObject *parent = 0); + GxsForumUserNotify(RsGxsIfaceHelper *ifaceImpl, const GxsGroupFrameDialog *g, QObject *parent = 0); virtual bool hasSetting(QString *name, QString *group); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.cpp index d8d300dde..1b0a36c6f 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.cpp @@ -62,13 +62,18 @@ void GxsForumsDialog::handleEvent_main_thread(std::shared_ptr eve case RsForumEventCode::NEW_MESSAGE: case RsForumEventCode::UPDATED_MESSAGE: // [[fallthrough]]; case RsForumEventCode::READ_STATUS_CHANGED: - updateMessageSummaryList(e->mForumGroupId); + updateGroupStatisticsReal(e->mForumGroupId); // update the list immediately break; case RsForumEventCode::NEW_FORUM: // [[fallthrough]]; case RsForumEventCode::SUBSCRIBE_STATUS_CHANGED: updateDisplay(true); break; + + case RsForumEventCode::STATISTICS_CHANGED: + updateGroupStatistics(e->mForumGroupId); // update the list when redraw less often than once every 2 mins + break; + default: break; } @@ -133,7 +138,7 @@ void GxsForumsDialog::shareInMessage(const RsGxsGroupId& forum_id,const QListicons/png/chat-lobbies.png icons/png/circles.png icons/png/digital-key.png + icons/png/dock.png icons/png/empty-circle.png icons/png/enter.png icons/png/exit.png @@ -121,6 +122,7 @@ icons/png/thumbs-neutral.png icons/png/thumbs-up.png icons/png/typing.png + icons/png/undock.png icons/png/video.png icons/quit_128.png icons/search_red_128.png diff --git a/retroshare-gui/src/gui/icons/png/addstickers.png b/retroshare-gui/src/gui/icons/png/addstickers.png index 91c4ee4c3..093a92c28 100644 Binary files a/retroshare-gui/src/gui/icons/png/addstickers.png and b/retroshare-gui/src/gui/icons/png/addstickers.png differ diff --git a/retroshare-gui/src/gui/icons/png/dock.png b/retroshare-gui/src/gui/icons/png/dock.png new file mode 100644 index 000000000..2e191961b Binary files /dev/null and b/retroshare-gui/src/gui/icons/png/dock.png differ diff --git a/retroshare-gui/src/gui/icons/png/highlight.png b/retroshare-gui/src/gui/icons/png/highlight.png index 93ba8f9af..040a2c330 100644 Binary files a/retroshare-gui/src/gui/icons/png/highlight.png and b/retroshare-gui/src/gui/icons/png/highlight.png differ diff --git a/retroshare-gui/src/gui/icons/png/search.png b/retroshare-gui/src/gui/icons/png/search.png index 5cd7be556..e05042694 100644 Binary files a/retroshare-gui/src/gui/icons/png/search.png and b/retroshare-gui/src/gui/icons/png/search.png differ diff --git a/retroshare-gui/src/gui/icons/png/send-message-blocked.png b/retroshare-gui/src/gui/icons/png/send-message-blocked.png index c344e8820..6a68824b1 100644 Binary files a/retroshare-gui/src/gui/icons/png/send-message-blocked.png and b/retroshare-gui/src/gui/icons/png/send-message-blocked.png differ diff --git a/retroshare-gui/src/gui/icons/png/send-message.png b/retroshare-gui/src/gui/icons/png/send-message.png index 4aaece137..7b6895d33 100644 Binary files a/retroshare-gui/src/gui/icons/png/send-message.png and b/retroshare-gui/src/gui/icons/png/send-message.png differ diff --git a/retroshare-gui/src/gui/icons/png/smiley.png b/retroshare-gui/src/gui/icons/png/smiley.png index 12e7f869d..eb6d3292c 100644 Binary files a/retroshare-gui/src/gui/icons/png/smiley.png and b/retroshare-gui/src/gui/icons/png/smiley.png differ diff --git a/retroshare-gui/src/gui/icons/png/undock.png b/retroshare-gui/src/gui/icons/png/undock.png new file mode 100644 index 000000000..10052db9a Binary files /dev/null and b/retroshare-gui/src/gui/icons/png/undock.png differ diff --git a/retroshare-gui/src/gui/icons/svg/dock.svg b/retroshare-gui/src/gui/icons/svg/dock.svg new file mode 100644 index 000000000..2847da24c --- /dev/null +++ b/retroshare-gui/src/gui/icons/svg/dock.svg @@ -0,0 +1,95 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/retroshare-gui/src/gui/icons/svg/highlight.svg b/retroshare-gui/src/gui/icons/svg/highlight.svg index 63ceeaae8..c2d5a7406 100644 --- a/retroshare-gui/src/gui/icons/svg/highlight.svg +++ b/retroshare-gui/src/gui/icons/svg/highlight.svg @@ -11,7 +11,7 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg4155" version="1.1" - inkscape:version="0.91 r13725" + inkscape:version="0.92.4 (5da689c313, 2019-01-14)" xml:space="preserve" width="80" height="80" @@ -19,7 +19,7 @@ sodipodi:docname="highlight.svg">image/svg+xml \ No newline at end of file + style="fill:#039bd5;fill-opacity:1" /> \ No newline at end of file diff --git a/retroshare-gui/src/gui/icons/svg/search.svg b/retroshare-gui/src/gui/icons/svg/search.svg index 811707601..f1acaa561 100644 --- a/retroshare-gui/src/gui/icons/svg/search.svg +++ b/retroshare-gui/src/gui/icons/svg/search.svg @@ -11,12 +11,15 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg4925" version="1.1" - inkscape:version="0.91 r13725" + inkscape:version="0.92.4 (5da689c313, 2019-01-14)" xml:space="preserve" width="80" height="80" viewBox="0 0 80 80" - sodipodi:docname="search.svg">image/svg+xml \ No newline at end of file + style="fill:#039bd5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.43466902" + d="m 26.664851,59.401639 c -5.582296,0 -10.830601,-2.174527 -14.777662,-6.121445 -8.1483473,-8.148489 -8.1483473,-21.406839 0,-29.555327 3.947061,-3.947635 9.195366,-6.121446 14.777662,-6.121446 5.582441,0 10.830747,2.173811 14.777665,6.121446 8.148488,8.148488 8.148488,21.406838 0,29.555327 -3.946918,3.946918 -9.195224,6.121445 -14.777665,6.121445 z m 0,-5.738675 c 3.879776,0 7.759551,-1.480721 10.719703,-4.440874 5.920879,-5.920162 5.920879,-15.518958 0,-21.439263 -2.960152,-2.960726 -6.839927,-4.440731 -10.719703,-4.440731 -3.879774,0 -7.75955,1.480005 -10.719558,4.440731 -5.920879,5.920305 -5.920879,15.519101 0,21.439263 2.960008,2.960153 6.839784,4.440874 10.719558,4.440874" /> \ No newline at end of file diff --git a/retroshare-gui/src/gui/icons/svg/undock.svg b/retroshare-gui/src/gui/icons/svg/undock.svg new file mode 100644 index 000000000..1c8d25c50 --- /dev/null +++ b/retroshare-gui/src/gui/icons/svg/undock.svg @@ -0,0 +1,95 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/retroshare-gui/src/gui/images.qrc b/retroshare-gui/src/gui/images.qrc index 5676c0e7b..f33664066 100644 --- a/retroshare-gui/src/gui/images.qrc +++ b/retroshare-gui/src/gui/images.qrc @@ -331,7 +331,6 @@ images/mimetypes/source_c.png images/mimetypes/source_cpp.png images/mimetypes/source_h.png - images/toaster/backgroundtoaster.png images/thumb-default-video.png images/user/add_user24.png images/user/add_user48.png diff --git a/retroshare-gui/src/gui/images/toaster/backgroundtoaster.png b/retroshare-gui/src/gui/images/toaster/backgroundtoaster.png deleted file mode 100644 index 96b7a2f5c..000000000 Binary files a/retroshare-gui/src/gui/images/toaster/backgroundtoaster.png and /dev/null differ diff --git a/retroshare-gui/src/gui/images/toaster/backgroundtoasterblue.png b/retroshare-gui/src/gui/images/toaster/backgroundtoasterblue.png deleted file mode 100644 index 71f57408d..000000000 Binary files a/retroshare-gui/src/gui/images/toaster/backgroundtoasterblue.png and /dev/null differ diff --git a/retroshare-gui/src/gui/msgs/MessageWidget.cpp b/retroshare-gui/src/gui/msgs/MessageWidget.cpp index a37924c43..001866927 100644 --- a/retroshare-gui/src/gui/msgs/MessageWidget.cpp +++ b/retroshare-gui/src/gui/msgs/MessageWidget.cpp @@ -132,6 +132,7 @@ MessageWidget::MessageWidget(bool controlled, QWidget *parent, Qt::WindowFlags f isControlled = controlled; isWindow = false; currMsgFlags = 0; + expandFiles = false; ui.actionTextBesideIcon->setData(Qt::ToolButtonTextBesideIcon); ui.actionIconOnly->setData(Qt::ToolButtonIconOnly); @@ -281,10 +282,7 @@ void MessageWidget::processSettings(const QString &settingsGroup, bool load) // load settings // expandFiles - bool value = Settings->value("expandFiles", false).toBool(); - ui.expandFilesButton->setChecked(value); - ui.msgList->setVisible(value); - togglefileview(); + expandFiles = Settings->value("expandFiles", false).toBool(); // toolbar button style Qt::ToolButtonStyle style = (Qt::ToolButtonStyle) Settings->value("ToolButon_Style", Qt::ToolButtonTextBesideIcon).toInt(); @@ -293,7 +291,7 @@ void MessageWidget::processSettings(const QString &settingsGroup, bool load) // save settings // expandFiles - Settings->setValue("expandFiles", ui.expandFilesButton->isChecked()); + Settings->setValue("expandFiles", expandFiles); //toolbar button style Settings->setValue("ToolButon_Style", ui.replyButton->toolButtonStyle()); @@ -322,7 +320,7 @@ void MessageWidget::msgfilelistWidgetCostumPopupMenu( QPoint /*point*/ ) contextMnu.exec(QCursor::pos()); } -void MessageWidget::togglefileview() +void MessageWidget::togglefileview(bool noUpdate/*=false*/) { /* if msg header visible -> change icon and tooltip * three widgets... @@ -335,6 +333,10 @@ void MessageWidget::togglefileview() ui.expandFilesButton->setIcon(QIcon(QString(":/icons/png/up-arrow.png"))); ui.expandFilesButton->setToolTip(tr("Show the attachment pane")); } + if (!noUpdate) + expandFiles = ui.expandFilesButton->isChecked(); + + ui.msgList->setVisible(ui.expandFilesButton->isChecked()); } /* download the recommendations... */ @@ -426,13 +428,10 @@ void MessageWidget::messagesChanged() void MessageWidget::clearTagLabels() { /* clear all tags */ - while (tagLabels.size()) { - delete tagLabels.front(); - tagLabels.pop_front(); - } - while (ui.tagLayout->count()) { - delete ui.tagLayout->takeAt(0); - } + qDeleteAll(tagLabels); + tagLabels.clear(); + + misc::clearLayout(ui.tagLayout); ui.tagsLabel->setVisible(false); } @@ -510,6 +509,16 @@ void MessageWidget::fill(const std::string &msgId) clearTagLabels(); + ui.inviteFrame->hide(); + ui.expandFilesButton->setChecked(false); + togglefileview(true); + + ui.replyButton->setEnabled(false); + ui.replyallButton->setEnabled(false); + ui.forwardButton->setEnabled(false); + ui.deleteButton->setEnabled(false); + ui.moreButton->setEnabled(false); + currMsgFlags = 0; return; @@ -517,6 +526,13 @@ void MessageWidget::fill(const std::string &msgId) clearTagLabels(); + + ui.replyButton->setEnabled(true); + ui.replyallButton->setEnabled(true); + ui.forwardButton->setEnabled(true); + ui.deleteButton->setEnabled(true); + ui.moreButton->setEnabled(true); + MessageInfo msgInfo; if (rsMail->getMessage(currMsgId, msgInfo) == false) { std::cerr << "MessageWidget::fill() Couldn't find Msg" << std::endl; @@ -549,6 +565,8 @@ void MessageWidget::fill(const std::string &msgId) /* add the items in! */ ui.msgList->insertTopLevelItems(0, items); + ui.expandFilesButton->setChecked(expandFiles && (items.count()>0) ); + togglefileview(true); /* iterate through the sources */ RetroShareLink link; @@ -688,8 +706,15 @@ void MessageWidget::remove() if (isWindow) { window()->close(); } else { - deleteLater(); + if (isControlled) { + currMsgId.clear(); + fill(currMsgId); + } else { + deleteLater(); + } } + + emit messageRemoved(); } void MessageWidget::print() diff --git a/retroshare-gui/src/gui/msgs/MessageWidget.h b/retroshare-gui/src/gui/msgs/MessageWidget.h index 4bce2466f..2bd630cb3 100644 --- a/retroshare-gui/src/gui/msgs/MessageWidget.h +++ b/retroshare-gui/src/gui/msgs/MessageWidget.h @@ -58,6 +58,8 @@ public: QString subject(bool noEmpty); +signals: + void messageRemoved(); private slots: void reply(); @@ -75,7 +77,7 @@ private slots: void messagesTagsChanged(); void messagesChanged(); - void togglefileview(); + void togglefileview(bool noUpdate = false); void getcurrentrecommended(); void getallrecommended(); @@ -94,6 +96,7 @@ private: bool isWindow; std::string currMsgId; unsigned int currMsgFlags; + bool expandFiles; QList tagLabels; diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp index 6fc76ed79..f31748f4b 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp @@ -124,9 +124,11 @@ MessagesDialog::MessagesDialog(QWidget *parent) inProcessSettings = false; inChange = false; lockUpdate = 0; + lastSelectedIndex = QModelIndex(); msgWidget = new MessageWidget(true, this); ui.msgLayout->addWidget(msgWidget); + connect(msgWidget, SIGNAL(messageRemoved()), this, SLOT(messageRemoved())); connectActions(); @@ -695,6 +697,7 @@ void MessagesDialog::openAsWindow() } msgWidget->activateWindow(); + connect(msgWidget, SIGNAL(messageRemoved()), this, SLOT(messageRemoved())); /* window will destroy itself! */ } @@ -714,6 +717,7 @@ void MessagesDialog::openAsTab() ui.tabWidget->addTab(msgWidget, msgWidget->subject(true)); ui.tabWidget->setCurrentWidget(msgWidget); + connect(msgWidget, SIGNAL(messageRemoved()), this, SLOT(messageRemoved())); /* window will destroy itself! */ } @@ -860,7 +864,8 @@ void MessagesDialog::clicked(const QModelIndex& proxy_index) case RsMessageModel::COLUMN_THREAD_READ: { mMessageModel->setMsgReadStatus(real_index, !isMessageRead(proxy_index)); - insertMsgTxtAndFiles(proxy_index); + //Already updated by currentChanged + //insertMsgTxtAndFiles(proxy_index); updateMessageSummaryList(); return; } @@ -871,8 +876,9 @@ void MessagesDialog::clicked(const QModelIndex& proxy_index) } } - // show current message directly - insertMsgTxtAndFiles(proxy_index); + // show current message directly + //Already updated by currentChanged + //insertMsgTxtAndFiles(proxy_index); } // double click in messageTreeWidget @@ -953,14 +959,20 @@ void MessagesDialog::insertMsgTxtAndFiles(const QModelIndex& proxy_index) QModelIndex real_index = mMessageProxyModel->mapToSource(proxy_index); - if(!real_index.isValid()) + if(!real_index.isValid()) { mCurrMsgId.clear(); msgWidget->fill(mCurrMsgId); updateInterface(); + lastSelectedIndex = QModelIndex(); return; } - mid = real_index.data(RsMessageModel::MsgIdRole).toString().toStdString(); + + lastSelectedIndex = proxy_index; + if (!ui.messageTreeWidget->indexBelow(proxy_index).isValid()) + lastSelectedIndex = ui.messageTreeWidget->indexAbove(proxy_index); + + mid = real_index.data(RsMessageModel::MsgIdRole).toString().toStdString(); /* Save the Data.... for later */ @@ -1025,6 +1037,12 @@ void MessagesDialog::removemessage() mMessageModel->updateMessages(); updateMessageSummaryList(); + messageRemoved(); +} + +void MessagesDialog::messageRemoved() +{ + ui.messageTreeWidget->setCurrentIndex(lastSelectedIndex); } void MessagesDialog::undeletemessage() diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.h b/retroshare-gui/src/gui/msgs/MessagesDialog.h index 57f935783..766268a79 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.h +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.h @@ -57,10 +57,6 @@ public: void setTextColorInbox(QColor color) { mTextColorInbox = color; } -signals: - void messagesAboutToLoad(); - void messagesLoaded(); - protected: virtual UserNotify *createUserNotify(QObject *parent) override; bool eventFilter(QObject *obj, QEvent *ev); @@ -69,6 +65,7 @@ protected: public slots: //void insertMessages(); void messagesTagsChanged(); + void messageRemoved(); void preModelUpdate(); void postModelUpdate(); @@ -156,6 +153,7 @@ private: Ui::MessagesDialog ui; QList mTmpSavedSelectedIds; + QModelIndex lastSelectedIndex; }; #endif diff --git a/retroshare-gui/src/gui/qss/stylesheet/Standard.qss b/retroshare-gui/src/gui/qss/stylesheet/Standard.qss index 6fa73f661..2fbfb1151 100644 --- a/retroshare-gui/src/gui/qss/stylesheet/Standard.qss +++ b/retroshare-gui/src/gui/qss/stylesheet/Standard.qss @@ -225,9 +225,8 @@ ChatWidget QFrame#infoFrame { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFFFD7, stop:1 #FFFFB2); } -ChatWidget QFrame#titleBarFrame { - background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FEFEFE, stop:1 #E8E8E8); - border: 1px solid #CCCCCC; +ChatWidget QFrame#titleBarFrame, QFrame#toolBarFrameTop { + } PopupChatWindow QToolBar#chattoolBar{ @@ -242,8 +241,8 @@ MessageComposer QToolBar#toolBar { } MessagesDialog QFrame#folderFrame, MessagesDialog QFrame#quickViewFrame { - background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FEFEFE, stop:1 #E8E8E8); - border: 1px solid #CCCCCC; + background: transparent; + } /* Profile */ diff --git a/retroshare-gui/src/gui/settings/NotifyPage.ui b/retroshare-gui/src/gui/settings/NotifyPage.ui index 0f25f470e..f468a62ec 100755 --- a/retroshare-gui/src/gui/settings/NotifyPage.ui +++ b/retroshare-gui/src/gui/settings/NotifyPage.ui @@ -75,7 +75,7 @@ - Links + Boards @@ -103,7 +103,7 @@ - Security + Friend Requests @@ -155,7 +155,7 @@ - Connect attempt + Friend Requests @@ -256,7 +256,7 @@ - Connect attempt + Friend Requests diff --git a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp index cde8c74da..10663a735 100644 --- a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp @@ -45,6 +45,7 @@ #include "util/QtVersion.h" #include "gui/common/UIStateHelper.h" #include "util/misc.h" +#include "util/qtthreadsutils.h" #include "gui/gxs/GxsIdLabel.h" #include "gui/gxs/GxsIdDetails.h" #include "gui/gxs/GxsIdTreeWidgetItem.h" @@ -85,8 +86,6 @@ GxsTransportStatistics::GxsTransportStatistics(QWidget *parent) mStateHelper = new UIStateHelper(this); mStateHelper->addWidget(GXSTRANS_GROUP_META, treeWidget); - mTransQueue = new TokenQueue(rsGxsTrans->getTokenService(), this); - m_bProcessSettings = false; mLastGroupReqTS = 0 ; @@ -154,7 +153,8 @@ void GxsTransportStatistics::updateDisplay(bool) std::cerr << "GxsTransportStatistics::updateDisplay()" << std::endl; #endif - requestGroupMeta(); + loadGroups(); + mLastGroupReqTS = now ; } @@ -201,7 +201,7 @@ void GxsTransportStatistics::updateContent() { RsGxsTrans::GxsTransStatistics transinfo ; - rsGxsTrans->getStatistics(transinfo) ; + rsGxsTrans->getDataStatistics(transinfo) ; // clear @@ -333,92 +333,8 @@ void GxsTransportStatistics::personDetails() dialog->show(); } -void GxsTransportStatistics::loadRequest(const TokenQueue *queue, const TokenRequest &req) -{ -#ifdef DEBUG_GXSTRANS_STATS - std::cerr << "GxsTransportStatistics::loadRequest() UserType: " << req.mUserType << std::endl; -#endif - - if (queue != mTransQueue) - { - std::cerr << "Wrong queue!" << std::endl; - return ; - } - - /* now switch on req */ - switch(req.mUserType) - { - case GXSTRANS_GROUP_META: loadGroupMeta(req.mToken); - break; - - case GXSTRANS_GROUP_STAT: loadGroupStat(req.mToken); - break; - - case GXSTRANS_MSG_META: loadMsgMeta(req.mToken); - break; - - default: - std::cerr << "GxsTransportStatistics::loadRequest() ERROR: INVALID TYPE"; - std::cerr << std::endl; - break; - } - - updateContent(); -} - -void GxsTransportStatistics::requestGroupMeta() -{ - mStateHelper->setLoading(GXSTRANS_GROUP_META, true); - -#ifdef DEBUG_GXSTRANS_STATS - std::cerr << "GxsTransportStatisticsWidget::requestGroupMeta()"; - std::cerr << std::endl; -#endif - - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_GROUP_META; - - uint32_t token; - mTransQueue->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_SUMMARY, opts, GXSTRANS_GROUP_META); -} -void GxsTransportStatistics::requestGroupStat(const RsGxsGroupId &groupId) -{ - uint32_t token; - rsGxsTrans->getTokenService()->requestGroupStatistic(token, groupId); - mTransQueue->queueRequest(token, 0, RS_TOKREQ_ANSTYPE_ACK, GXSTRANS_GROUP_STAT); -} -void GxsTransportStatistics::requestMsgMeta(const RsGxsGroupId& grpId) -{ - mStateHelper->setLoading(GXSTRANS_MSG_META, true); - -#ifdef DEBUG_GXSTRANS_STATS - std::cerr << "GxsTransportStatisticsWidget::requestGroupMeta()"; - std::cerr << std::endl; -#endif - - RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_MSG_META; - - std::list grouplist ; - grouplist.push_back(grpId) ; - - uint32_t token; - rsGxsTrans->getTokenService()->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_SUMMARY, opts, grouplist); - mTransQueue->queueRequest(token, 0, RS_TOKREQ_ANSTYPE_ACK, GXSTRANS_MSG_META); -} - -void GxsTransportStatistics::loadGroupStat(const uint32_t &token) -{ - GxsGroupStatistic stats; - rsGxsTrans->getGroupStatistic(token, stats); - -#ifdef DEBUG_GXSTRANS_STATS - std::cerr << "Loading group stats: " << stats.mGrpId << ", num msgs=" << stats.mNumMsgs << ", total size=" << stats.mTotalSizeOfMsgs << std::endl; -#endif - dynamic_cast(mGroupStats[stats.mGrpId]) = stats ; -} - -void GxsTransportStatistics::loadGroupMeta(const uint32_t& token) +#ifdef TO_REMOVE +void GxsTransportStatistics::loadGroupMeta(const std::vector& groupInfo) { mStateHelper->setLoading(GXSTRANS_GROUP_META, false); @@ -427,22 +343,11 @@ void GxsTransportStatistics::loadGroupMeta(const uint32_t& token) std::cerr << std::endl; #endif - std::list groupInfo; - std::list::iterator vit; - - if (!rsGxsTrans->getGroupSummary(token,groupInfo)) - { - std::cerr << "GxsTransportStatistics::loadGroupMeta() Error getting GroupMeta"; - std::cerr << std::endl; - mStateHelper->setActive(GXSTRANS_GROUP_META, false); - return; - } - mStateHelper->setActive(GXSTRANS_GROUP_META, true); std::set existing_groups ; - for(vit = groupInfo.begin(); vit != groupInfo.end(); ++vit) + for(auto vit = groupInfo.begin(); vit != groupInfo.end(); ++vit) { existing_groups.insert(vit->mGroupId) ; @@ -451,8 +356,8 @@ void GxsTransportStatistics::loadGroupMeta(const uint32_t& token) std::cerr << "GxsTransportStatisticsWidget::loadGroupMeta() GroupId: " << vit->mGroupId << " Group: " << vit->mGroupName << std::endl; #endif - requestGroupStat(vit->mGroupId) ; - requestMsgMeta(vit->mGroupId) ; + loadGroupStats(vit->mGroupId) ; + loadMsgMetas(vit->mGroupId) ; RsGxsTransGroupStatistics& s(mGroupStats[vit->mGroupId]); s.popularity = vit->mPop ; @@ -469,17 +374,74 @@ void GxsTransportStatistics::loadGroupMeta(const uint32_t& token) ++it; } -void GxsTransportStatistics::loadMsgMeta(const uint32_t& token) +void GxsTransportStatistics::loadGroupStats(const RsGxsGroupId& groupId) { - mStateHelper->setLoading(GXSTRANS_MSG_META, false); +#ifdef DEBUG_GXSTRANS_STATS + std::cerr << "Loading group stats: " << stats.mGrpId << ", num msgs=" << stats.mNumMsgs << ", total size=" << stats.mTotalSizeOfMsgs << std::endl; +#endif - GxsMsgMetaMap m ; + RsThread::async([this]() + { + // 1 - get message data from p3GxsForums - if (!rsGxsTrans->getMsgSummary(token,m)) - return ; +#ifdef DEBUG_FORUMS + std::cerr << "Retrieving post data for post " << mThreadId << std::endl; +#endif + GxsGroupStatistic stats; + rsGxsTrans->getGroupStatistic(groupId,stats); - for(GxsMsgMetaMap::const_iterator it(m.begin());it!=m.end();++it) - for(uint32_t i=0;isecond.size();++i) - mGroupStats[it->first].addMessageMeta(it->first,it->second[i]) ; + RsQThreadUtils::postToObject( [stats,this]() + { + /* Here it goes any code you want to be executed on the Qt Gui + * thread, for example to update the data model with new information + * after a blocking call to RetroShare API complete */ + + dynamic_cast(mGroupStats[stats.mGrpId]) = stats ; + + mStateHelper->setLoading(GXSTRANS_GROUP_STAT, false); + + }, this ); + + }); + +} +#endif + + +void GxsTransportStatistics::loadGroups() +{ + mStateHelper->setLoading(GXSTRANS_GROUP_META, true); + + RsThread::async([this]() + { + // 1 - get message data from p3GxsForums + +#ifdef DEBUG_FORUMS + std::cerr << "Retrieving post data for post " << mThreadId << std::endl; +#endif + std::map stats; + + if(!rsGxsTrans->getGroupStatistics(stats)) + { + RsErr() << "Cannot retrieve group statistics in GxsTransportStatistics" << std::endl; + return; + } + + RsQThreadUtils::postToObject( [stats,this]() + { + /* Here it goes any code you want to be executed on the Qt Gui + * thread, for example to update the data model with new information + * after a blocking call to RetroShare API complete */ + + mGroupStats = stats; + + updateContent(); + + mStateHelper->setLoading(GXSTRANS_GROUP_META, false); + + }, this ); + + }); } + diff --git a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.h b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.h index 2cf8c78b4..01a31e776 100644 --- a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.h +++ b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.h @@ -25,8 +25,8 @@ #include #include #include +#include -#include "util/TokenQueue.h" #include "RsAutoUpdatePage.h" #include "ui_GxsTransportStatistics.h" #include "gui/gxs/RsGxsUpdateBroadcastPage.h" @@ -35,32 +35,7 @@ class GxsTransportStatisticsWidget ; class UIStateHelper; -class RsGxsTransGroupStatistics: public GxsGroupStatistic -{ -public: - RsGxsTransGroupStatistics() - { - last_publish_TS = 0; - popularity = 0; - subscribed = false; - } - - void addMessageMeta(const RsGxsGroupId& grp,const RsMsgMetaData& meta) - { - messages_metas[meta.mMsgId] = meta ; - last_publish_TS = std::max(last_publish_TS,meta.mPublishTs) ; - mGrpId = grp ; - } - - bool subscribed ; - int popularity ; - - rstime_t last_publish_TS; - - std::map messages_metas ; -}; - -class GxsTransportStatistics: public MainPage, public TokenResponse, public Ui::GxsTransportStatistics +class GxsTransportStatistics: public MainPage, public Ui::GxsTransportStatistics { Q_OBJECT @@ -71,8 +46,6 @@ public: // Cache for peer names. static QString getPeerName(const RsPeerId& peer_id) ; - virtual void loadRequest(const TokenQueue *queue, const TokenRequest &req) ; - void updateContent() ; private slots: @@ -82,19 +55,12 @@ private slots: private: void updateDisplay(bool complete) ; - void loadGroupMeta(const uint32_t& token); - void loadGroupStat(const uint32_t& token); - void loadMsgMeta(const uint32_t& token); - - void requestGroupMeta(); - void requestMsgMeta(const RsGxsGroupId& groupId); - void requestGroupStat(const RsGxsGroupId &groupId); + void loadGroups(); void processSettings(bool bLoad); bool m_bProcessSettings; GxsTransportStatisticsWidget *_tst_CW ; - TokenQueue *mTransQueue ; UIStateHelper *mStateHelper; uint32_t mLastGroupReqTS ; diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 8806741ee..a5d6838ae 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -1240,7 +1240,8 @@ gxsthewire { gui/TheWire/WireGroupItem.cpp \ gui/TheWire/WireGroupDialog.cpp \ gui/TheWire/PulseAddDialog.cpp \ - + + RESOURCES += gui/TheWire/TheWire_images.qrc } identities { diff --git a/retroshare-gui/src/util/misc.cpp b/retroshare-gui/src/util/misc.cpp index a66de053c..4bcfd7149 100644 --- a/retroshare-gui/src/util/misc.cpp +++ b/retroshare-gui/src/util/misc.cpp @@ -405,3 +405,23 @@ QString misc::getExistingDirectory(QWidget *parent, const QString &caption, cons return QFileDialog::getExistingDirectory(parent, caption, dir, QFileDialog::DontUseNativeDialog | QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); #endif } + +/*! + * Clear a Layout content + * \param layout: Layout to Clear + */ +void misc::clearLayout(QLayout * layout) { + if (! layout) + return; + + while (auto item = layout->takeAt(0)) + { + if (auto *widget = item->widget()) + widget->deleteLater(); + if (auto *spacer = item->spacerItem()) + delete spacer; + + clearLayout(item->layout()); + delete item; + } +} diff --git a/retroshare-gui/src/util/misc.h b/retroshare-gui/src/util/misc.h index 6bf37f4b0..f09280ecf 100644 --- a/retroshare-gui/src/util/misc.h +++ b/retroshare-gui/src/util/misc.h @@ -27,6 +27,7 @@ #include #include #include +#include #include "gui/settings/rsharesettings.h" @@ -182,6 +183,10 @@ class misc : public QObject static QString getExistingDirectory(QWidget *parent = nullptr , const QString &caption = QString() , const QString &dir = QString()); + + //Clear QLayout + static void clearLayout(QLayout *layout); + }; // Trick to get a portable sleep() function