handle more of discord's quirky way of doing slowmode

also has the side effect of reducing db hits a little bit
This commit is contained in:
ouwou 2021-04-14 02:59:57 -04:00
parent 9733ae54c3
commit f5df43194e
2 changed files with 21 additions and 12 deletions

View File

@ -26,6 +26,7 @@ RateLimitIndicator::RateLimitIndicator()
Abaddon::Get().GetDiscordClient().signal_message_create().connect(sigc::mem_fun(*this, &RateLimitIndicator::OnMessageCreate));
Abaddon::Get().GetDiscordClient().signal_message_send_fail().connect(sigc::mem_fun(*this, &RateLimitIndicator::OnMessageSendFail));
Abaddon::Get().GetDiscordClient().signal_channel_update().connect(sigc::mem_fun(*this, &RateLimitIndicator::OnChannelUpdate));
}
void RateLimitIndicator::SetActiveChannel(Snowflake id) {
@ -48,8 +49,8 @@ bool RateLimitIndicator::CanSpeak() const {
return true;
const auto now = std::chrono::steady_clock::now();
const auto sec_diff = std::chrono::duration_cast<std::chrono::seconds>(now - it->second).count();
return sec_diff >= GetRateLimit();
const auto sec_diff = std::chrono::duration_cast<std::chrono::seconds>(it->second - now).count();
return sec_diff <= 0;
}
int RateLimitIndicator::GetTimeLeft() const {
@ -59,12 +60,12 @@ int RateLimitIndicator::GetTimeLeft() const {
if (it == m_times.end()) return 0;
const auto now = std::chrono::steady_clock::now();
const auto sec_diff = std::chrono::duration_cast<std::chrono::seconds>(now - it->second).count();
const auto sec_diff = std::chrono::duration_cast<std::chrono::seconds>(it->second - now).count();
if (sec_diff >= GetRateLimit())
if (sec_diff <= 0)
return 0;
else
return GetRateLimit() - sec_diff;
return sec_diff;
}
int RateLimitIndicator::GetRateLimit() const {
@ -105,8 +106,9 @@ void RateLimitIndicator::OnMessageCreate(const Message &message) {
auto &discord = Abaddon::Get().GetDiscordClient();
if (message.Author.ID != discord.GetUserData().ID) return;
const bool can_bypass = discord.HasAnyChannelPermission(discord.GetUserData().ID, m_active_channel, Permission::MANAGE_MESSAGES | Permission::MANAGE_CHANNELS);
if (GetRateLimit() > 0 && !can_bypass) {
m_times[message.ChannelID] = std::chrono::steady_clock::now();
const auto rate_limit = GetRateLimit();
if (rate_limit > 0 && !can_bypass) {
m_times[message.ChannelID] = std::chrono::steady_clock::now() + std::chrono::duration<int>(rate_limit + 1);
UpdateIndicator();
}
}
@ -115,10 +117,16 @@ void RateLimitIndicator::OnMessageSendFail(const std::string &nonce, float retry
if (retry_after != 0) { // failed to rate limit
const auto msg = Abaddon::Get().GetDiscordClient().GetMessage(nonce);
const auto channel_id = msg->ChannelID;
const auto channel = *Abaddon::Get().GetDiscordClient().GetChannel(channel_id);
const auto rate_limit = *channel.RateLimitPerUser;
const auto sent_time = std::chrono::steady_clock::now() - std::chrono::duration<int>(rate_limit - std::lroundf(retry_after + 0.5f)); // + 0.5 will ceil it
m_times[channel_id] = sent_time;
m_times[channel_id] = std::chrono::steady_clock::now() + std::chrono::duration<int>(std::lroundf(retry_after + 0.5f) + 1); // + 0.5 will ceil it
UpdateIndicator();
}
}
void RateLimitIndicator::OnChannelUpdate(Snowflake channel_id) {
const auto r = Abaddon::Get().GetDiscordClient().GetChannel(channel_id)->RateLimitPerUser;
if (r.has_value())
m_rate_limit = *r;
else
m_rate_limit = 0;
UpdateIndicator();
}

View File

@ -18,6 +18,7 @@ private:
bool UpdateIndicator();
void OnMessageCreate(const Message &message);
void OnMessageSendFail(const std::string &nonce, float rate_limit);
void OnChannelUpdate(Snowflake channel_id);
Gtk::Image m_img;
Gtk::Label m_label;
@ -26,5 +27,5 @@ private:
int m_rate_limit;
Snowflake m_active_channel;
std::unordered_map<Snowflake, std::chrono::time_point<std::chrono::steady_clock>> m_times;
std::unordered_map<Snowflake, std::chrono::time_point<std::chrono::steady_clock>> m_times; // time point of when next message can be sent
};