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

Commit

Permalink
Merge pull request #35 from The-B1T-Foundation/added_requests_limiter
Browse files Browse the repository at this point in the history
Added requests limiter
  • Loading branch information
b1tflyyyy authored May 4, 2024
2 parents 98f2b36 + c0837d9 commit 88afc03
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 16 deletions.
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();
};

0 comments on commit 88afc03

Please sign in to comment.