Teaspeak-Server/server/src/weblist/WebListManager.cpp
2019-10-29 16:06:34 +01:00

138 lines
4.2 KiB
C++

#include <algorithm>
#include <thread>
#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<ts::server::TSServer> &server) {
{
unique_lock lock(this->entry_lock);
for(const auto& entry : this->entries) {
if(entry->server == server)
return;
}
auto entry = make_shared<Entry>();
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<ts::server::TSServer> &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<ts::server::TSServer> &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<TSWebClient>(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();
}
}
}
}