/* */ #include "ServerStatMan.h" #include #include #include #include #include #include #include "ServerStat.h" #include "util.h" #include "RecoverableException.h" #include "a2functional.h" #include "BufferedFile.h" #include "message.h" #include "fmt.h" #include "LogFactory.h" #include "File.h" namespace aria2 { ServerStatMan::ServerStatMan() {} ServerStatMan::~ServerStatMan() {} SharedHandle ServerStatMan::find(const std::string& hostname, const std::string& protocol) const { SharedHandle ss(new ServerStat(hostname, protocol)); std::deque >::const_iterator i = std::lower_bound(serverStats_.begin(), serverStats_.end(), ss, DerefLess >()); if(i != serverStats_.end() && (*i)->getHostname() == hostname && (*i)->getProtocol() == protocol) { return *i; } else { return SharedHandle(); } } bool ServerStatMan::add(const SharedHandle& serverStat) { std::deque >::iterator i = std::lower_bound(serverStats_.begin(), serverStats_.end(), serverStat, DerefLess >()); if(i != serverStats_.end() && *(*i) == *serverStat) { return false; } else { serverStats_.insert(i, serverStat); return true; } } bool ServerStatMan::save(const std::string& filename) const { std::string tempfile = filename; tempfile += "__temp"; { BufferedFile fp(tempfile, BufferedFile::WRITE); if(!fp) { A2_LOG_ERROR(fmt(MSG_OPENING_WRITABLE_SERVER_STAT_FILE_FAILED, filename.c_str())); return false; } for(std::deque >::const_iterator i = serverStats_.begin(), eoi = serverStats_.end(); i != eoi; ++i) { std::string l = (*i)->toString(); l += "\n"; if(fp.write(l.data(), l.size()) != l.size()) { A2_LOG_ERROR(fmt(MSG_WRITING_SERVER_STAT_FILE_FAILED, filename.c_str())); } } if(fp.close() == EOF) { A2_LOG_ERROR(fmt(MSG_WRITING_SERVER_STAT_FILE_FAILED, filename.c_str())); return false; } } if(File(tempfile).renameTo(filename)) { A2_LOG_NOTICE(fmt(MSG_SERVER_STAT_SAVED, filename.c_str())); return true; } else { A2_LOG_ERROR(fmt(MSG_WRITING_SERVER_STAT_FILE_FAILED, filename.c_str())); return false; } } bool ServerStatMan::load(const std::string& filename) { static const std::string S_HOST = "host"; static const std::string S_PROTOCOL = "protocol"; static const std::string S_DL_SPEED = "dl_speed"; static const std::string S_SC_AVG_SPEED = "sc_avg_speed"; static const std::string S_MC_AVG_SPEED = "mc_avg_speed"; static const std::string S_LAST_UPDATED = "last_updated"; static const std::string S_COUNTER = "counter"; static const std::string S_STATUS = "status"; BufferedFile fp(filename, BufferedFile::READ); if(!fp) { A2_LOG_ERROR(fmt(MSG_OPENING_READABLE_SERVER_STAT_FILE_FAILED, filename.c_str())); return false; } char buf[4096]; while(1) { if(!fp.getsn(buf, sizeof(buf))) { if(fp.eof()) { break; } else { A2_LOG_ERROR(fmt(MSG_READING_SERVER_STAT_FILE_FAILED, filename.c_str())); return false; } } std::pair p = util::stripIter(&buf[0], &buf[strlen(buf)]); if(p.first == p.second) { continue; } std::string line(p.first, p.second); std::vector items; util::split(line, std::back_inserter(items), ","); std::map m; for(std::vector::const_iterator i = items.begin(), eoi = items.end(); i != eoi; ++i) { std::pair p; util::divide(p, (*i).begin(), (*i).end(), '='); m[std::string(p.first.first, p.first.second)] = std::string(p.second.first, p.second.second); } if(m[S_HOST].empty() || m[S_PROTOCOL].empty()) { continue; } SharedHandle sstat(new ServerStat(m[S_HOST], m[S_PROTOCOL])); try { const std::string& dlSpeed = m[S_DL_SPEED]; sstat->setDownloadSpeed(util::parseUInt(dlSpeed.begin(), dlSpeed.end())); // Old serverstat file doesn't contains SC_AVG_SPEED if(m.find(S_SC_AVG_SPEED) != m.end()) { const std::string& s = m[S_SC_AVG_SPEED]; sstat->setSingleConnectionAvgSpeed(util::parseUInt(s.begin(), s.end())); } // Old serverstat file doesn't contains MC_AVG_SPEED if(m.find(S_MC_AVG_SPEED) != m.end()) { const std::string& s = m[S_MC_AVG_SPEED]; sstat->setMultiConnectionAvgSpeed(util::parseUInt(s.begin(), s.end())); } // Old serverstat file doesn't contains COUNTER_SPEED if(m.find(S_COUNTER) != m.end()) { const std::string& s = m[S_COUNTER]; sstat->setCounter(util::parseUInt(s.begin(), s.end())); } const std::string& lastUpdated = m[S_LAST_UPDATED]; sstat->setLastUpdated (Time(util::parseInt(lastUpdated.begin(), lastUpdated.end()))); sstat->setStatus(m[S_STATUS]); add(sstat); } catch(RecoverableException& e) { continue; } } A2_LOG_NOTICE(fmt(MSG_SERVER_STAT_LOADED, filename.c_str())); return true; } namespace { class FindStaleServerStat { private: time_t timeout_; Time time_; public: FindStaleServerStat(time_t timeout):timeout_(timeout) {} bool operator()(const SharedHandle& ss) const { return ss->getLastUpdated().difference(time_) >= timeout_; } }; } // namespace void ServerStatMan::removeStaleServerStat(time_t timeout) { serverStats_.erase(std::remove_if(serverStats_.begin(), serverStats_.end(), FindStaleServerStat(timeout)), serverStats_.end()); } } // namespace aria2