Skip to content
This repository has been archived by the owner on Jan 3, 2025. It is now read-only.

Added requests limiter #35

Merged
merged 4 commits into from
May 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions source/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ set(LIBRARY_NAME UTILS)

set(HEADERS
logger/logger_utility.hpp
api_requests_limiter/api_requests_limiter.hpp
)

set(SOURCES
logger/logger_utility.cpp
api_requests_limiter/api_requests_limiter.cpp
)

add_library(${LIBRARY_NAME} STATIC ${HEADERS} ${SOURCES})
Expand Down
47 changes: 47 additions & 0 deletions source/utils/api_requests_limiter/api_requests_limiter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// MIT License

// Copyright (c) 2024 The B1T Foundation

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.


#include "api_requests_limiter.hpp"


// ---------------------------------------------------------------------------------------------------------------------
AApi_Requests_Limiter::AApi_Requests_Limiter(std::ptrdiff_t requests_limit, std::int64_t required_duration) :
Requests_Limit{ requests_limit }, Current_Requests_Count{ }, Required_Duration{ required_duration }, Previous_Time{ }
{ }

// ---------------------------------------------------------------------------------------------------------------------
bool AApi_Requests_Limiter::Can_Send_Request()
{
auto current_time{ static_cast<std::int64_t>(std::chrono::duration_cast<std::chrono::hours>(std::chrono::high_resolution_clock::now().time_since_epoch()).count()) };
if (current_time - Previous_Time >= Required_Duration && Requests_Limit - Current_Requests_Count > 1) // 1 - free requests
{
++Current_Requests_Count;
return true;
}

Previous_Time = current_time;
Current_Requests_Count = 0;

return false;
}

44 changes: 44 additions & 0 deletions source/utils/api_requests_limiter/api_requests_limiter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// MIT License

// Copyright (c) 2024 The B1T Foundation

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.


#pragma once

#include <chrono>
#include <cstdint>
#include <cstddef>

class AApi_Requests_Limiter
{
public:
explicit AApi_Requests_Limiter(std::ptrdiff_t requests_limit, std::int64_t required_duration);
constexpr ~AApi_Requests_Limiter() = default;

bool Can_Send_Request();

private:
std::ptrdiff_t Requests_Limit;
std::ptrdiff_t Current_Requests_Count;

std::int64_t Required_Duration;
std::int64_t Previous_Time;
};
17 changes: 12 additions & 5 deletions source/view/handlers/message_handler/message_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ std::mutex AMessage_Handler::Mutex{ };

// ---------------------------------------------------------------------------------------------------------------------
AMessage_Handler::AMessage_Handler(TgBot::Bot& tg_bot, AUser_DB_Controller& user_db_controller, AState_DB_Controller& state_db_controller, ATask_DB_Controller& task_db_controller, AStats_DB_Controller& stats_db_controller, AEnglish_Words_Info_API_Controller& english_words_api_controller, AMetrics_DB_Controller& metrics_db_controller, ATG_Root_User_Config& tg_root_user_cfg) :
TG_Bot{ tg_bot }, User_DB_Controller{ user_db_controller }, State_DB_Controller{ state_db_controller }, Task_DB_Controller{ task_db_controller }, Stats_DB_Controller{ stats_db_controller }, English_Words_API_Controller{ english_words_api_controller }, Metrics_DB_Controller{ metrics_db_controller }, TG_Root_User_Cfg{ tg_root_user_cfg }
TG_Bot{ tg_bot }, User_DB_Controller{ user_db_controller }, State_DB_Controller{ state_db_controller }, Task_DB_Controller{ task_db_controller }, Stats_DB_Controller{ stats_db_controller }, English_Words_API_Controller{ english_words_api_controller }, Metrics_DB_Controller{ metrics_db_controller }, TG_Root_User_Cfg{ tg_root_user_cfg }, Words_Api_Requests_Limiter{ 2500, 24 }
{ }

