mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-01-12 16:09:37 -05:00
factored the collection of latest channel post versions and added a proper counting for new/unread posts
This commit is contained in:
parent
c95a0edd60
commit
6775a64ed5
@ -369,7 +369,25 @@ void GxsChannelDialog::toggleAutoDownload()
|
||||
|
||||
bool GxsChannelDialog::getGroupStatistics(const RsGxsGroupId& groupId,GxsGroupStatistic& stat)
|
||||
{
|
||||
return rsGxsChannels->getChannelStatistics(groupId,stat);
|
||||
// What follows is a hack to replace the GXS group statistics by the actual count of unread messages in channels,
|
||||
// which should take into account old post versions, discard comments and votes, etc.
|
||||
|
||||
RsGxsChannelStatistics s;
|
||||
bool res = rsGxsChannels->getChannelStatistics(groupId,s);
|
||||
|
||||
if(!res)
|
||||
return false;
|
||||
|
||||
stat.mGrpId = groupId;
|
||||
stat.mNumMsgs = s.mNumberOfPosts;
|
||||
|
||||
stat.mTotalSizeOfMsgs = 0; // hopefuly unused. Required the loading of the full channel data, so not very convenient.
|
||||
stat.mNumThreadMsgsNew = s.mNumberOfNewPosts;
|
||||
stat.mNumThreadMsgsUnread = s.mNumberOfUnreadPosts;
|
||||
stat.mNumChildMsgsNew = 0;
|
||||
stat.mNumChildMsgsUnread = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GxsChannelDialog::getGroupData(std::list<RsGxsGenericGroupData*>& groupInfo)
|
||||
|
@ -548,8 +548,9 @@ void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vecto
|
||||
initEmptyHierarchy();
|
||||
mChannelGroup = group;
|
||||
|
||||
createPostsArray(posts);
|
||||
// createPostsArray(posts);
|
||||
|
||||
mPosts = posts;
|
||||
std::sort(mPosts.begin(),mPosts.end());
|
||||
|
||||
for(uint32_t i=0;i<mPosts.size();++i)
|
||||
@ -641,268 +642,6 @@ void RsGxsChannelPostsModel::update_posts(const RsGxsGroupId& group_id)
|
||||
});
|
||||
}
|
||||
|
||||
void RsGxsChannelPostsModel::old_createPostsArray(std::vector<RsGxsChannelPost>& posts)
|
||||
{
|
||||
// collect new versions of posts if any
|
||||
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << "Inserting channel posts" << std::endl;
|
||||
#endif
|
||||
|
||||
std::vector<uint32_t> new_versions ;
|
||||
for (uint32_t i=0;i<posts.size();++i)
|
||||
{
|
||||
if(posts[i].mMeta.mOrigMsgId == posts[i].mMeta.mMsgId)
|
||||
posts[i].mMeta.mOrigMsgId.clear();
|
||||
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << " " << i << ": name=\"" << posts[i].mMeta.mMsgName << "\" msg_id=" << posts[i].mMeta.mMsgId << ": orig msg id = " << posts[i].mMeta.mOrigMsgId << std::endl;
|
||||
#endif
|
||||
|
||||
if(!posts[i].mMeta.mOrigMsgId.isNull())
|
||||
new_versions.push_back(i) ;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << "New versions: " << new_versions.size() << std::endl;
|
||||
#endif
|
||||
|
||||
if(!new_versions.empty())
|
||||
{
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << " New versions present. Replacing them..." << std::endl;
|
||||
std::cerr << " Creating search map." << std::endl;
|
||||
#endif
|
||||
|
||||
// make a quick search map
|
||||
std::map<RsGxsMessageId,uint32_t> search_map ;
|
||||
for (uint32_t i=0;i<posts.size();++i)
|
||||
search_map[posts[i].mMeta.mMsgId] = i ;
|
||||
|
||||
for(uint32_t i=0;i<new_versions.size();++i)
|
||||
{
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << " Taking care of new version at index " << new_versions[i] << std::endl;
|
||||
#endif
|
||||
|
||||
uint32_t current_index = new_versions[i] ;
|
||||
uint32_t source_index = new_versions[i] ;
|
||||
|
||||
// What we do is everytime we find a replacement post, we climb up the replacement graph until we find the original post
|
||||
// (or the most recent version of it). When we reach this post, we replace it with the data of the source post.
|
||||
// In the mean time, all other posts have their MsgId cleared, so that the posts are removed from the list.
|
||||
|
||||
//std::vector<uint32_t> versions ;
|
||||
std::map<RsGxsMessageId,uint32_t>::const_iterator vit ;
|
||||
|
||||
while(search_map.end() != (vit=search_map.find(posts[current_index].mMeta.mOrigMsgId)))
|
||||
{
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << " post at index " << current_index << " replaces a post at position " << vit->second ;
|
||||
#endif
|
||||
|
||||
// Now replace the post only if the new versionis more recent. It may happen indeed that the same post has been corrected multiple
|
||||
// times. In this case, we only need to replace the post with the newest version
|
||||
|
||||
//uint32_t prev_index = current_index ;
|
||||
current_index = vit->second ;
|
||||
|
||||
if(posts[current_index].mMeta.mMsgId.isNull()) // This handles the branching situation where this post has been already erased. No need to go down further.
|
||||
{
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << " already erased. Stopping." << std::endl;
|
||||
#endif
|
||||
break ;
|
||||
}
|
||||
|
||||
if(posts[current_index].mMeta.mPublishTs < posts[source_index].mMeta.mPublishTs)
|
||||
{
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << " and is more recent => following" << std::endl;
|
||||
#endif
|
||||
for(std::set<RsGxsMessageId>::const_iterator itt(posts[current_index].mOlderVersions.begin());itt!=posts[current_index].mOlderVersions.end();++itt)
|
||||
posts[source_index].mOlderVersions.insert(*itt);
|
||||
|
||||
posts[source_index].mOlderVersions.insert(posts[current_index].mMeta.mMsgId);
|
||||
posts[current_index].mMeta.mMsgId.clear(); // clear the msg Id so the post will be ignored
|
||||
}
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
else
|
||||
std::cerr << " but is older -> Stopping" << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << "Now adding " << posts.size() << " posts into array structure..." << std::endl;
|
||||
#endif
|
||||
|
||||
mPosts.clear();
|
||||
|
||||
for (std::vector<RsGxsChannelPost>::const_reverse_iterator it = posts.rbegin(); it != posts.rend(); ++it)
|
||||
{
|
||||
if(!(*it).mMeta.mMsgId.isNull())
|
||||
{
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << " adding post \"" << (*it).mMeta.mMsgName << "\"" << std::endl;
|
||||
#endif
|
||||
mPosts.push_back(*it);
|
||||
}
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
else
|
||||
std::cerr << " skipped older version post \"" << (*it).mMeta.mMsgName << "\"" << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void RsGxsChannelPostsModel::createPostsArray(std::vector<RsGxsChannelPost>& posts)
|
||||
{
|
||||
// The hierarchy of posts may contain edited posts. In the new model (03/2023), mOrigMsgId points to the original
|
||||
// top-level post in the hierarchy of edited posts. However, in the old model, mOrigMsgId points to the edited post.
|
||||
// Therefore the algorithm below is made to cope with both models at once.
|
||||
//
|
||||
// In the future, using the new model, it will be possible to delete old versions from the db, and detect new versions
|
||||
// because they all share the same mOrigMsgId.
|
||||
//
|
||||
// We proceed as follows:
|
||||
//
|
||||
// 1 - create a search map to convert post IDs into their index in the posts tab
|
||||
// 2 - recursively climb up the post mOrigMsgId until no parent is found. At top level, create the original post, and add all previous elements as newer versions.
|
||||
// 3 - go through the list of original posts, select among them the most recent version, and set all others as older versions.
|
||||
//
|
||||
// The algorithm handles the case where some parent has been deleted.
|
||||
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << "Inserting channel posts" << std::endl;
|
||||
#endif
|
||||
|
||||
// 1 - create a search map to convert post IDs into their index in the posts tab
|
||||
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << " Given list: " << std::endl;
|
||||
#endif
|
||||
std::map<RsGxsMessageId,uint32_t> search_map ;
|
||||
|
||||
for (uint32_t i=0;i<posts.size();++i)
|
||||
{
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << " " << i << ": " << posts[i].mMeta.mMsgId << " orig=" << posts[i].mMeta.mOrigMsgId << " publish TS =" << posts[i].mMeta.mPublishTs << std::endl;
|
||||
#endif
|
||||
search_map[posts[i].mMeta.mMsgId] = i ;
|
||||
}
|
||||
|
||||
// 2 - recursively climb up the post mOrigMsgId until no parent is found. At top level, create the original post, and add all previous elements as newer versions.
|
||||
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << " Searching for top-level posts..." << std::endl;
|
||||
#endif
|
||||
std::map<RsGxsMessageId,std::pair<uint32_t,std::set<RsGxsMessageId> > > original_versions ;
|
||||
|
||||
for (uint32_t i=0;i<posts.size();++i)
|
||||
{
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << " Post " << i;
|
||||
#endif
|
||||
|
||||
// We use a recursive function here, so as to collect versions when climbing up to the top level post, and
|
||||
// set the top level as the orig for all visited posts on the way back.
|
||||
|
||||
std::function<RsGxsMessageId (uint32_t,std::set<RsGxsMessageId>& versions,rstime_t newest_time,uint32_t newest_index,int depth)> recurs_find_top_level
|
||||
= [&posts,&search_map,&recurs_find_top_level,&original_versions](uint32_t index,
|
||||
std::set<RsGxsMessageId>& collected_versions,
|
||||
rstime_t newest_time,
|
||||
uint32_t newest_index,
|
||||
int depth)
|
||||
-> RsGxsMessageId
|
||||
{
|
||||
const auto& m(posts[index].mMeta);
|
||||
|
||||
if(m.mPublishTs > newest_time)
|
||||
{
|
||||
newest_index = index;
|
||||
newest_time = m.mPublishTs;
|
||||
}
|
||||
collected_versions.insert(m.mMsgId);
|
||||
|
||||
RsGxsMessageId top_level_id;
|
||||
std::map<RsGxsMessageId,uint32_t>::const_iterator it;
|
||||
|
||||
if(m.mOrigMsgId.isNull() || m.mOrigMsgId==m.mMsgId) // we have a top-level post.
|
||||
top_level_id = m.mMsgId;
|
||||
else if( (it = search_map.find(m.mOrigMsgId)) == search_map.end()) // we don't have the post. Never mind, we store the
|
||||
{
|
||||
top_level_id = m.mOrigMsgId;
|
||||
collected_versions.insert(m.mOrigMsgId); // this one will never be added to the set by the previous call
|
||||
}
|
||||
else
|
||||
{
|
||||
top_level_id = recurs_find_top_level(it->second,collected_versions,newest_time,newest_index,depth+1);
|
||||
posts[index].mMeta.mOrigMsgId = top_level_id; // this fastens calculation because it will skip already seen posts.
|
||||
|
||||
return top_level_id;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << std::string(2*depth,' ') << " top level = " << top_level_id ;
|
||||
#endif
|
||||
auto vit = original_versions.find(top_level_id);
|
||||
|
||||
if(vit != original_versions.end())
|
||||
{
|
||||
if(posts[vit->second.first].mMeta.mPublishTs < newest_time)
|
||||
vit->second.first = newest_index;
|
||||
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << " already existing. " << std::endl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
original_versions[top_level_id].first = newest_index;
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << " new. " << std::endl;
|
||||
#endif
|
||||
}
|
||||
original_versions[top_level_id].second.insert(collected_versions.begin(),collected_versions.end());
|
||||
|
||||
return top_level_id;
|
||||
};
|
||||
|
||||
auto versions_set = std::set<RsGxsMessageId>();
|
||||
recurs_find_top_level(i,versions_set,posts[i].mMeta.mPublishTs,i,0);
|
||||
}
|
||||
|
||||
mPosts.clear();
|
||||
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << " Total top_level posts: " << original_versions.size() << std::endl;
|
||||
|
||||
for(auto it:original_versions)
|
||||
{
|
||||
std::cerr << " Post " << it.first << ". Total versions = " << it.second.second.size() << " latest: " << posts[it.second.first].mMeta.mMsgId << std::endl;
|
||||
|
||||
for(auto m:it.second.second)
|
||||
if(m != it.first)
|
||||
std::cerr << " other (newer version): " << m << std::endl;
|
||||
}
|
||||
#endif
|
||||
// make sure the posts are delivered in the same order they appears in the posts[] tab.
|
||||
|
||||
std::vector<uint32_t> ids;
|
||||
|
||||
for(auto id:original_versions)
|
||||
ids.push_back(id.second.first);
|
||||
|
||||
std::sort(ids.begin(),ids.end());
|
||||
|
||||
for(uint32_t i=0;i<ids.size();++i)
|
||||
{
|
||||
mPosts.push_back(posts[ids[i]]);
|
||||
mPosts.back().mOlderVersions = original_versions[posts[ids[i]].mMeta.mMsgId].second;
|
||||
}
|
||||
|
||||
}
|
||||
void RsGxsChannelPostsModel::setAllMsgReadStatus(bool read_status)
|
||||
{
|
||||
// No need to call preMods()/postMods() here because we're not changing the model
|
||||
|
Loading…
Reference in New Issue
Block a user