/* * 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 "services/p3photoservice.h" #include "pqi/pqibin.h" #include "pqi/p3authmgr.h" #include "util/rsdir.h" std::string generateRandomShowId(); /**** * #define PHOTO_DEBUG 1 ****/ PhotoSet::PhotoSet() { return; } /********************************************************************************/ /******************* Startup / Tick ******************************************/ /********************************************************************************/ p3PhotoService::p3PhotoService(uint16_t type, CacheStrapper *cs, CacheTransfer *cft, std::string sourcedir, std::string storedir) :CacheSource(type, true, cs, sourcedir), CacheStore(type, true, cs, cft, storedir), mUpdated(true) { { RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ mOwnId = getAuthMgr()->OwnId(); } // createDummyData(); return; } void p3PhotoService::tick() { bool repub = false; { RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ repub = mRepublish; } if (repub) { //publishPhotos(); RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ mRepublish = false; } } /********************************************************************************/ /******************* Cache Interaction ******************************************/ /********************************************************************************/ bool p3PhotoService::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 PHOTO_DEBUG std::cerr << "p3PhotoService::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 if (data.cid.subid == 0) { loadPhotoIndex(filename, hash, source); } else { availablePhoto(filename, hash, source); } { RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ mRepublish = false; mUpdated = true; } if (data.size > 0) /* don't refresh zero sized caches */ { refreshCache(data); } return true; } int p3PhotoService::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 PHOTO_DEBUG std::cerr << "p3PhotoService::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 if (data.cid.subid == 0) { loadPhotoIndex(filename, hash, source); } else { availablePhoto(filename, hash, source); } CacheStore::lockData(); /***** LOCK ****/ locked_storeCacheEntry(data); CacheStore::unlockData(); /***** UNLOCK ****/ return 1; } void p3PhotoService::loadPhotoIndex(std::string filename, std::string hash, std::string src) { /* create the serialiser to load info */ RsSerialiser *rsSerialiser = new RsSerialiser(); rsSerialiser->addSerialType(new RsPhotoSerialiser()); uint32_t bioflags = BIN_FLAGS_HASH_DATA | BIN_FLAGS_READABLE; BinInterface *bio = new BinFileInterface(filename.c_str(), bioflags); pqistreamer *stream = new pqistreamer(rsSerialiser, src, bio, 0); #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::loadPhotoIndex()"; std::cerr << std::endl; std::cerr << "\tSource: " << src; std::cerr << std::endl; std::cerr << "\tHash: " << hash; std::cerr << std::endl; std::cerr << "\tFilename: " << filename; std::cerr << std::endl; #endif RsItem *item; RsPhotoItem *pitem; RsPhotoShowItem *sitem; stream->tick(); /* Tick to read! */ while(NULL != (item = stream->GetItem())) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::loadPhotoIndex() Got Item:"; std::cerr << std::endl; item->print(std::cerr, 10); std::cerr << std::endl; #endif pitem = dynamic_cast(item); sitem = dynamic_cast(item); if (pitem) { /* photo item */ #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::loadPhotoIndex() Loading Photo Item"; std::cerr << std::endl; #endif loadPhotoItem(pitem); } else if (sitem) { /* show item */ #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::loadPhotoIndex() Loading Show Item"; std::cerr << std::endl; #endif loadPhotoShowItem(sitem); } else { /* unknown */ #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::loadRankFile() Unknown Item (deleting):"; std::cerr << std::endl; #endif } delete item; stream->tick(); /* Tick to read! */ } delete stream; } bool p3PhotoService::loadPhotoItem(RsPhotoItem *item) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::loadPhotoItem()"; std::cerr << std::endl; item->print(std::cerr); std::cerr << std::endl; #endif RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ PhotoSet &pset = locked_getPhotoSet(item->PeerId()); pset.photos[item->photoId] = item; mUpdated = true; return true; } bool p3PhotoService::loadPhotoShowItem(RsPhotoShowItem *item) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::loadPhotoShowItem()"; std::cerr << std::endl; item->print(std::cerr); std::cerr << std::endl; #endif /* add to set */ RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ PhotoSet &pset = locked_getPhotoSet(item->PeerId()); pset.shows[item->showId] = item; //mRepublish = true; mUpdated = true; return true; } void p3PhotoService::availablePhoto(std::string filename, std::string hash, std::string src) { /* TODO */ return; } void p3PhotoService::publishPhotos() { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::publishPhotos()"; std::cerr << std::endl; #endif /* determine filename */ std::string path = CacheSource::getCacheDir(); std::ostringstream out; out << "photo-index-" << time(NULL) << ".pdx"; std::string tmpname = out.str(); std::string fname = path + "/" + tmpname; #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::publishPhotos() Storing to: " << fname; std::cerr << std::endl; #endif RsSerialiser *rsSerialiser = new RsSerialiser(); rsSerialiser->addSerialType(new RsPhotoSerialiser()); uint32_t bioflags = BIN_FLAGS_HASH_DATA | BIN_FLAGS_WRITEABLE; BinInterface *bio = new BinFileInterface(fname.c_str(), bioflags); pqistreamer *stream = new pqistreamer(rsSerialiser, mOwnId, bio, BIN_FLAGS_NO_DELETE); { RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ PhotoSet &pset = locked_getPhotoSet(mOwnId); std::map::iterator pit; for(pit = pset.photos.begin(); pit != pset.photos.end(); pit++) { RsPhotoItem *pitem = pit->second; #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::publishPhotos() Storing Photo Item:"; std::cerr << std::endl; pitem->print(std::cerr, 10); std::cerr << std::endl; #endif stream->SendItem(pitem); stream->tick(); /* Tick to write! */ } std::map::iterator sit; for(sit = pset.shows.begin(); sit != pset.shows.end(); sit++) { RsPhotoShowItem *sitem = sit->second; #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::publishPhotos() Storing PhotoShow Item:"; std::cerr << std::endl; sitem->print(std::cerr, 10); std::cerr << std::endl; #endif stream->SendItem(sitem); stream->tick(); /* Tick to write! */ } } /********** STACK LOCKED MTX ******/ stream->tick(); /* Tick for final write! */ /* flag as new info */ CacheData data; { RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ data.pid = mOwnId; } /********** STACK LOCKED MTX ******/ data.cid = CacheId(CacheSource::getCacheType(), 1); data.path = path; data.name = tmpname; data.hash = bio->gethash(); data.size = bio->bytecount(); data.recvd = time(NULL); #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::publishPhotos() 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 stream; /* TO HERE * update Cache (new Photos (all Photos?)) * */ } /********************************************************************************/ /******************* External Interface *****************************************/ /********************************************************************************/ bool p3PhotoService::updated() { RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ if (mUpdated) { mUpdated = false; return true; } return false; } bool p3PhotoService::getPhotoList(std::string id, std::list &photoIds) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::getPhotoList() pid: " << id; std::cerr << std::endl; #endif RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ PhotoSet &pset = locked_getPhotoSet(id); /* get the list of photoids */ std::map::iterator pit; for(pit = pset.photos.begin(); pit != pset.photos.end(); pit++) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::getPhotoList() PhotoId: " << pit->first; std::cerr << std::endl; #endif photoIds.push_back(pit->first); } return true; } bool p3PhotoService::getShowList(std::string id, std::list &showIds) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::getShowList() pid: " << id; std::cerr << std::endl; #endif RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ PhotoSet &pset = locked_getPhotoSet(id); /* get the list of showIds */ std::map::iterator sit; for(sit = pset.shows.begin(); sit != pset.shows.end(); sit++) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::getShowList() ShowId: " << sit->first; std::cerr << std::endl; #endif showIds.push_back(sit->first); } return true; } bool p3PhotoService::getShowDetails(std::string id, std::string showId, RsPhotoShowDetails &detail) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::getShowDetails() pid: " << id; std::cerr << "showId: " << showId; std::cerr << std::endl; #endif RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ RsPhotoShowItem *item = locked_getShow(id, showId); if (!item) { return false; } /* extract Show details */ return true; } bool p3PhotoService::getPhotoDetails(std::string id, std::string photoId, RsPhotoDetails &detail) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::getPhotoDetails() pid: " << id; std::cerr << " photoId: " << photoId; std::cerr << std::endl; #endif RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ RsPhotoItem *item = locked_getPhoto(id, photoId); if (!item) { return false; } /* extract Photo details */ detail.id = item->PeerId(); detail.srcid = item->srcId; detail.hash = item->photoId; detail.size = item->size; detail.name = item->name; detail.location = item->location; detail.comment = item->comment; detail.date = item->date; detail.format = 0; detail.isAvailable = item->isAvailable; detail.path = item->path; return true; } /* add / delete */ std::string p3PhotoService::createShow(std::string name) { std::string showId = generateRandomShowId(); RsPhotoShowItem *newShow = new RsPhotoShowItem(); newShow->showId = showId; newShow->name = name; /* add to set */ RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ PhotoSet &pset = locked_getPhotoSet(mOwnId); pset.shows[showId] = newShow; mRepublish = true; return showId; } bool p3PhotoService::deleteShow(std::string showId) { /* add to set */ RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ PhotoSet &pset = locked_getPhotoSet(mOwnId); std::map::iterator sit; sit = pset.shows.find(showId); if (sit == pset.shows.end()) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::deleteShow() no existant"; std::cerr << std::endl; #endif return false; } RsPhotoShowItem *oldShow = sit->second; pset.shows.erase(sit); delete oldShow; mRepublish = true; return true; } bool p3PhotoService::addPhotoToShow(std::string showId, std::string photoId, int16_t index) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::addPhotoToShow() showId: " << showId; std::cerr << " photoId: " << photoId; std::cerr << std::endl; #endif /* add to set */ RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ RsPhotoItem *photo = locked_getPhoto(mOwnId, photoId); RsPhotoShowItem *show = locked_getShow(mOwnId, showId); if ((!photo) || (!show)) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::addPhotoToShow() NULL data"; std::cerr << std::endl; #endif return false; } /* can have duplicates so just add it in */ RsPhotoRefItem ref; ref.photoId = photoId; /* add in at correct location! */ //uint32_t i = 0; //for(it = show.photos.begin(); // (i < index) && (it != show.photos.end()); it++, i++); show->photos.push_back(ref); mRepublish = true; return true; } bool p3PhotoService::movePhotoInShow(std::string showId, std::string photoId, int16_t index) { return false; } bool p3PhotoService::removePhotoFromShow(std::string showId, std::string photoId) { return false; } std::string p3PhotoService::addPhoto(std::string path) /* add from file */ { /* check file exists */ std::string hash; uint64_t size; if (!RsDirUtil::getFileHash(path, hash, size)) { return hash; } /* copy to outgoing directory TODO */ /* create item */ RsPhotoItem *item = new RsPhotoItem(); { RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ item->PeerId(mOwnId); } item->srcId = item->PeerId(); item->photoId = hash; item->name = RsDirUtil::getTopDir(path); item->path = path; item->size = size; item->isAvailable = true; item->comment = L"No Comment Yet!"; /* add in */ loadPhotoItem(item); /* flag for republish */ { RsStackMutex stack(mPhotoMtx); /********** STACK LOCKED MTX ******/ mRepublish = true; } return hash; } bool p3PhotoService::addPhoto(std::string srcId, std::string photoId) /* add from peers photos */ { return false; } bool p3PhotoService::deletePhoto(std::string photoId) { return false; } /* modify properties (TODO) */ bool p3PhotoService::modifyShow(std::string showId, std::wstring name, std::wstring comment) { return false; } bool p3PhotoService::modifyPhoto(std::string photoId, std::wstring name, std::wstring comment) { return false; } bool p3PhotoService::modifyShowComment(std::string showId, std::string photoId, std::wstring comment) { return false; } /********************************************************************************/ /******************* Utility Functions ******************************************/ /********************************************************************************/ PhotoSet &p3PhotoService::locked_getPhotoSet(std::string id) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::locked_getPhotoSet() pid: " << id; std::cerr << std::endl; #endif std::map::iterator it; it = mPhotos.find(id); if (it == mPhotos.end()) { /* missing group -> add it in */ PhotoSet pset; pset.pid = id; mPhotos[id] = pset; it = mPhotos.find(id); } return (it->second); } RsPhotoItem *p3PhotoService::locked_getPhoto(std::string id, std::string photoId) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::locked_getPhoto() pid: " << id; std::cerr << " photoId: " << photoId; std::cerr << std::endl; #endif PhotoSet &pset = locked_getPhotoSet(id); std::map::iterator pit; pit = pset.photos.find(photoId); if (pit == pset.photos.end()) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::getPhotoDetails() Failed - noPhoto"; std::cerr << std::endl; #endif return NULL; } return pit->second; } RsPhotoShowItem *p3PhotoService::locked_getShow(std::string id, std::string showId) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::locked_getShow() pid: " << id; std::cerr << " showId: " << showId; std::cerr << std::endl; #endif PhotoSet &pset = locked_getPhotoSet(id); std::map::iterator sit; sit = pset.shows.find(showId); if (sit == pset.shows.end()) { #ifdef PHOTO_DEBUG std::cerr << "p3PhotoService::locked_getShow() Failed - no Show"; std::cerr << std::endl; #endif return NULL; } return sit->second; } std::string generateRandomShowId() { 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(); } void p3PhotoService::createDummyData() { #if 0 RsRankLinkMsg *msg = new RsRankLinkMsg(); time_t now = time(NULL); msg->PeerId(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"; addRankMsg(msg); msg = new RsRankLinkMsg(); msg->PeerId(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"; addRankMsg(msg); msg = new RsRankLinkMsg(); msg->PeerId("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!"; addRankMsg(msg); msg = new RsRankLinkMsg(); msg->PeerId("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"; addRankMsg(msg); /***** Third one ****/ msg = new RsRankLinkMsg(); msg->PeerId(mOwnId); msg->rid = "0003"; msg->title = L"Weird Site!"; msg->timestamp = now - 60 * 60; msg->link = L"http://www.lunamutt.com"; msg->comment = L""; addRankMsg(msg); msg = new RsRankLinkMsg(); msg->PeerId("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""; addRankMsg(msg); #endif }