// ---------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -102,21 +102,28 @@ void AMessage_Handler::Bind_Commands()
std::lock_guard<std::mutex> locker(Mutex);
++Metrics.About_Project_Request_Count;

TG_Bot.getApi().sendMessage(message->chat->id, AMessage_Reply::Get_Info_About_Project());
TG_Bot.getApi().sendMessage(message->chat->id, AMessage_Reply::Get_Info_About_Project_Msg());
});
TG_Bot.getEvents().onCommand(SMessage_Commands::Definiton.data(), [this](TgBot::Message::Ptr message) -> void
{
if (!Words_Api_Requests_Limiter.Can_Send_Request())
{
TG_Bot.getApi().sendMessage(message->chat->id, AMessage_Reply::Get_Limit_Api_Requests_Msg());
return;
}

std::lock_guard<std::mutex> locker(Mutex);
++Metrics.Definition_Request_Count;

Cut_User_Input(message->text, SMessage_Commands::Definiton.size());
if (auto response{ English_Words_API_Controller.Get_Definition(message->text) }; response != std::nullopt)
{
TG_Bot.getApi().sendMessage(message->chat->id, AMessage_Reply::Get_Word_Definition(message->text, response.value()));
TG_Bot.getApi().sendMessage(message->chat->id,
AMessage_Reply::Get_Word_Definition_Msg(message->text, response.value()));
return;
}

TG_Bot.getApi().sendMessage(message->chat->id, AMessage_Reply::Get_Not_Found_Word_Definition());
TG_Bot.getApi().sendMessage(message->chat->id, AMessage_Reply::Get_Not_Found_Word_Definition_Msg());
});
TG_Bot.getEvents().onCommand(SMessage_Commands::Metrics_Count.data(), [this](TgBot::Message::Ptr message) -> void
{
Expand Down Expand Up @@ -152,7 +159,7 @@ void AMessage_Handler::Run_Metrics()
Metrics.Clear();

Mutex.unlock();
std::this_thread::sleep_for(18h);
std::this_thread::sleep_for(1h);
}
}

Expand Down
6 changes: 4 additions & 2 deletions source/view/handlers/message_handler/message_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@
#include <controller/db/stats_db/stats_db_controller.hpp>
#include <controller/db/metrics_db/metrics_db_controller.hpp>
#include <controller/api/english_words_info_api/english_words_info_api_controller.hpp>

#include <controller/programmer_game/programmer_game_controller.hpp>
#include <controller/math_problem_game/math_problem_game_controller.hpp>

#include <api_requests_limiter/api_requests_limiter.hpp>

#include <model/user/user_model.hpp>
#include <model/config/tg_root_user_config/tg_root_user_config_model.hpp>

Expand All @@ -64,7 +65,7 @@ class AMessage_Handler
bool Is_Root_User(std::int64_t user_id);

private:
constexpr static std::size_t Time_To_Wait{ 3 };
constexpr static std::size_t Time_To_Wait{ 1 };

private:
static std::mutex Mutex;
Expand All @@ -79,4 +80,5 @@ class AMessage_Handler
AStats_DB_Controller& Stats_DB_Controller;
AMetrics_DB_Controller& Metrics_DB_Controller;
AEnglish_Words_Info_API_Controller& English_Words_API_Controller;
AApi_Requests_Limiter Words_Api_Requests_Limiter;
};
6 changes: 3 additions & 3 deletions source/view/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ int main()
return -1;
}

