From 1dd54317c71358573e82ae6c80b2dd882bf528cd Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 4 Nov 2020 22:30:30 +0100 Subject: [PATCH] fixed pinned post immediate update by adding the proper rsEvent notification when updating own group data. Should also help in circles --- libretroshare/src/gxs/rsgenexchange.cc | 159 ++++++++++++++---- libretroshare/src/retroshare/rsgxsforums.h | 1 + libretroshare/src/services/p3gxscircles.cc | 6 +- libretroshare/src/services/p3gxsforums.cc | 25 ++- .../gui/gxsforums/GxsForumThreadWidget.cpp | 7 +- 5 files changed, 155 insertions(+), 43 deletions(-) diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index 96a812b51..ff71e83ac 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -63,6 +63,72 @@ static const uint32_t INDEX_AUTHEN_ADMIN = 0x00000040; // admin key #define GEN_EXCH_DEBUG 1 +// Data flow in RsGenExchange +// +// publishGroup() +// | +// +--- stores in mGrpsToPublish +// +// updateGroup() +// | +// +--- stores in mGroupUpdatePublish +// +// tick() +// | +// +--- processRecvdData(); +// | | +// | +-- processRecvdGroups(); +// | | | +// | | +---- mGroupPendingValidate +// | | | +// | | +---- acceptance => validateGrp() => check existance => store in mGroupUpdates +// | | | +// | | +--- validateNxsGrp() +// | | +// | +-- processRecvdMessages(); +// | | +// | +-- performUpdateValidation(); // validates group updates in mGroupUpdates received from friends +// | | +// | +---- mGroupUpdates => updateValid() => store new groups +// | | | +// | | +--- stamp keys, check admin keys are the same, validateNxsGrp() +// | | | +// | +---- stores RsGxsGroupChange in mNotifications +--- data signature check +// | +// +--- publishGrps(); // creates signatures and data for locally created groups +// | | +// | +-- reads mGrpsToPublish, creates the group, clears mGrpsToPublish +// | | +// | +--- generateGroupKeys() +// | | +// | +--- serviceCreateGroup() +// | | +// | +--- createGroup() +// | | +// | +--- createGroupSignatures() +// | +// +--- processGroupUpdatePublish(); // goes through list of group updates to perform locally +// | | +// | +-- reads/deletes mGroupUpdatePublish, stores in mGrpsToPublish +// | +// +--- processGrpMetaChanges(); +// | | +// | +-- updates mNotifications, calls mDataAccess +// | +// +--- processGroupDelete(); +// | +// +--- publishMsgs(); +// | +// +--- processMsgMetaChanges(); +// | | +// | +-- updates mNotifications, calls mDataAccess +// | +// +--- processMessageDelete(); +// | +// +--- mDataAccess->processRequests(); +// | +// +--- processRoutingClues() ; +// static const uint32_t MSG_CLEANUP_PERIOD = 60*59; // 59 minutes static const uint32_t INTEGRITY_CHECK_PERIOD = 60*31; // 31 minutes @@ -2596,8 +2662,17 @@ void RsGenExchange::publishGrps() RS_STACK_MUTEX(mGenMtx) ; NxsGrpSignPendVect::iterator vit = mGrpsToPublish.begin(); - typedef std::pair GrpNote; - std::map toNotify; + typedef struct _GrpNote { + + _GrpNote(bool success,bool is_update,const RsGxsGroupId& gid) : mSuccess(success),mIsUpdate(is_update),mGroupId(gid){} + + bool mSuccess; + bool mIsUpdate; + RsGxsGroupId mGroupId; + + } GrpNote; + + std::map toNotify; // used to notify about token processing if success or fails because of timeout while( vit != mGrpsToPublish.end() ) { @@ -2611,8 +2686,7 @@ void RsGenExchange::publishGrps() if(now > (ggps.mStartTS + PENDING_SIGN_TIMEOUT) ) { // timed out - toNotify.insert(std::make_pair( - token, GrpNote(false, RsGxsGroupId()))); + toNotify.insert(std::make_pair( token, GrpNote(false,ggps.mIsUpdate, RsGxsGroupId()))); delete ggps.mItem; vit = mGrpsToPublish.erase(vit); @@ -2723,12 +2797,36 @@ void RsGenExchange::publishGrps() computeHash(grp->grp, grp->metaData->mHash); grp->metaData->mRecvTS = time(NULL); - if(ggps.mIsUpdate) - mDataAccess->updateGroupData(grp); - else - mDataAccess->addGroupData(grp); + // Also push in notifications. We do it here when we still have pointers on the old and new groups - delete grp ; + RsGxsGroupChange *c = new RsGxsGroupChange(ggps.mIsUpdate?RsGxsNotify::TYPE_UPDATED:RsGxsNotify::TYPE_PUBLISHED, grpId,false); + + c->mNewGroupItem = dynamic_cast(mSerialiser->deserialise(grp->grp.bin_data,&grp->grp.bin_len)); + c->mNewGroupItem->meta = *grp->metaData; // grp will be deleted because mDataStore will destroy it on update + + if(ggps.mIsUpdate) + { + RsNxsGrpDataTemporaryMap oldGrpDatas; + oldGrpDatas.insert(std::make_pair(grpId, (RsNxsGrp*)NULL)); + + if(mDataStore->retrieveNxsGrps(oldGrpDatas,true,false) && oldGrpDatas.size() == 1) + { + auto oldGrp = oldGrpDatas[grpId]; + c->mOldGroupItem = dynamic_cast(mSerialiser->deserialise(oldGrp->grp.bin_data,&oldGrp->grp.bin_len)); + c->mOldGroupItem->meta = *oldGrp->metaData; + } + } + + mNotifications.push_back(c); + + // now store (and incidently delete grp) + + if(ggps.mIsUpdate) + mDataAccess->updateGroupData(grp); + else + mDataAccess->addGroupData(grp); + + delete grp ; groups_to_subscribe.push_back(grpId) ; } else @@ -2744,7 +2842,7 @@ void RsGenExchange::publishGrps() // services should return SERVICE_CREATE_FAIL if the action timed out // at the moment this is only important for the idservice: // the idservice may ask the user for a password, and the user needs time - ggps.mStartTS = now; + ggps.mStartTS = now; create = CREATE_FAIL_TRY_LATER; } else if(ret == SERVICE_CREATE_FAIL) @@ -2766,8 +2864,7 @@ void RsGenExchange::publishGrps() delete grp; delete grpItem; vit = mGrpsToPublish.erase(vit); - toNotify.insert(std::make_pair( - token, GrpNote(false, grpId))); + toNotify.insert(std::make_pair(token, GrpNote(false, ggps.mIsUpdate,grpId))); } else if(create == CREATE_FAIL_TRY_LATER) @@ -2790,30 +2887,21 @@ void RsGenExchange::publishGrps() #endif // add to published to allow acknowledgement - toNotify.insert(std::make_pair(token, - GrpNote(true,grpId))); + toNotify.insert(std::make_pair(token, GrpNote(true,ggps.mIsUpdate,grpId))); } } - std::map::iterator mit = toNotify.begin(); + // toNotify contains the token and the group update/creation info. We parse it to + // - notify that group creation/update for a specific token was - std::list grpChanged; - for(; mit != toNotify.end(); ++mit) + for(auto mit=toNotify.begin(); mit != toNotify.end(); ++mit) { GrpNote& note = mit->second; - RsTokenService::GxsRequestStatus status = - note.first ? RsTokenService::COMPLETE - : RsTokenService::FAILED; + RsTokenService::GxsRequestStatus status = note.mSuccess ? RsTokenService::COMPLETE : RsTokenService::FAILED; - mGrpNotify.insert(std::make_pair(mit->first, note.second)); - mDataAccess->updatePublicRequestStatus(mit->first, status); - - if(note.first) - grpChanged.push_back(note.second); - } - - for(auto& groupId:grpChanged) - mNotifications.push_back(new RsGxsGroupChange(RsGxsNotify::TYPE_RECEIVED_NEW,groupId, true)); + mGrpNotify.insert(std::make_pair(mit->first, note.mGroupId)); // always notify + mDataAccess->updatePublicRequestStatus(mit->first, status); // update the token request with the given status + } } // This is done off-mutex to avoid possible cross deadlocks with the net service. @@ -2823,8 +2911,6 @@ void RsGenExchange::publishGrps() mNetService->subscribeStatusChanged((*it),true) ; } - - uint32_t RsGenExchange::generatePublicToken() { return mDataAccess->generatePublicToken(); @@ -3082,7 +3168,7 @@ void RsGenExchange::processRecvdMessages() mNotifications.push_back(c); } - mDataStore->storeMessage(msgs_to_store); // we do that late because it destroys the items in msgs_to_store + mDataStore->storeMessage(msgs_to_store); // All items will be destroyed later on, since msgs_to_store is a temporary map } } @@ -3224,9 +3310,9 @@ void RsGenExchange::processRecvdGroups() mDataStore->storeGroup(grps_to_store); #ifdef GEN_EXCH_DEBUG - std::cerr << " adding the following grp ids to notification: " << std::endl; - for(std::list::const_iterator it(grpIds.begin());it!=grpIds.end();++it) - std::cerr << " " << *it << std::endl; + std::cerr << " adding the following grp ids to notification: " << std::endl; + for(std::list::const_iterator it(grpIds.begin());it!=grpIds.end();++it) + std::cerr << " " << *it << std::endl; #endif } } @@ -3317,8 +3403,7 @@ void RsGenExchange::performUpdateValidation() } } - // Warning: updateGroup will destroy the objects in grps. Dont use it afterwards! - mDataStore->updateGroup(grps); + mDataStore->updateGroup(grps); #ifdef GEN_EXCH_DEBUG std::cerr << " adding the following grp ids to notification: " << std::endl; diff --git a/libretroshare/src/retroshare/rsgxsforums.h b/libretroshare/src/retroshare/rsgxsforums.h index 20b7d87de..573111d9f 100644 --- a/libretroshare/src/retroshare/rsgxsforums.h +++ b/libretroshare/src/retroshare/rsgxsforums.h @@ -116,6 +116,7 @@ enum class RsForumEventCode: uint8_t STATISTICS_CHANGED = 0x07, /// suppliers and how many messages they have changed MODERATOR_LIST_CHANGED = 0x08, /// forum moderation list has changed. SYNC_PARAMETERS_UPDATED = 0x0a, /// sync and storage times have changed + PINNED_POSTS_CHANGED = 0x0b, /// some posts where pinned or un-pinned }; struct RsGxsForumEvent: RsEvent diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 80f5fa290..9366be299 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -683,8 +683,6 @@ void p3GxsCircles::notifyChanges(std::vector &changes) RsGxsCircleGroupItem *old_circle_grp_item = dynamic_cast(groupChange->mOldGroupItem); RsGxsCircleGroupItem *new_circle_grp_item = dynamic_cast(groupChange->mNewGroupItem); - const RsGxsCircleId circle_id ( old_circle_grp_item->meta.mGroupId ); - if(old_circle_grp_item == nullptr || new_circle_grp_item == nullptr) { RsErr() << __PRETTY_FUNCTION__ << " received GxsGroupUpdate item with mOldGroup and mNewGroup not of type RsGxsCircleGroupItem. This is inconsistent!" << std::endl; @@ -692,7 +690,9 @@ void p3GxsCircles::notifyChanges(std::vector &changes) continue; } - // First of all, we check if there is a difference between the old and new list of invited members + const RsGxsCircleId circle_id ( old_circle_grp_item->meta.mGroupId ); + + // First of all, we check if there is a difference between the old and new list of invited members for(auto& gxs_id: new_circle_grp_item->gxsIdSet.ids) if(old_circle_grp_item->gxsIdSet.ids.find(gxs_id) == old_circle_grp_item->gxsIdSet.ids.end()) diff --git a/libretroshare/src/services/p3gxsforums.cc b/libretroshare/src/services/p3gxsforums.cc index cf0625f1d..1a7b984fc 100644 --- a/libretroshare/src/services/p3gxsforums.cc +++ b/libretroshare/src/services/p3gxsforums.cc @@ -307,7 +307,7 @@ void p3GxsForums::notifyChanges(std::vector &changes) if(old_forum_grp_item == nullptr || new_forum_grp_item == nullptr) { - RsErr() << __PRETTY_FUNCTION__ << " received GxsGroupUpdate item with mOldGroup and mNewGroup not of type RsGxsForumGroupItem. This is inconsistent!" << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " received GxsGroupUpdate item with mOldGroup and mNewGroup not of type RsGxsForumGroupItem or NULL. This is inconsistent!" << std::endl; delete grpChange; continue; } @@ -335,6 +335,29 @@ void p3GxsForums::notifyChanges(std::vector &changes) rsEvents->postEvent(ev); } + + // check the list of pinned posts + + std::list added_pins, removed_pins; + + for(auto& msg_id: new_forum_grp_item->mGroup.mPinnedPosts.ids) + if(old_forum_grp_item->mGroup.mPinnedPosts.ids.find(msg_id) == old_forum_grp_item->mGroup.mPinnedPosts.ids.end()) + added_pins.push_back(msg_id); + + for(auto& msg_id: old_forum_grp_item->mGroup.mPinnedPosts.ids) + if(new_forum_grp_item->mGroup.mPinnedPosts.ids.find(msg_id) == new_forum_grp_item->mGroup.mPinnedPosts.ids.end()) + removed_pins.push_back(msg_id); + + if(!added_pins.empty() || !removed_pins.empty()) + { + auto ev = std::make_shared(); + + ev->mForumGroupId = new_forum_grp_item->meta.mGroupId; + ev->mForumEventCode = RsForumEventCode::PINNED_POSTS_CHANGED; + + rsEvents->postEvent(ev); + } + } break; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index d26da49e3..de0f4a056 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -386,6 +386,7 @@ void GxsForumThreadWidget::handleEvent_main_thread(std::shared_ptrmForumGroupId == mForumGroup.mMeta.mGroupId) updateDisplay(true); @@ -1571,8 +1572,10 @@ void GxsForumThreadWidget::togglePinUpPost() uint32_t token; rsGxsForums->updateGroup(token,mForumGroup); - groupIdChanged(); // reloads all posts. We could also update the model directly, but the cost is so small now ;-) - updateDisplay(true) ; + // We dont call this from here anymore. The update will be called by libretroshare using the rsEvent system when + // the data is actually updated. + // groupIdChanged(); // reloads all posts. We could also update the model directly, but the cost is so small now ;-) + // updateDisplay(true) ; } void GxsForumThreadWidget::createthread()