/* * libretroshare/src/services p3ranking.cc * * 3P/PQI network interface for RetroShare. * * Copyright 2007-2008 by Robert Fernie. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License Version 2 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. * * Please report all bugs and problems to "retroshare@lunamutt.com". * */ #include "rsrankitems.h" #include "p3ranking.h" #include #include #include "pqi/p3connmgr.h" #include "pqi/pqibin.h" #include "pqi/authssl.h" #include "pqi/pqistore.h" RsRanks *rsRanks = NULL ; const uint32_t RANK_MAX_FWD_OFFSET = (60 * 60 * 24 * 2); /* 2 Days */ const uint32_t RANK_STORE_PERIOD = (60 * 60 * 24 * 30 * 6); /* 6 months */ const uint32_t FRIEND_RANK_REPUBLISH_PERIOD = 60; /* every minute for testing */ //const uint32_t FRIEND_RANK_REPUBLISH_PERIOD = 1800; /* every 30 minutes */ std::string generateRandomLinkId(); /***** * TODO * (1) Streaming. * (2) Ranking. * */ /********* * #define RANK_DEBUG 1 *********/ #define RANK_DEBUG 1 p3Ranking::p3Ranking() : RsCacheService(RS_SERVICE_TYPE_RANK,CONFIG_TYPE_RANK_LINK,5), mRepublish(false), mRepublishFriends(false), mRepublishFriendTS(0), mStorePeriod(RANK_STORE_PERIOD), mUpdated(true),mRankMtx(std::string("p3Ranking")) { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ mOwnId = rsPlugins->getConnectMgr()->getOwnId(); mViewPeriod = 60 * 60 * 24 * 30; /* one Month */ mSortType = RS_RANK_ALG; } bool p3Ranking::loadLocalCache(const CacheData &data) { std::string filename = data.path + '/' + data.name; std::string hash = data.hash; //uint64_t size = data.size; std::string source = data.pid; #ifdef RANK_DEBUG std::cerr << "p3Ranking::loadLocalCache()"; std::cerr << std::endl; std::cerr << "\tSource: " << source; std::cerr << std::endl; std::cerr << "\tFilename: " << filename; std::cerr << std::endl; std::cerr << "\tHash: " << hash; std::cerr << std::endl; std::cerr << "\tSize: " << data.size; std::cerr << std::endl; #endif loadRankFile(filename, source); { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ mRepublish = false; } if (data.size > 0) /* don't refresh zero sized caches */ { refreshCache(data); } return true; } int p3Ranking::loadCache(const CacheData &data) { std::string filename = data.path + '/' + data.name; std::string hash = data.hash; //uint64_t size = data.size; std::string source = data.pid; #ifdef RANK_DEBUG std::cerr << "p3Ranking::loadCache()"; std::cerr << std::endl; std::cerr << "\tSource: " << source; std::cerr << std::endl; std::cerr << "\tFilename: " << filename; std::cerr << std::endl; std::cerr << "\tHash: " << hash; std::cerr << std::endl; std::cerr << "\tSize: " << data.size; std::cerr << std::endl; #endif loadRankFile(filename, source); CacheStore::lockData(); /***** LOCK ****/ locked_storeCacheEntry(data); CacheStore::unlockData(); /***** UNLOCK ****/ return 1; } void p3Ranking::loadRankFile(std::string filename, std::string src) { /* create the serialiser to load info */ RsSerialiser *rsSerialiser = new RsSerialiser(); rsSerialiser->addSerialType(new RsRankSerialiser()); uint32_t bioflags = BIN_FLAGS_HASH_DATA | BIN_FLAGS_READABLE; BinInterface *bio = new BinFileInterface(filename.c_str(), bioflags); pqistore *store = new pqistore(rsSerialiser, src, bio, BIN_FLAGS_READABLE); time_t now = time(NULL); time_t min, max; { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ min = now - mStorePeriod; max = now + RANK_MAX_FWD_OFFSET; } /********** STACK LOCKED MTX ******/ #ifdef RANK_DEBUG std::cerr << "p3Ranking::loadRankFile()"; std::cerr << std::endl; std::cerr << "\tSource: " << src; std::cerr << std::endl; std::cerr << "\tFilename: " << filename; std::cerr << std::endl; #endif RsItem *item; RsRankLinkMsg *newMsg; while(NULL != (item = store->GetItem())) { #ifdef RANK_DEBUG std::cerr << "p3Ranking::loadRankFile() Got Item:"; std::cerr << std::endl; item->print(std::cerr, 10); std::cerr << std::endl; #endif if (NULL == (newMsg = dynamic_cast(item))) { #ifdef RANK_DEBUG std::cerr << "p3Ranking::loadRankFile() Item not LinkMsg (deleting):"; std::cerr << std::endl; #endif delete item; } /* check timestamp */ else if (((time_t) newMsg->timestamp < min) || ((time_t) newMsg->timestamp > max)) { #ifdef RANK_DEBUG std::cerr << "p3Ranking::loadRankFile() Outside TimeRange (deleting):"; std::cerr << std::endl; #endif /* if outside range -> remove */ delete newMsg; } else { #ifdef RANK_DEBUG std::cerr << "p3Ranking::loadRankFile() Loading Item"; std::cerr << std::endl; #endif /* correct the source (if is a message from a friend) */ newMsg->PeerId(newMsg->pid); addRankMsg(newMsg); } } delete store; } void p3Ranking::publishMsgs(bool own) { #ifdef RANK_DEBUG std::cerr << "p3Ranking::publishMsgs()"; std::cerr << std::endl; #endif std::string path = CacheSource::getCacheDir(); std::ostringstream out; uint16_t subid; /* setup name / etc based on whether we're * publishing own or friends... */ if (own) { /* setup to publish own messages */ out << "rank-links-" << time(NULL) << ".rsrl"; subid = 1; } else { /* setup to publish friend messages */ out << "rank-friend-links-" << time(NULL) << ".rsrl"; subid = 2; } /* determine filename */ std::string tmpname = out.str(); std::string fname = path + "/" + tmpname; #ifdef RANK_DEBUG std::cerr << "p3Ranking::publishMsgs() Storing to: " << fname; std::cerr << std::endl; #endif RsSerialiser *rsSerialiser = new RsSerialiser(); rsSerialiser->addSerialType(new RsRankSerialiser()); uint32_t bioflags = BIN_FLAGS_HASH_DATA | BIN_FLAGS_WRITEABLE; BinInterface *bio = new BinFileInterface(fname.c_str(), bioflags); pqistore *store = new pqistore(rsSerialiser, mOwnId, bio, BIN_FLAGS_NO_DELETE | BIN_FLAGS_WRITEABLE); { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ /* iterate through list */ std::map::iterator it; std::map::iterator cit; for(it = mData.begin(); it != mData.end(); it++) { if (own) { if (it->second.ownTag) { /* write to serialiser */ RsItem *item = it->second.comments[mOwnId]; if (item) { #ifdef RANK_DEBUG std::cerr << "p3Ranking::publishMsgs() Storing Item:"; std::cerr << std::endl; item->print(std::cerr, 10); std::cerr << std::endl; #endif store->SendItem(item); } } else { #ifdef RANK_DEBUG std::cerr << "p3Ranking::publishMsgs() Skipping Foreign item"; std::cerr << std::endl; #endif } } else { /* if we have pushed it out already - don't bother */ if (it->second.ownTag) { #ifdef RANK_DEBUG std::cerr << "p3Ranking::publishMsgs() (Friends) Skipping Own Item"; std::cerr << std::endl; #endif continue; } /* if we have some comments ... then a friend has recommended it * serialise a sanitized version. */ if (it->second.comments.size() > 0) { RsRankLinkMsg *origmsg = (it->second.comments.begin())->second; RsRankLinkMsg *msg = new RsRankLinkMsg(); /* copy anon data */ /*************************************************************************/ /****************************** LINK SPECIFIC ****************************/ /*************************************************************************/ msg->clear(); msg->PeerId(""); msg->pid = ""; /* Anon */ msg->rid = origmsg->rid; msg->link = origmsg->link; msg->title = origmsg->title; msg->timestamp = origmsg->timestamp; msg->score = 0; #ifdef RANK_DEBUG std::cerr << "p3Ranking::publishMsgs() (Friends) Storing (Anon) Item:"; std::cerr << std::endl; msg->print(std::cerr, 10); std::cerr << std::endl; #endif store->SendItem(msg); /* cleanup */ delete msg; } } } /* now we also add our anon messages to the friends list */ if (!own) { std::list::iterator ait; for(ait=mAnon.begin(); ait != mAnon.end(); ait++) { #ifdef RANK_DEBUG std::cerr << "p3Ranking::publishMsgs() (Friends) Adding Own Anon Item:"; std::cerr << std::endl; (*ait)->print(std::cerr, 10); std::cerr << std::endl; #endif store->SendItem(*ait); } } } /********** STACK LOCKED MTX ******/ /* flag as new info */ CacheData data; { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ data.pid = mOwnId; } /********** STACK LOCKED MTX ******/ data.cid = CacheId(CacheSource::getCacheType(), subid); data.path = path; data.name = tmpname; data.hash = bio->gethash(); data.size = bio->bytecount(); data.recvd = time(NULL); #ifdef RANK_DEBUG std::cerr << "p3Ranking::publishMsgs() refreshing Cache"; std::cerr << std::endl; std::cerr << "\tCache Path: " << data.path; std::cerr << std::endl; std::cerr << "\tCache Name: " << data.name; std::cerr << std::endl; std::cerr << "\tCache Hash: " << data.hash; std::cerr << std::endl; std::cerr << "\tCache Size: " << data.size; std::cerr << std::endl; #endif if (data.size > 0) /* don't refresh zero sized caches */ { refreshCache(data); } delete store; } void p3Ranking::addRankMsg(RsRankLinkMsg *msg) { /* find msg */ std::string id = msg->PeerId(); std::string rid = msg->rid; #ifdef RANK_DEBUG std::cerr << "p3Ranking::addRankMsg() Item:"; std::cerr << std::endl; msg->print(std::cerr, 10); std::cerr << std::endl; #endif RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ std::map::iterator it; it = mData.find(rid); if (it == mData.end()) { /* add a new one */ RankGroup grp; grp.rid = rid; grp.ownTag = false; grp.rank = 0.0f; /*************************************************************************/ /****************************** LINK SPECIFIC ****************************/ /*************************************************************************/ grp.link = msg->link; grp.title = msg->title; /*************************************************************************/ /****************************** LINK SPECIFIC ****************************/ /*************************************************************************/ mData[rid] = grp; it = mData.find(rid); if (id == "") { #ifdef RANK_DEBUG std::cerr << "p3Ranking::addRankMsg() New Anon Link: mUpdated = true"; std::cerr << std::endl; #endif locked_reSortGroup(it->second); mUpdated = true; } } /**** If it is an anonymous Link (ie Friend of a Friend) Drop out now ***/ if (id == "") { return; } /* check for old comment */ std::map::iterator cit; cit = (it->second).comments.find(id); /* Check that it is different! */ bool newComment = false; if ((it->second).comments.end() == cit) { newComment = true; } else { RsRankLinkMsg *old = cit->second; if ((msg->timestamp != old->timestamp) || (msg->comment != old->comment)) { newComment = true; } } if (newComment) { #ifdef RANK_DEBUG std::cerr << "p3Ranking::addRankMsg() New Comment"; std::cerr << std::endl; #endif /* clean up old */ if ((it->second).comments.end() != cit) { delete (cit->second); (it->second).comments.erase(cit); } /* add in */ (it->second).comments[id] = msg; /* republish? */ if (id == mOwnId) { it->second.ownTag = true; mRepublish = true; #ifdef RANK_DEBUG std::cerr << "p3Ranking::addRankMsg() Own Comment: mRepublish = true"; std::cerr << std::endl; #endif } else { mRepublishFriends = true; #ifdef RANK_DEBUG std::cerr << "p3Ranking::addRankMsg() Other Comment: mRepublishFriends = true"; std::cerr << "p3Ranking::addRankMsg() Old Comment ignoring"; std::cerr << std::endl; #endif } locked_reSortGroup(it->second); mUpdated = true; } else { delete msg; #ifdef RANK_DEBUG std::cerr << "p3Ranking::addRankMsg() Old Comment ignoring"; std::cerr << std::endl; #endif } } /***************** Sorting ****************/ bool p3Ranking::setSortPeriod(uint32_t period) { bool reSort = false; { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ reSort = (mViewPeriod != period); mViewPeriod = period; } if (reSort) { sortAllMsgs(); } return true; } bool p3Ranking::setSortMethod(uint32_t type) { bool reSort = false; { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ reSort = (mSortType != type); mSortType = type; } if (reSort) { sortAllMsgs(); } return true; } bool p3Ranking::clearPeerFilter() { bool reSort = false; { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ reSort = (mPeerFilter.size() > 0); mPeerFilter.clear(); } if (reSort) { sortAllMsgs(); } return true; } bool p3Ranking::setPeerFilter(std::list peers) { { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ mPeerFilter = peers; } sortAllMsgs(); return true; } float p3Ranking::locked_calcRank(RankGroup &grp) { /* Ranking Calculations ..... */ time_t now = time(NULL); time_t minTime = now-mViewPeriod; bool doFilter = (mPeerFilter.size() > 0); bool doScore = (mSortType & RS_RANK_SCORE); bool doTime = (mSortType & RS_RANK_TIME); uint32_t count = 0; float algScore = 0; float comboScore = 0; float popScore = 0; #ifdef RANK_DEBUG std::string normlink(grp.link.begin(), grp.link.end()); std::cerr << "p3Ranking::locked_calcRank() for: " << normlink; std::cerr << std::endl; std::cerr << "Period: " << mViewPeriod; std::cerr << " doFilter: " << doFilter; std::cerr << " doScore: " << doScore; std::cerr << " doTime: " << doTime; std::cerr << std::endl; #endif std::map::iterator it; for(it = grp.comments.begin(); it != grp.comments.end(); it++) { #ifdef RANK_DEBUG std::cerr << "Comment by:" << it->first << " age: " << now - it->second->timestamp; std::cerr << std::endl; #endif if (doFilter) { if (mPeerFilter.end() == std::find(mPeerFilter.begin(), mPeerFilter.end(), it->first)) { continue; /* skip it */ #ifdef RANK_DEBUG std::cerr << "\tFiltered Out"; std::cerr << std::endl; #endif } } /* if Scoring is involved... drop old ones */ if ((doScore) && ((time_t) it->second->timestamp < minTime)) { #ifdef RANK_DEBUG std::cerr << "\tToo Old"; std::cerr << std::endl; #endif continue; } time_t deltaT; if ((time_t) it->second->timestamp > now) { deltaT = it->second->timestamp - now; } else { deltaT = now - it->second->timestamp; } float timeScore = ((float) mViewPeriod - deltaT) / (mViewPeriod + 0.01); #ifdef RANK_DEBUG std::cerr << "\tTimeScore: " << timeScore; std::cerr << std::endl; #endif /* algScore is sum of (filtered) timeScores */ /* timeScore is average of (all) timeScores */ /* popScore is just count of valid scores */ algScore += timeScore; count++; /* for more advanced scoring (where each peer gives a score +2 -> -2) */ /* combo = SUM value * timeScore */ /* time = same as before (average) */ /* popScore = SUM value */ float value = it->second->score; comboScore += value * timeScore; popScore += value; } #ifdef RANK_DEBUG std::cerr << "p3Ranking::locked_calcRank() algScore: " << algScore; std::cerr << " Count: " << count; std::cerr << std::endl; #endif if ((count <= 0) || (algScore <= 0)) { #ifdef RANK_DEBUG std::cerr << "Final score: 0"; std::cerr << std::endl; #endif return 0; } if ((doScore) && (doTime)) { #ifdef RANK_DEBUG std::cerr << "Old (alg) score:" << algScore; std::cerr << std::endl; std::cerr << "Final (Combo) score:" << comboScore; std::cerr << std::endl; #endif if (comboScore < 0) { #ifdef RANK_DEBUG std::cerr << "Combo score reset = 0"; std::cerr << std::endl; #endif comboScore = 0; } return comboScore; } else if (doScore) { #ifdef RANK_DEBUG std::cerr << "Old (tally) score:" << count; std::cerr << std::endl; std::cerr << "Final (pop) score:" << popScore; std::cerr << std::endl; #endif if (popScore < 0) { #ifdef RANK_DEBUG std::cerr << "Pop score reset = 0"; std::cerr << std::endl; #endif popScore = 0; } return popScore; } else if (doTime) { #ifdef RANK_DEBUG std::cerr << "Final (time) score:" << algScore / count; std::cerr << std::endl; #endif return algScore / count; } return 0; } void p3Ranking::locked_reSortGroup(RankGroup &grp) { std::string rid = grp.rid; /* remove from existings rankings */ std::multimap::iterator rit; rit = mRankings.lower_bound(grp.rank); for(; (rit != mRankings.end()) && (rit->first == grp.rank); rit++) { if (rit->second == rid) { mRankings.erase(rit); break; } } /* add it back in */ grp.rank = locked_calcRank(grp); mRankings.insert( std::pair(grp.rank, rid)); } void p3Ranking::sortAllMsgs() { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ /* iterate through list and re-score each one */ std::map::iterator it; mRankings.clear(); for(it = mData.begin(); it != mData.end(); it++) { (it->second).rank = locked_calcRank(it->second); if (it->second.rank < 0) { it->second.rank = 0; } mRankings.insert( std::pair (it->second.rank, it->first)); } } /******** ACCESS *************/ /* get Ids */ uint32_t p3Ranking::getRankingsCount() { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ return mRankings.size(); } float p3Ranking::getMaxRank() { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ if (mRankings.size() == 0) return 0; return mRankings.rbegin()->first; } bool p3Ranking::getRankings(uint32_t first, uint32_t count, std::list &rids) { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ #ifdef RANK_DEBUG std::cerr << "p3Ranking::getRankings() First: " << first << " Count: " << count; std::cerr << std::endl; #endif uint32_t i = 0; std::multimap::reverse_iterator rit; for(rit = mRankings.rbegin(); (i < first) && (rit != mRankings.rend()); rit++, i++); i = 0; for(; (i < count) && (rit != mRankings.rend()); rit++, i++) { rids.push_back(rit->second); } return true; } bool p3Ranking::getRankDetails(std::string rid, RsRankDetails &details) { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ /* get the details. */ std::map::iterator it; it = mData.find(rid); if (mData.end() == it) { return false; } /*************************************************************************/ /****************************** LINK SPECIFIC ****************************/ /*************************************************************************/ details.rid = it->first; details.link = (it->second).link; details.title = (it->second).title; details.rank = (it->second).rank; details.ownTag = (it->second).ownTag; /*************************************************************************/ /****************************** LINK SPECIFIC ****************************/ /*************************************************************************/ std::map::iterator cit; for(cit = (it->second).comments.begin(); cit != (it->second).comments.end(); cit++) { RsRankComment comm; comm.id = (cit->second)->PeerId(); comm.timestamp = (cit->second)->timestamp; comm.comment = (cit->second)->comment; comm.score = (cit->second)->score; details.comments.push_back(comm); } return true; } void p3Ranking::tick() { bool repub = false; bool repubFriends = false; { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ repub = mRepublish; repubFriends = mRepublishFriends && (time(NULL) > mRepublishFriendTS); } if (repub) { publishMsgs(true); RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ mRepublish = false; } if (repubFriends) { publishMsgs(false); RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ mRepublishFriends = false; mRepublishFriendTS = time(NULL) + FRIEND_RANK_REPUBLISH_PERIOD; } } bool p3Ranking::updated() { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ if (mUpdated) { mUpdated = false; return true; } return false; } /***** NEW CONTENT *****/ /*************************************************************************/ /****************************** LINK SPECIFIC ****************************/ /*************************************************************************/ std::string p3Ranking::newRankMsg(std::wstring link, std::wstring title, std::wstring comment, int32_t score) { /* generate an id */ std::string rid = generateRandomLinkId(); RsRankLinkMsg *msg = new RsRankLinkMsg(); time_t now = time(NULL); { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ msg->PeerId(mOwnId); msg->pid = mOwnId; } msg->rid = rid; msg->title = title; msg->timestamp = now; msg->comment = comment; msg->score = score; msg->linktype = RS_LINK_TYPE_WEB; msg->link = link; addRankMsg(msg); return rid; } /*************************************************************************/ /****************************** LINK SPECIFIC ****************************/ /*************************************************************************/ bool p3Ranking::updateComment(std::string rid, std::wstring comment, int32_t score) { #ifdef RANK_DEBUG std::cerr << "p3Ranking::updateComment() rid:" << rid; std::cerr << std::endl; #endif RsRankLinkMsg *msg = NULL; { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ std::map::iterator it; it = mData.find(rid); if (it == mData.end()) { /* missing group -> fail */ #ifdef RANK_DEBUG std::cerr << "p3Ranking::updateComment() Failed - noData"; std::cerr << std::endl; #endif return false; } msg = new RsRankLinkMsg(); time_t now = time(NULL); msg->PeerId(mOwnId); msg->pid = mOwnId; msg->rid = rid; msg->timestamp = now; msg->title = (it->second).title; msg->comment = comment; msg->score = score; msg->linktype = RS_LINK_TYPE_WEB; msg->link = (it->second).link; } /********** STACK UNLOCKED MTX ******/ #ifdef RANK_DEBUG std::cerr << "p3Ranking::updateComment() Item:"; std::cerr << std::endl; msg->print(std::cerr, 10); std::cerr << std::endl; #endif addRankMsg(msg); return true; } /*************************************************************************/ /****************************** LINK SPECIFIC ****************************/ /*************************************************************************/ std::string p3Ranking::anonRankMsg(std::string rid, std::wstring link, std::wstring title) { bool alreadyExists = true; if (rid == "") { alreadyExists = false; /* generate an id */ rid = generateRandomLinkId(); } RsRankLinkMsg *msg1 = new RsRankLinkMsg(); RsRankLinkMsg *msg2 = new RsRankLinkMsg(); time_t now = time(NULL); { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ msg1->PeerId(""); msg1->pid = ""; msg2->PeerId(""); msg2->pid = ""; } msg1->rid = rid; msg1->title = title; msg1->timestamp = now; msg1->comment.clear(); msg1->score = 0; msg1->linktype = RS_LINK_TYPE_WEB; msg1->link = link; msg2->rid = rid; msg2->title = title; msg2->timestamp = now; msg2->comment.clear(); msg2->score = 0; msg2->linktype = RS_LINK_TYPE_WEB; msg2->link = link; if (alreadyExists) { delete msg1; } else { addRankMsg(msg1); } addAnonToList(msg2); return rid; } pqistore *createStore(std::string file, std::string src, bool reading) { RsSerialiser *rsSerialiser = new RsSerialiser(); rsSerialiser->addSerialType(new RsRankSerialiser()); uint32_t bioflags = BIN_FLAGS_HASH_DATA; if (reading) { bioflags |= BIN_FLAGS_READABLE; } else { bioflags |= BIN_FLAGS_WRITEABLE; } /* bin flags: READ | WRITE | HASH_DATA */ BinInterface *bio = new BinFileInterface(file.c_str(), bioflags); /* store flags: NO_DELETE (yes) | NO_CLOSE (no) */ pqistore *store = new pqistore(rsSerialiser, src, bio, BIN_FLAGS_NO_DELETE | (bioflags & BIN_FLAGS_WRITEABLE)); return store; } std::string generateRandomLinkId() { std::ostringstream out; out << std::hex; /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ #ifndef WINDOWS_SYS /* 4 bytes per random number: 4 x 4 = 16 bytes */ for(int i = 0; i < 4; i++) { out << std::setw(8) << std::setfill('0'); uint32_t rint = random(); out << rint; } #else srand(time(NULL)); /* 2 bytes per random number: 8 x 2 = 16 bytes */ for(int i = 0; i < 8; i++) { out << std::setw(4) << std::setfill('0'); uint16_t rint = rand(); /* only gives 16 bits */ out << rint; } #endif /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ return out.str(); } /*************************************************************************/ /****************************** LINK SPECIFIC ****************************/ /*************************************************************************/ void p3Ranking::createDummyData() { RsRankLinkMsg *msg = new RsRankLinkMsg(); time_t now = time(NULL); msg->PeerId(mOwnId); msg->pid = mOwnId; msg->rid = "0001"; msg->title = L"Original Awesome Site!"; msg->timestamp = now - 60 * 60 * 24 * 15; msg->link = L"http://www.retroshare.org"; msg->comment = L"Retroshares Website"; msg->score = 1; addRankMsg(msg); msg = new RsRankLinkMsg(); msg->PeerId(mOwnId); msg->pid = mOwnId; msg->rid = "0002"; msg->title = L"Awesome Site!"; msg->timestamp = now - 123; msg->link = L"http://www.lunamutt.org"; msg->comment = L"Lunamutt's Website"; msg->score = 1; addRankMsg(msg); msg = new RsRankLinkMsg(); msg->PeerId("ALTID"); msg->pid = "ALTID"; msg->rid = "0002"; msg->title = L"Awesome Site!"; msg->timestamp = now - 60 * 60 * 24 * 29; msg->link = L"http://www.lunamutt.org"; msg->comment = L"Lunamutt's Website (TWO) How Long can this comment be!\n"; msg->comment += L"What happens to the second line?\n"; msg->comment += L"And a 3rd!"; msg->score = 1; addRankMsg(msg); msg = new RsRankLinkMsg(); msg->PeerId("ALTID2"); msg->pid = "ALTID2"; msg->rid = "0002"; msg->title = L"Awesome Site!"; msg->timestamp = now - 60 * 60 * 7; msg->link = L"http://www.lunamutt.org"; msg->comment += L"A Short Comment"; msg->score = 1; addRankMsg(msg); /***** Third one ****/ msg = new RsRankLinkMsg(); msg->PeerId(mOwnId); msg->pid = mOwnId; msg->rid = "0003"; msg->title = L"Weird Site!"; msg->timestamp = now - 60 * 60; msg->link = L"http://www.lunamutt.com"; msg->comment = L""; msg->score = 1; addRankMsg(msg); msg = new RsRankLinkMsg(); msg->PeerId("ALTID"); msg->pid = "ALTID"; msg->rid = "0003"; msg->title = L"Weird Site!"; msg->timestamp = now - 60 * 60 * 24 * 2; msg->link = L"http://www.lunamutt.com"; msg->comment = L""; msg->score = 1; addRankMsg(msg); } /***************************************************************************/ /****************************** CONFIGURATION HANDLING *********************/ /***************************************************************************/ /**** Store Anon Links: OVERLOADED FROM p3Config ****/ RsSerialiser *p3Ranking::setupSerialiser() { RsSerialiser *rss = new RsSerialiser(); /* add in the types we need! */ rss->addSerialType(new RsRankSerialiser()); return rss; } bool p3Ranking::addAnonToList(RsRankLinkMsg *msg) { { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ std::list::iterator it; for(it = mAnon.begin(); it != mAnon.end(); it++) { if (msg->rid == (*it)->rid) break; } if (it != mAnon.end()) { delete msg; return false; } mAnon.push_back(msg); mRepublishFriends = true; } IndicateConfigChanged(); /**** INDICATE CONFIG CHANGED! *****/ return true; } bool p3Ranking::saveList(bool &cleanup, std::list & saveData) { mRankMtx.lock(); /*********************** LOCK *******/ cleanup = false; std::list::iterator it; for(it = mAnon.begin(); it != mAnon.end(); it++) { saveData.push_back(*it); } /* list completed! */ return true; } void p3Ranking::saveDone() { mRankMtx.unlock(); /*********************** UNLOCK *******/ return; } bool p3Ranking::loadList(std::list& load) { std::list::iterator it; RsRankLinkMsg *msg; #ifdef SERVER_DEBUG std::cerr << "p3Ranking::loadList() Item Count: " << load.size(); std::cerr << std::endl; #endif time_t now = time(NULL); time_t min, max; { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ min = now - mStorePeriod; max = now + RANK_MAX_FWD_OFFSET; } /********** STACK LOCKED MTX ******/ for(it = load.begin(); it != load.end(); it++) { /* switch on type */ if (NULL != (msg = dynamic_cast(*it))) { /* check date -> if old expire */ if (((time_t) msg->timestamp < min) || ((time_t) msg->timestamp > max)) { #ifdef RANK_DEBUG std::cerr << "p3Ranking::loadList() Outside TimeRange (deleting Own Anon):"; std::cerr << std::endl; #endif /* if outside range -> remove */ delete msg; continue; } #ifdef RANK_DEBUG std::cerr << "p3Ranking::loadList() Anon TimeRange ok"; std::cerr << std::endl; #endif msg->PeerId(""); msg->pid = ""; RsRankLinkMsg *msg2 = new RsRankLinkMsg(); msg2->clear(); msg2->PeerId(msg->PeerId()); msg2->pid = msg->pid; msg2->rid = msg->rid; msg2->title = msg->title; msg2->timestamp = msg->timestamp; msg2->comment.clear(); msg2->score = 0; msg2->linktype = msg->linktype; msg2->link = msg->link; /* make a copy to add into standard map */ addRankMsg(msg); RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ mAnon.push_back(msg2); } else { /* cleanup */ delete (*it); } } return true; }