/* * libretroshare/src/services: p3statusservice.cc * * RetroShare C++ . * * Copyright 2008 by Vinny Do, Chris Evi-Parker. * * 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/p3statusservice.h" #include "serialiser/rsstatusitems.h" #include #include #include #include std::ostream& operator<<(std::ostream& out, const StatusInfo& si) { out << "StatusInfo: " << std::endl; out << "id: " << si.id << std::endl; out << "status: " << si.status << std::endl; out << "time_stamp: " << si.time_stamp << std::endl; return out; } RsStatus *rsStatus = NULL; p3StatusService::p3StatusService(p3ConnectMgr *cm) :p3Service(RS_SERVICE_TYPE_STATUS), p3Config(CONFIG_TYPE_STATUS), mConnMgr(cm) { addSerialType(new RsStatusSerialiser()); } p3StatusService::~p3StatusService() { } bool p3StatusService::getOwnStatus(StatusInfo& statusInfo) { std::map::iterator it; std::string ownId = mConnMgr->getOwnId(); RsStackMutex stack(mStatusMtx); it = mStatusInfoMap.find(ownId); if (it == mStatusInfoMap.end()){ std::cerr << "p3StatusService::saveList() :" << "Did not find your status" << ownId << std::endl; return false; } statusInfo = it->second; return true; } bool p3StatusService::getStatus(std::list& statusInfo) { time_t time_now = time(NULL); #ifdef STATUS_DEBUG std::cerr << "p3StatusService::getStatus() " << std::endl; #endif statusInfo.clear(); std::list status_items; getStatusQueue(status_items); std::map::iterator mit; std::list peers, peersOnline; std::list::iterator pit, pit_online; { RsStackMutex stack(mStatusMtx); /* first update map */ mConnMgr->getFriendList(peers); mConnMgr->getOnlineList(peersOnline); pit_online = peersOnline.begin(); // ensure member map is up to date with all client's peers for(pit = peers.begin(); pit != peers.end(); pit++){ mit = mStatusInfoMap.find(*pit); if(mit == mStatusInfoMap.end()){ StatusInfo info; info.id = *pit; info.status = RS_STATUS_ONLINE; info.time_stamp = time_now; std::pair pr(*pit, info); mStatusInfoMap.insert(pr); } } // now note members who have sent specific status updates while (status_items.size()){ RsStatusItem* si = status_items.front(); status_items.pop_front(); mit = mStatusInfoMap.find(si->PeerId()); if(mit != mStatusInfoMap.end()){ mit->second.id = si->PeerId(); mit->second.status = si->status; mit->second.time_stamp = si->sendTime; #ifdef STATUS_DEBUG } else { std::cerr << "p3GetStatus() " << "Could not find Peer" << si->PeerId(); std::cerr << std::endl; #endif } delete (si); } // then fill up statusInfo list with this information for(mit = mStatusInfoMap.begin(); mit != mStatusInfoMap.end(); mit++){ statusInfo.push_back(mit->second); } } return true; } /* id = "", status is sent to all online peers */ bool p3StatusService::sendStatus(const std::string &id, uint32_t status) { StatusInfo statusInfo; std::list onlineList; { RsStackMutex stack(mStatusMtx); statusInfo.id = mConnMgr->getOwnId(); statusInfo.status = status; // don't save inactive status if(statusInfo.status != RS_STATUS_INACTIVE){ // If your id is not set, set it if(mStatusInfoMap.find(statusInfo.id) == mStatusInfoMap.end()){ std::pair pr(statusInfo.id, statusInfo); mStatusInfoMap.insert(pr); IndicateConfigChanged(); } else if(mStatusInfoMap[statusInfo.id].status != statusInfo.status){ IndicateConfigChanged(); mStatusInfoMap[statusInfo.id] = statusInfo; } } if (id.empty()) { mConnMgr->getOnlineList(onlineList); } else { onlineList.push_back(id); } } std::list::iterator it; #ifdef STATUS_DEBUG std::cerr << "p3StatusService::sendStatus() " << std::endl; std::cerr << statusInfo; #endif // send to all peers online for(it = onlineList.begin(); it != onlineList.end(); it++){ RsStatusItem* statusItem = new RsStatusItem(); statusItem->sendTime = time(NULL); statusItem->status = statusInfo.status; statusItem->PeerId(*it); sendItem(statusItem); } return true; } bool p3StatusService::statusAvailable(){ return receivedItems(); } /******************************/ void p3StatusService::getStatusQueue(std::list &ilist) { time_t time_now = time(NULL); RsItem* item; while(NULL != (item = recvItem())){ RsStatusItem* status_item = dynamic_cast(item); if(status_item == NULL) { std::cerr << "p3Status::getStatusQueue() " << "Failed to cast Item \n" << std::endl; delete (item); continue; } #ifdef STATUS_DEBUG std::cerr << "p3StatusService::getStatusQueue()" << std::endl; std::cerr << "PeerId : " << status_item->PeerId() << std::endl; std::cerr << "Status: " << status_item->status << std::endl; std::cerr << "Got status Item" << std::endl; #endif status_item->recvTime = time_now; ilist.push_back(status_item); } } /* p3Config */ RsSerialiser* p3StatusService::setupSerialiser(){ RsSerialiser *rss = new RsSerialiser; rss->addSerialType(new RsStatusSerialiser); return rss; } std::list p3StatusService::saveList(bool& cleanup){ // save your status before quiting cleanup = true; RsStatusItem* own_status = new RsStatusItem; StatusInfo own_info; std::list ilist; std::map::iterator it; { RsStackMutex stack(mStatusMtx); it = mStatusInfoMap.find(mConnMgr->getOwnId()); if(it == mStatusInfoMap.end()){ std::cerr << "p3StatusService::saveList() :" << "Did not find your status" << mConnMgr->getOwnId() << std::endl; delete own_status; return ilist; } own_info = it->second; } own_status->PeerId(own_info.id); own_status->sendTime = own_info.time_stamp; own_status->status = own_info.status; ilist.push_back(own_status); return ilist; } bool p3StatusService::loadList(std::list load){ // load your status from last rs session StatusInfo own_info; std::list::const_iterator it = load.begin(); if(it == load.end()){ std::cerr << "p3StatusService::loadList(): Failed to load " << std::endl; return false; } for(; it != load.end(); it++){ RsStatusItem* own_status = dynamic_cast(*it); if(own_status != NULL){ own_info.id = mConnMgr->getOwnId(); own_info.status = own_status->status; own_info.time_stamp = own_status->sendTime; delete own_status; { RsStackMutex stack(mStatusMtx); std::pair pr(mConnMgr->getOwnId(), own_info); mStatusInfoMap.insert(pr); } return true; }else{ std::cerr << "p3StatusService::loadList " << "Failed to load list " << std::endl; } } return false; } int p3StatusService::tick(){ return 0; } int p3StatusService::status(){ return 1; } /*************** pqiMonitor callback ***********************/ void p3StatusService::statusChange(const std::list &plist) { StatusInfo statusInfo; std::list::const_iterator it; for (it = plist.begin(); it != plist.end(); it++) { if ((it->state & RS_PEER_S_FRIEND) && (it->state & RS_PEER_CONNECTED)) { /* send current status */ if (statusInfo.id.empty() == false || getOwnStatus(statusInfo)) { sendStatus(it->id, statusInfo.status); } } } }