auto english_words_info_api_config{ AEnglish_Words_Info_API_Config_Controller::Load_Config() };
if (english_words_info_api_config == std::nullopt)
auto english_words_info_api_cfg{AEnglish_Words_Info_API_Config_Controller::Load_Config() };
if (english_words_info_api_cfg == std::nullopt)
{
ALogger_Utility::Error("Error reading english words api config data");
return -1;
Expand All @@ -71,7 +71,7 @@ int main()
ATask_DB_Controller task_db_controller{ *db_cfg };
AStats_DB_Controller stats_db_controller{ *db_cfg };
AMetrics_DB_Controller metrics_db_controller{ *db_cfg };
AEnglish_Words_Info_API_Controller english_words_api_controller{ *english_words_info_api_config };
AEnglish_Words_Info_API_Controller english_words_api_controller{ *english_words_info_api_cfg };

AMessage_Handler message_handler{ tg_bot, user_db_controller, state_db_controller, task_db_controller, stats_db_controller, english_words_api_controller, metrics_db_controller, *tg_root_user_cfg };
message_handler.Bind_Commands();
Expand Down
11 changes: 8 additions & 3 deletions source/view/texts/message_reply/message_reply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,19 @@ std::string AMessage_Reply::Get_Help_Msg()
}

// ---------------------------------------------------------------------------------------------------------------------
std::string AMessage_Reply::Get_Info_About_Project()
std::string AMessage_Reply::Get_Info_About_Project_Msg()
{
return std::format("Інформація про цей проект{}\n\nЦе Open-Source проект ліцензований під MIT ліцензією.\nПосилання на код проекту: https://github.com/The-B1T-Foundation/tg_arbuz-bot\nПровідний розробник проекту: https://github.com/b1tflyyyy\n\nСвої побажання щодо функціоналу надсилайте на пошту [email protected]", BOOKS);
}

// ---------------------------------------------------------------------------------------------------------------------
std::string AMessage_Reply::Get_Word_Definition(std::string_view primary_word, std::string_view definiton)
std::string AMessage_Reply::Get_Word_Definition_Msg(std::string_view primary_word, std::string_view definiton)
{
return std::format("Визначення слова {}:\n{} - {}", primary_word, primary_word, definiton);
}

// ---------------------------------------------------------------------------------------------------------------------
std::string AMessage_Reply::Get_Not_Found_Word_Definition()
std::string AMessage_Reply::Get_Not_Found_Word_Definition_Msg()
{
return std::format("Скоріш за все ти ввів дивне слово, я не можу знайти визначення для нього)");
}
Expand All @@ -99,4 +99,9 @@ std::string AMessage_Reply::Get_Metrics_Count_Msg(std::int64_t metrics_count)
std::string AMessage_Reply::Get_Metrics_Msg(const SMetrics& metrics)
{
return std::format("Метрики Arbuz-Bot\n\nДата: {}\n\nКількість реквестів на команди:\nStart: {}\nProfile: {}\nProgrammer Game: {}\nMath Game: {}\nHelp: {}\nAbout Project: {}\nDefinition: {}", metrics.Get_Current_Date(), metrics.Start_Request_Count, metrics.Profile_Request_Count, metrics.Pr_Game_Request_Count, metrics.Math_Game_Request_Count, metrics.Help_Request_Count, metrics.About_Project_Request_Count, metrics.Definition_Request_Count);
}

std::string AMessage_Reply::Get_Limit_Api_Requests_Msg()
{
return std::string{ "Нажаль ліміт запросів перевищено!\nСпробуйте пізніше)" };
}
7 changes: 4 additions & 3 deletions source/view/texts/message_reply/message_reply.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ class AMessage_Reply
static std::string Get_Correct_Answer_Msg(std::int64_t score);
static std::string Get_Incorrect_Answer_Msg(std::int64_t score, std::string_view correct_answer);
static std::string Get_Help_Msg();
static std::string Get_Info_About_Project();
static std::string Get_Word_Definition(std::string_view primary_word, std::string_view definiton);
static std::string Get_Not_Found_Word_Definition();
static std::string Get_Info_About_Project_Msg();
static std::string Get_Word_Definition_Msg(std::string_view primary_word, std::string_view definiton);
static std::string Get_Not_Found_Word_Definition_Msg();
static std::string Get_Metrics_Count_Msg(std::int64_t metrics_count);
static std::string Get_Metrics_Msg(const SMetrics& metrics);
static std::string Get_Limit_Api_Requests_Msg();
};
Loading