mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2025-12-16 12:08:36 +00:00
133 lines
4.2 KiB
C++
133 lines
4.2 KiB
C++
#include "server/chatlimiter.h"
|
|
#include "base/tick.h"
|
|
|
|
namespace wi {
|
|
|
|
ChatLimiter::ChatLimiter(int chat_count, int seconds_count,
|
|
int timeout_minutes, int repeat_limit) {
|
|
ms_per_token_ = seconds_count * 1000 / chat_count;
|
|
token_limit_ = chat_count;
|
|
timeout_minutes_ = timeout_minutes;
|
|
repeat_limit_ = repeat_limit;
|
|
}
|
|
|
|
void ChatLimiter::OnEndpointDelete(Endpoint *endpoint) {
|
|
// Stop tracking this endpoint
|
|
ChatterMap::iterator it = map_.find(endpoint->id());
|
|
if (it == map_.end()) {
|
|
return;
|
|
}
|
|
|
|
// If currently blocked, remember the ip so it can be blocked if there
|
|
// is a reconnect.
|
|
long64 tCurrent = base::GetMillisecondCount();
|
|
if (tCurrent < it->second.tExpires) {
|
|
endpoint->AddTracker(tracker_, it->second.tExpires);
|
|
}
|
|
map_.erase(it);
|
|
}
|
|
|
|
Chatter *ChatLimiter::CreateChatter(Endpoint *endpoint) {
|
|
// Create a new chatter
|
|
map_.insert(ChatterMap::value_type(endpoint->id(), Chatter(token_limit_)));
|
|
endpoint->SignalOnDelete.connect(this, &ChatLimiter::OnEndpointDelete);
|
|
Chatter *chatter = FindChatter(endpoint);
|
|
if (chatter == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
// See if this user is being tracked. If so, pick up the settings and
|
|
// remove the tracker.
|
|
if (endpoint->FindTracker(tracker_, &chatter->tExpires)) {
|
|
endpoint->RemoveTracker(tracker_);
|
|
}
|
|
return chatter;
|
|
}
|
|
|
|
Chatter *ChatLimiter::FindChatter(Endpoint *endpoint) {
|
|
// First see if this endpoint is already being tracked.
|
|
ChatterMap::iterator it = map_.find(endpoint->id());
|
|
if (it != map_.end()) {
|
|
return &it->second;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void ChatLimiter::Mute(Endpoint *endpoint, int minutes) {
|
|
// See if this endpoint is already being tracked. If not, add it.
|
|
Chatter *chatter = FindChatter(endpoint);
|
|
if (chatter == NULL) {
|
|
chatter = CreateChatter(endpoint);
|
|
if (chatter == NULL) {
|
|
return;
|
|
}
|
|
}
|
|
if (minutes < 0) {
|
|
minutes = 0;
|
|
}
|
|
if (minutes > kcMinutesTimeoutMaximum) {
|
|
minutes = kcMinutesTimeoutMaximum;
|
|
}
|
|
chatter->repeat_count = 0;
|
|
chatter->tExpires = base::GetMillisecondCount() + minutes * 60000;
|
|
}
|
|
|
|
int ChatLimiter::Submit(Endpoint *endpoint, const char *chat,
|
|
int *minutes_remaining) {
|
|
// See if this endpoint is already being tracked. If not, add it.
|
|
Chatter *chatter = FindChatter(endpoint);
|
|
if (chatter == NULL) {
|
|
chatter = CreateChatter(endpoint);
|
|
if (chatter == NULL) {
|
|
return knChatLimitResultNotLimited;
|
|
}
|
|
}
|
|
|
|
// Calculate the # of new tokens to add to the bucket since last chat
|
|
long64 tCurrent = base::GetMillisecondCount();
|
|
chatter->token_count += (dword)(tCurrent - chatter->tLast) / ms_per_token_;
|
|
if (chatter->token_count > token_limit_) {
|
|
chatter->token_count = token_limit_;
|
|
}
|
|
chatter->tLast = tCurrent;
|
|
|
|
// Is this chatter rate limited already? If so, wait until the limit
|
|
// expires.
|
|
if (tCurrent < chatter->tExpires) {
|
|
*minutes_remaining = (int)(((chatter->tExpires - tCurrent + 500) / 1000
|
|
+ 59) / 60);
|
|
return knChatLimitResultLimited;
|
|
}
|
|
|
|
// Is there a full token left? If not, this chatter has gone over
|
|
// the rate limit.
|
|
bool moderator = endpoint->IsModerator();
|
|
if (chatter->token_count < 1.0 && !moderator) {
|
|
chatter->repeat_count = 0;
|
|
chatter->tExpires = tCurrent + timeout_minutes_ * 60000;
|
|
*minutes_remaining = timeout_minutes_;
|
|
return knChatLimitResultNewlyLimited;
|
|
}
|
|
chatter->token_count -= 1.0f;
|
|
|
|
// Spamming the same string over and over?
|
|
if ((strcmp(chatter->last_chat.c_str(), chat) == 0 || strlen(chat) > 80) &&
|
|
!moderator) {
|
|
chatter->repeat_count++;
|
|
if (chatter->repeat_count >= repeat_limit_) {
|
|
chatter->repeat_count = 0;
|
|
chatter->tExpires = tCurrent + timeout_minutes_ * 60000;
|
|
*minutes_remaining = timeout_minutes_;
|
|
return knChatLimitResultNewlyLimited;
|
|
}
|
|
} else {
|
|
chatter->last_chat = chat;
|
|
chatter->repeat_count = 0;
|
|
}
|
|
|
|
// Looks good, let it go through
|
|
return knChatLimitResultNotLimited;
|
|
}
|
|
|
|
} // namespace wi
|