#include #include #include "src/TSServer.h" #include "log/LogUtils.h" #include "TeamSpeakWebClient.h" #include "WebListManager.h" using namespace std; using namespace std::chrono; using namespace ts; using namespace ts::server; using namespace ts::weblist; WebListManager::WebListManager() { this->event_base = event_base_new(); this->event_base_dispatch = std::thread([&](){ system_clock::time_point start; while(this->event_base) { start = system_clock::now(); ::event_base_dispatch(this->event_base); if(system_clock::now() - start < seconds(1)) this_thread::sleep_for(seconds(1)); } }); } WebListManager::~WebListManager() { auto base = this->event_base; this->event_base = nullptr; event_base_loopbreak(base); this->event_base_dispatch.join(); event_base_free(base); } void WebListManager::enable_report(const std::shared_ptr &server) { { unique_lock lock(this->entry_lock); for(const auto& entry : this->entries) { if(entry->server == server) return; } auto entry = make_shared(); entry->server = server; entry->scheduled_request = system_clock::now(); entry->fail_count = 0; this->entries.push_back(entry); } } bool WebListManager::reports_enabled(const std::shared_ptr &server) { { lock_guard lock(this->entry_lock); for(const auto& entry : this->entries) { if(entry->server == server) return true; } } return false; } void WebListManager::disable_report(const std::shared_ptr &server) { if(!server) return; unique_lock lock(this->entry_lock); for(const auto& entry : this->entries) { if(entry->server == server) { shared_ptr copied_entry = entry; //Copy it before erasing auto it = find(this->entries.begin(), this->entries.end(), copied_entry); if(it != this->entries.end()) this->entries.erase(it); if(copied_entry->current_request) { lock.unlock(); copied_entry->current_request->abort_sync(); } return; } } } void WebListManager::tick() { if(!this->enabled) return; unique_lock lock(this->entry_lock); auto entries = this->entries; lock.unlock(); auto now = system_clock::now(); for(const auto& entry : entries) { if(entry->scheduled_request < now && (!entry->current_request || entry->scheduled_request + minutes(5) < now)) { entry->current_request = make_shared(entry->server, this->event_base, entry->session_count, entry->last_name != entry->server->getDisplayName()); weak_ptr weak_entry = entry; entry->current_request->callback_success = [weak_entry, now](){ auto _entry = weak_entry.lock(); if(!_entry) return; _entry->fail_count = 0; _entry->scheduled_request = now + minutes(10); _entry->session_count++; _entry->last_name = _entry->server->getDisplayName(); logMessage(_entry->server->getServerId(), "[WebList] Status update succeeded! Scheduling next update in ten minutes."); _entry->current_request.reset(); }; entry->current_request->callback_error = [weak_entry, now](auto error, bool retry) { auto _entry = weak_entry.lock(); if(!_entry) return; _entry->fail_count++; logError(_entry->server->getServerId(), "[WebList] Status update failed. Error: " + error); if(_entry->fail_count == 1 && retry) { logMessage(_entry->server->getServerId(), "[WebList] Scheduling next update attempt in 5 seconds."); _entry->scheduled_request = now + seconds(5); } else if(_entry->fail_count == 2 && retry) { logMessage(_entry->server->getServerId(), "[WebList] Scheduling next update attempt in 30 seconds."); _entry->scheduled_request = now + seconds(30); } else if(_entry->fail_count == 3 && retry) { logMessage(_entry->server->getServerId(), "[WebList] Scheduling next update attempt in 1 minute."); _entry->scheduled_request = now + seconds(60); } else if(_entry->fail_count >= 4) { logMessage(_entry->server->getServerId(), "[WebList] Scheduling next update attempt in 10 minutes."); _entry->scheduled_request = now + minutes(10); } _entry->current_request.reset(); }; { /* could be blocking due to gethostbyname. We dont want to have the request deallocated */ auto ref_request = entry->current_request; ref_request->report(); } } } }