diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 0b1ac5270..6d5c1dcd5 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -103,7 +103,7 @@ #define MIN_CIRCLE_LOAD_GAP 5 #define GXS_CIRCLE_DELAY_TO_FORCE_MEMBERSHIP_UPDATE 60 // re-check every 1 mins. Normally this shouldn't be necessary since notifications inform abotu new messages. #define GXS_CIRCLE_DELAY_TO_CHECK_MEMBERSHIP_UPDATE 60 // re-check every 1 mins. Normally this shouldn't be necessary since notifications inform abotu new messages. -#define GXS_CIRCLE_DELAY_TO_SEND_CACHE_UPDATED_EVENT 10 // do not send cache update events more often than every 10 secs. +#define GXS_CIRCLE_DELAY_TO_SEND_CACHE_UPDATED_EVENT 2 // do not send cache update events more often than every 2 secs. /********************************************************************************/ /******************* Startup / Tick ******************************************/ @@ -532,6 +532,7 @@ void p3GxsCircles::notifyChanges(std::vector &changes) #endif p3Notify *notify = RsServer::notify(); + std::set circles_to_reload; for(auto it = changes.begin(); it != changes.end(); ++it) { @@ -576,6 +577,7 @@ void p3GxsCircles::notifyChanges(std::vector &changes) } mCircleCache.erase(circle_id); + circles_to_reload.insert(circle_id); mCacheUpdated = true; } @@ -608,6 +610,7 @@ void p3GxsCircles::notifyChanges(std::vector &changes) RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ mCircleCache.erase(RsGxsCircleId(*git)); mCacheUpdated = true; + circles_to_reload.insert(RsGxsCircleId(*git)); } } } @@ -686,6 +689,7 @@ void p3GxsCircles::notifyChanges(std::vector &changes) RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ mCircleCache.erase(RsGxsCircleId(*git)); mCacheUpdated = true; + circles_to_reload.insert(RsGxsCircleId(*git)); } } @@ -693,6 +697,9 @@ void p3GxsCircles::notifyChanges(std::vector &changes) delete c; } + + for(auto& circle_id:circles_to_reload) + force_cache_reload(circle_id); } /********************************************************************************/ diff --git a/retroshare-gui/src/gui/NewsFeed.cpp b/retroshare-gui/src/gui/NewsFeed.cpp index 6c6a0d761..63d81c41e 100644 --- a/retroshare-gui/src/gui/NewsFeed.cpp +++ b/retroshare-gui/src/gui/NewsFeed.cpp @@ -294,97 +294,120 @@ void NewsFeed::handleChannelEvent(std::shared_ptr event) void NewsFeed::handleCircleEvent(std::shared_ptr event) { - const RsGxsCircleEvent *pe = dynamic_cast(event.get()); - if(!pe) - return; + // Gives the backend a few secs to load the cache data while not blocking the UI. This is not so nice, but there's no proper + // other way to do that. - RsGxsCircleDetails details; - - if(pe->mCircleId.isNull()) // probably an item for cache update - return ; - - if(!rsGxsCircles->getCircleDetails(pe->mCircleId,details)) + RsThread::async( [event,this]() { - std::cerr << "(EE) Cannot get information about circle " << pe->mCircleId << ". Not in cache?" << std::endl; - return; - } + const RsGxsCircleEvent *pe = dynamic_cast(event.get()); + if(!pe) + return; - if(!details.isGxsIdBased()) // not handled yet. - return; + if(pe->mCircleId.isNull()) // probably an item for cache update + return ; - // Check if the circle is one of which we belong to or we are an admin of. - // If so, then notify in the GUI about other members leaving/subscribing, according - // to the following rules. The names correspond to the RS_FEED_CIRCLE_* variables: - // - // Message-based notifications: - // - // +---------------------------+----------------------------+ - // | Membership request | Membership cancellation | - // +-------------+-------------+-------------+--------------+ - // | Admin | Not admin | Admin | Not admin | - // +--------------------+-------------+-------------+----------------------------+ - // | in invitee list | MEMB_JOIN | MEMB_JOIN | MEMB_LEAVE | MEMB_LEAVE | - // +--------------------+-------------+-------------+-------------+--------------+ - // |not in invitee list | MEMB_REQ | X | X | X | - // +--------------------+-------------+-------------+-------------+--------------+ - // - // Note: in this case, the GxsId never belongs to you, since you dont need to handle - // notifications for actions you took yourself (leave/join a circle) - // - // GroupData-based notifications, the GxsId belongs to you: - // - // +---------------------------+----------------------------+ - // | GxsId joins invitee list | GxsId leaves invitee list | - // +-------------+-------------+-------------+--------------+ - // | Id is yours| Id is not | Id is yours | Id is not | - // +--------------------+-------------+-------------+-------------+--------------+ - // | Has Member request | MEMB_ACCEPT | (MEMB_JOIN) | MEMB_REVOKED| (MEMB_LEAVE) | - // +--------------------+-------------+-------------+-------------+--------------+ - // | No Member request | INVITE_REC | X | INVITE_REM | X | - // +--------------------+-------------+-------------+-------------+--------------+ - // - // Note: In this case you're never an admin of the circle, since these notification - // would be a direct consequence of your own actions. + RsGxsCircleDetails details; + bool loaded = false; - switch(pe->mCircleEventType) - { - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REQUEST: - // only show membership requests if we're an admin of that circle - if(details.isIdInInviteeList(pe->mGxsId)) - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_JOIN),true); - else if(details.mAmIAdmin) - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REQ),true); - - break; - - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE: - - if(details.isIdInInviteeList(pe->mGxsId)) - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_LEAVE),true); - break; - - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_ADDED_TO_INVITEE_LIST: - if(rsIdentity->isOwnId(pe->mGxsId)) - { - if(details.isIdRequestingMembership(pe->mGxsId)) - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_ACCEPTED),true); + for(int i=0;i<5 && !loaded;++i) + if(rsGxsCircles->getCircleDetails(pe->mCircleId,details)) + { + std::cerr << "Cache item loaded for circle " << pe->mCircleId << std::endl; + loaded = true; + } else - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_INVITE_REC),true); - } - break; + { + std::cerr << "Cache item for circle " << pe->mCircleId << " not loaded. Waiting " << i << "s" << std::endl; + rstime::rs_usleep(1000*1000); + } - case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_REMOVED_FROM_INVITEE_LIST: - if(rsIdentity->isOwnId(pe->mGxsId)) - { - if(details.isIdRequestingMembership(pe->mGxsId)) - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REVOKED),true); - else - addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_INVITE_CANCELLED),true); - } - break; + if(!loaded) + { + std::cerr << "(EE) Cannot get information about circle " << pe->mCircleId << ". Not in cache?" << std::endl; + return; + } - default: break; - } + if(!details.isGxsIdBased()) // not handled yet. + return; + + // Check if the circle is one of which we belong to or we are an admin of. + // If so, then notify in the GUI about other members leaving/subscribing, according + // to the following rules. The names correspond to the RS_FEED_CIRCLE_* variables: + // + // Message-based notifications: + // + // +---------------------------+----------------------------+ + // | Membership request | Membership cancellation | + // +-------------+-------------+-------------+--------------+ + // | Admin | Not admin | Admin | Not admin | + // +--------------------+-------------+-------------+----------------------------+ + // | in invitee list | MEMB_JOIN | MEMB_JOIN | MEMB_LEAVE | MEMB_LEAVE | + // +--------------------+-------------+-------------+-------------+--------------+ + // |not in invitee list | MEMB_REQ | X | X | X | + // +--------------------+-------------+-------------+-------------+--------------+ + // + // Note: in this case, the GxsId never belongs to you, since you dont need to handle + // notifications for actions you took yourself (leave/join a circle) + // + // GroupData-based notifications, the GxsId belongs to you: + // + // +---------------------------+----------------------------+ + // | GxsId joins invitee list | GxsId leaves invitee list | + // +-------------+-------------+-------------+--------------+ + // | Id is yours| Id is not | Id is yours | Id is not | + // +--------------------+-------------+-------------+-------------+--------------+ + // | Has Member request | MEMB_ACCEPT | (MEMB_JOIN) | MEMB_REVOKED| (MEMB_LEAVE) | + // +--------------------+-------------+-------------+-------------+--------------+ + // | No Member request | INVITE_REC | X | INVITE_REM | X | + // +--------------------+-------------+-------------+-------------+--------------+ + // + // Note: In this case you're never an admin of the circle, since these notification + // would be a direct consequence of your own actions. + + RsQThreadUtils::postToObject( [event,details,this]() + { + const RsGxsCircleEvent *pe = static_cast(event.get()); + + switch(pe->mCircleEventType) + { + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REQUEST: + // only show membership requests if we're an admin of that circle + if(details.isIdInInviteeList(pe->mGxsId)) + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_JOIN),true); + else if(details.mAmIAdmin) + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REQ),true); + + break; + + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE: + + if(details.isIdInInviteeList(pe->mGxsId)) + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_LEAVE),true); + break; + + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_ADDED_TO_INVITEE_LIST: + if(rsIdentity->isOwnId(pe->mGxsId)) + { + if(details.isIdRequestingMembership(pe->mGxsId)) + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_ACCEPTED),true); + else + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_INVITE_REC),true); + } + break; + + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_ID_REMOVED_FROM_INVITEE_LIST: + if(rsIdentity->isOwnId(pe->mGxsId)) + { + if(details.isIdRequestingMembership(pe->mGxsId)) + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_MEMB_REVOKED),true); + else + addFeedItemIfUnique(new GxsCircleItem(this, NEWSFEED_CIRCLELIST, pe->mCircleId, pe->mGxsId, RS_FEED_ITEM_CIRCLE_INVITE_CANCELLED),true); + } + break; + + default: break; + } + }, this ); }); // damn! } void NewsFeed::handleConnectionEvent(std::shared_ptr event) diff --git a/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp b/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp index 4d4f3e031..f827b115e 100644 --- a/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp +++ b/retroshare-gui/src/gui/feeds/GxsCircleItem.cpp @@ -86,13 +86,13 @@ void GxsCircleItem::setup() RsGxsCircleDetails circleDetails; if (rsGxsCircles->getCircleDetails(mCircleId, circleDetails)) { + ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str()) + " (ID: " + QString::fromStdString(circleDetails.mCircleId.toStdString()) + ")"); + // from here we can figure out if we already have requested membership or not if (mType == RS_FEED_ITEM_CIRCLE_MEMB_REQ) { ui->titleLabel->setText(tr("You received a membership request a circle you're administrating:")); - ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); - ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); @@ -102,8 +102,6 @@ void GxsCircleItem::setup() else if (mType == RS_FEED_ITEM_CIRCLE_INVITE_REC) { ui->titleLabel->setText(tr("You received an invitation for this circle:")); - ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); - ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); @@ -114,8 +112,6 @@ void GxsCircleItem::setup() else if (mType == RS_FEED_ITEM_CIRCLE_MEMB_LEAVE) { ui->titleLabel->setText(idName + tr(" has left this circle.")); - ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); - ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); @@ -125,8 +121,6 @@ void GxsCircleItem::setup() else if (mType == RS_FEED_ITEM_CIRCLE_MEMB_JOIN) { ui->titleLabel->setText(idName + tr(" which you invited, has join this circle you're administrating.")); - ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); - ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); @@ -137,8 +131,6 @@ void GxsCircleItem::setup() { ui->titleLabel->setText(tr("Your identity %1 has been revoked from this circle.").arg(idName)); - ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); - ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); @@ -149,8 +141,6 @@ void GxsCircleItem::setup() { ui->titleLabel->setText(tr("Your identity %1 as been accepted in this circle.").arg(idName)); - ui->nameLabel->setText(QString::fromUtf8(circleDetails.mCircleName.c_str())); - ui->gxsIdLabel->setText(idName); ui->iconLabel->setPixmap(pixmap); ui->gxsIdLabel->setId(mGxsId); diff --git a/retroshare-gui/src/gui/feeds/GxsCircleItem.ui b/retroshare-gui/src/gui/feeds/GxsCircleItem.ui index 408781e9b..4cd6846e2 100644 --- a/retroshare-gui/src/gui/feeds/GxsCircleItem.ui +++ b/retroshare-gui/src/gui/feeds/GxsCircleItem.ui @@ -7,7 +7,7 @@ 0 0 618 - 104 + 172 @@ -104,8 +104,8 @@ QFrame::Sunken - - + + @@ -130,154 +130,8 @@ - - - - - - for identity - - - - - - - - 20 - 20 - - - - TextLabel - - - true - - - - - - - name - - - true - - - - - - - Qt::Horizontal - - - - 358 - 20 - - - - - - - - - - - 0 - 0 - - - - Qt::NoFocus - - - Accept - - - - :/images/accepted16.png:/images/accepted16.png - - - - - - - - 0 - 0 - - - - Qt::NoFocus - - - Revoke - - - - :/images/cancel.png:/images/cancel.png - - - - - - - - 0 - 0 - - - - Qt::NoFocus - - - Details - - - - :/images/informations_24x24.png:/images/informations_24x24.png - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 285 - 18 - - - - - - - - - 0 - 0 - - - - Qt::NoFocus - - - Remove Item - - - - :/icons/png/exit2.png:/icons/png/exit2.png - - - - - + + @@ -294,32 +148,193 @@ - Circle + Circle msg - - - name - - - true - - + + + + + Circle name: + + + + + + + name + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - Qt::Horizontal - - - - 40 - 20 - - - + + + + + Identity: + + + + + + + + 20 + 20 + + + + TextLabel + + + true + + + + + + + name + + + true + + + + + + + Qt::Horizontal + + + + 358 + 20 + + + + + + + + + + + + + 0 + 0 + + + + Qt::NoFocus + + + Accept + + + + :/images/accepted16.png:/images/accepted16.png + + + + + + + + 0 + 0 + + + + Qt::NoFocus + + + Revoke + + + + :/images/cancel.png:/images/cancel.png + + + + + + + + 0 + 0 + + + + Qt::NoFocus + + + Details + + + + :/images/informations_24x24.png:/images/informations_24x24.png + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 285 + 18 + + + + + + + + + 0 + 0 + + + + Qt::NoFocus + + + Remove Item + + + + :/icons/png/exit2.png:/icons/png/exit2.png + + + + @@ -336,8 +351,8 @@ - +