refactor(tgbot-front): replaced the context usage with a new thread-safe one
This commit is contained in:
parent
b1c035ae35
commit
a6848bb4d7
5 changed files with 55 additions and 56 deletions
|
|
@ -3,6 +3,7 @@
|
|||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include "constants.hpp"
|
||||
|
||||
enum class UserState {
|
||||
MAIN_MENU, // Главное меню
|
||||
|
|
@ -50,6 +51,13 @@ public:
|
|||
// Получить текущий шаг (последний в истории) или std::nullopt, если нет истории
|
||||
std::optional<NavigationStep> getCurrentStep(int64_t userId) const;
|
||||
|
||||
// pop последнего состояния. true в случае удачи
|
||||
bool popStep(int64_t userId);
|
||||
|
||||
// Удалить контекст пользователя (например, при логауте)
|
||||
void removeContext(int64_t userId);
|
||||
|
||||
/// @brief Создает контекст начального меню для пользователя
|
||||
/// @param userId
|
||||
void createInitContext(int64_t userId);
|
||||
};
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
#include <structs.hpp>
|
||||
#include <unordered_map>
|
||||
#include "BotToServer.hpp"
|
||||
#include "BotUserContext.hpp"
|
||||
|
||||
/// @brief Структура возвращаемого значения класса BotHandlers для изменения текущего сообщения
|
||||
struct HandlerResult {
|
||||
|
|
@ -11,30 +12,6 @@ struct HandlerResult {
|
|||
TgBot::InlineKeyboardMarkup::Ptr keyboard;
|
||||
};
|
||||
|
||||
enum class UserState {
|
||||
MAIN_MENU, // Главное меню
|
||||
VIEWING_MY_TITLES, // Список моих тайтлов
|
||||
AWAITING_TITLE_NAME, // Жду название тайтла для поиска
|
||||
VIEWING_FOUND_TITLES, // Смотрю найденные тайтлы
|
||||
VIEWING_TITLE_PAGE, // Смотрю страничку тайтла
|
||||
AWAITING_REVIEW, // Жду ревью на тайтл
|
||||
VIEWING_REVIEW_LIST, // Смотрю список ревью на тайтл
|
||||
VIEWING_REVIEW, // Смотрю (конкретное) ревью на тайтл
|
||||
VIEWING_DESCRIPTION, // Смотрю описание тайтла
|
||||
ERROR, // Ошибка состояния
|
||||
};
|
||||
|
||||
struct NavigationStep {
|
||||
UserState state;
|
||||
int64_t payload; // ID тайтла, ревью и т.д.
|
||||
};
|
||||
|
||||
|
||||
struct UserContext {
|
||||
int64_t userId;
|
||||
std::vector<NavigationStep> history; // Текущее состояние пользователя + история предыдущих состояний
|
||||
};
|
||||
|
||||
class BotHandlers {
|
||||
public:
|
||||
BotHandlers(TgBot::Api api) : botApi(api) {;}
|
||||
|
|
@ -51,19 +28,16 @@ public:
|
|||
/// в боте.
|
||||
/// @param message обрабатываемое сообщение
|
||||
void handleMessage(TgBot::Message::Ptr message);
|
||||
|
||||
/// @brief Создает контекст начального меню для пользователя
|
||||
/// @param chatId id чата пользователя
|
||||
void createInitContext(int64_t chatId);
|
||||
|
||||
void initUser(int64_t userId);
|
||||
private:
|
||||
TgBot::Api botApi;
|
||||
std::unordered_map<int64_t, UserContext> userContexts;
|
||||
BotUserContext contextManager;
|
||||
BotToServer server_;
|
||||
|
||||
void handleNavigation(TgBot::CallbackQuery::Ptr query, UserContext& ctx);
|
||||
void handleNavigation(TgBot::CallbackQuery::Ptr query);
|
||||
|
||||
void handleError(TgBot::CallbackQuery::Ptr query, UserContext& ctx);
|
||||
void handleError(TgBot::CallbackQuery::Ptr query);
|
||||
|
||||
void processCallbackImpl(TgBot::CallbackQuery::Ptr query);
|
||||
|
||||
|
|
@ -73,17 +47,6 @@ private:
|
|||
/// @return HandlerResult
|
||||
/// static HandlerResult returnMyTitles(int64_t userId, int64_t payload);
|
||||
|
||||
/// @brief Вход в новое состояние
|
||||
/// @param ctx текущий контекст
|
||||
/// @param newState новое состояние, добавляемое в стек
|
||||
/// @param payload полезная нагрузка этого состояния
|
||||
void pushState(UserContext& ctx, UserState newState, int64_t payload);
|
||||
|
||||
/// @brief Возврат в предыдущее состояние
|
||||
/// @param ctx Текущий контекст
|
||||
/// @return true в случае успеха
|
||||
bool popState(UserContext& ctx);
|
||||
|
||||
/// @brief Уменьшает значение нагрузки с учетом текущего состояния
|
||||
/// @param payload Изменяемое значение нагрузки
|
||||
/// @param curState Текущее состояние
|
||||
|
|
@ -105,7 +68,7 @@ private:
|
|||
|
||||
/// @brief Отрисовка текущего экрана (соотв. контексту)
|
||||
/// @param ctx - текущий контекст
|
||||
void renderCurrent(TgBot::CallbackQuery::Ptr query, const UserContext& ctx);
|
||||
void renderCurrent(TgBot::CallbackQuery::Ptr query);
|
||||
|
||||
/// @brief Логика переходов между контекстами (навигация на следующий шаг)
|
||||
/// @param query - запрос
|
||||
|
|
|
|||
|
|
@ -40,4 +40,19 @@ std::optional<NavigationStep> BotUserContext::getCurrentStep(int64_t userId) con
|
|||
void BotUserContext::removeContext(int64_t userId) {
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
userContexts.erase(userId);
|
||||
}
|
||||
|
||||
bool BotUserContext::popStep(int64_t userId) {
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
auto it = userContexts.find(userId);
|
||||
if (it != userContexts.end() && (it->second.history.size() > 1)) {
|
||||
it->second.history.pop_back();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BotUserContext::createInitContext(int64_t userId) {
|
||||
NavigationStep initStep = {UserState::MAIN_MENU, BotConstants::NULL_PAYLOAD};
|
||||
setContext(userId, {userId, {initStep}});
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ void AnimeBot::setupHandlers() {
|
|||
bot.getEvents().onCommand("start", [this](TgBot::Message::Ptr message) {
|
||||
sendMainMenu(message->chat->id);
|
||||
//TODO: производить инициализацию контекста только после авторизации
|
||||
handler.createInitContext(message->chat->id);
|
||||
handler.initUser(message->from->id);
|
||||
});
|
||||
|
||||
bot.getEvents().onCallbackQuery([this](TgBot::CallbackQuery::Ptr query) {
|
||||
|
|
|
|||
|
|
@ -3,13 +3,15 @@
|
|||
#include "structs.hpp"
|
||||
#include "constants.hpp"
|
||||
|
||||
void BotHandlers::handleNavigation(TgBot::CallbackQuery::Ptr query, UserContext& ctx) {
|
||||
const auto& current = ctx.history.back(); // текущий экран
|
||||
void BotHandlers::handleNavigation(TgBot::CallbackQuery::Ptr query) {
|
||||
//const auto& current = ctx.history.back(); // текущий экран
|
||||
const std::string& data = query->data;
|
||||
int64_t userId = query->from->id;
|
||||
int64_t chatId = query->message->chat->id;
|
||||
int64_t messageId = query->message->messageId;
|
||||
|
||||
// Пагинация (в списках)
|
||||
/* Временно отключаем, все равно не функционирует :)
|
||||
if ((data == BotConstants::Callback::LIST_PREV || data == BotConstants::Callback::LIST_NEXT)
|
||||
&& (current.state == UserState::VIEWING_MY_TITLES || current.state == UserState::VIEWING_REVIEW_LIST ||
|
||||
current.state == UserState::VIEWING_FOUND_TITLES)) {
|
||||
|
|
@ -32,35 +34,46 @@ void BotHandlers::handleNavigation(TgBot::CallbackQuery::Ptr query, UserContext&
|
|||
|
||||
renderCurrent(query, ctx);
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
// Обработка back по интерфейсу
|
||||
if (data == BotConstants::Callback::NAV_BACK) {
|
||||
if (!popState(ctx)) {
|
||||
if (!contextManager.popStep(userId)) {
|
||||
sendError(chatId, messageId, BotConstants::Text::SAD_ERROR);
|
||||
return;
|
||||
}
|
||||
renderCurrent(query, ctx);
|
||||
renderCurrent(query);
|
||||
return;
|
||||
}
|
||||
|
||||
// Переходы вперёд (push)
|
||||
auto newStepOpt = computeNextStep(query, current);
|
||||
std::optional<NavigationStep> currentStep = contextManager.getCurrentStep(userId);
|
||||
if(!currentStep.has_value()) {
|
||||
sendError(chatId, messageId, BotConstants::Text::SAD_ERROR);
|
||||
return;
|
||||
}
|
||||
auto newStepOpt = computeNextStep(query, currentStep.value());
|
||||
if (!newStepOpt.has_value()) {
|
||||
sendError(chatId, messageId, BotConstants::Text::SAD_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.history.push_back(*newStepOpt);
|
||||
renderCurrent(query, ctx);
|
||||
contextManager.pushNavigationStep(userId, newStepOpt.value());
|
||||
renderCurrent(query);
|
||||
}
|
||||
|
||||
void BotHandlers::renderCurrent(TgBot::CallbackQuery::Ptr query, const UserContext& ctx) {
|
||||
const auto& step = ctx.history.back();
|
||||
//int64_t userId = query->from->id;
|
||||
void BotHandlers::renderCurrent(TgBot::CallbackQuery::Ptr query) {
|
||||
int64_t userId = query->from->id;
|
||||
int64_t chatId = query->message->chat->id;
|
||||
int64_t messageId = query->message->messageId;
|
||||
switch (step.state) {
|
||||
|
||||
auto step = contextManager.getCurrentStep(userId);
|
||||
if(!step.has_value()) {;
|
||||
sendError(chatId, messageId, BotConstants::Text::SAD_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (step.value().state) {
|
||||
case UserState::MAIN_MENU:
|
||||
editMessage(chatId, messageId, showMainMenu());
|
||||
return;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue