diff --git a/CMakeLists.txt b/CMakeLists.txt index 5553079..e8c40db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,9 +58,9 @@ add_library(tg-cli-lib src/controllers/GetChatsController.cpp src/controllers/SendMessageController.cpp src/controllers/ChatHistoryController.cpp + src/controllers/LabelsController.cpp src/facade/TgClientFacade.cpp src/label/LabelsParser.cpp - src/label/LabelsParser.h ) target_include_directories(tg-cli-lib diff --git a/src/controllers/GetChatsController.cpp b/src/controllers/GetChatsController.cpp index ec7dcfc..dbd65e5 100644 --- a/src/controllers/GetChatsController.cpp +++ b/src/controllers/GetChatsController.cpp @@ -14,16 +14,14 @@ ChatsController::ChatsController(ITgClient& client) std::vector ChatsController::get_chats(int limit) { clear_error(); - if (limit <= 0) { - limit = 10; - } - if (!cached_chats_.empty() && !should_refresh_cache()) { int return_count = std::min(static_cast(cached_chats_.size()), limit); - return std::vector( + auto result = std::vector( cached_chats_.begin(), cached_chats_.begin() + return_count ); + reverse(result.begin(), result.end()); + return result; } try { @@ -33,21 +31,11 @@ std::vector ChatsController::get_chats(int limit) { std::cout << "[ChatsController] Retrieved " << chats.size() << " chats\n"; - + reverse(chats.begin(), chats.end()); return chats; } catch (const std::exception& e) { handle_error(std::string("Failed to get chats: ") + e.what()); - - if (!cached_chats_.empty()) { - std::cerr << "[ChatsController] Returning cached data due to error\n"; - int return_count = std::min(static_cast(cached_chats_.size()), limit); - return std::vector( - cached_chats_.begin(), - cached_chats_.begin() + return_count - ); - } - return {}; } } diff --git a/src/controllers/LabelsController.cpp b/src/controllers/LabelsController.cpp new file mode 100644 index 0000000..2e52040 --- /dev/null +++ b/src/controllers/LabelsController.cpp @@ -0,0 +1,57 @@ +// +// Created by Kirtsuha on 13.12.2025. +// + +#include "LabelsController.h" + +#include "../label/Label.h" +#include "../label/LabelsParser.h" + +#include + +LabelsController::LabelsController(std::string filename) + : filename_(std::move(filename)) { + reload(); +} + +void LabelsController::reload() { + label_to_id_ = LabelsParser::load_labels(filename_); + rebuild_reverse_index(); +} + +void LabelsController::rebuild_from_chats(const std::vector& chats) { + label_to_id_.clear(); + id_to_label_.clear(); + + auto labels = generate_labels(chats.size()); + for (size_t i = 0; i < chats.size(); ++i) { + if (chats[i].chatId.empty()) continue; + label_to_id_.insert_or_assign(labels[i], chats[i].chatId); + } + + rebuild_reverse_index(); + LabelsParser::save_labels(filename_, label_to_id_); +} + +std::string LabelsController::resolve_chat_id(const std::string& label_or_id) const { + auto it = label_to_id_.find(label_or_id); + if (it != label_to_id_.end()) { + return it->second; + } + return label_or_id; +} + +std::string LabelsController::label_for_chat_id(const std::string& chat_id) const { + auto it = id_to_label_.find(chat_id); + if (it != id_to_label_.end()) { + return it->second; + } + return {}; +} + +void LabelsController::rebuild_reverse_index() { + id_to_label_.clear(); + for (const auto& [label, id] : label_to_id_) { + if (!id.empty()) id_to_label_.insert_or_assign(id, label); + } +} \ No newline at end of file diff --git a/src/controllers/LabelsController.h b/src/controllers/LabelsController.h new file mode 100644 index 0000000..dc5760d --- /dev/null +++ b/src/controllers/LabelsController.h @@ -0,0 +1,34 @@ +// +// Created by Kirtsuha on 13.12.2025. +// + +#pragma once + +#include "../tgClient/ITgClient.hpp" + +#include +#include +#include + + +class LabelsController { +public: + explicit LabelsController(std::string filename); + + void reload(); + + void rebuild_from_chats(const std::vector& chats); + + std::string resolve_chat_id(const std::string& label_or_id) const; + + std::string label_for_chat_id(const std::string& chat_id) const; + + const std::map& labels() const { return label_to_id_; } + +private: + std::string filename_; + std::map label_to_id_; + std::map id_to_label_; + + void rebuild_reverse_index(); +}; \ No newline at end of file diff --git a/src/facade/TgClientFacade.cpp b/src/facade/TgClientFacade.cpp index 7d9e969..089f650 100644 --- a/src/facade/TgClientFacade.cpp +++ b/src/facade/TgClientFacade.cpp @@ -1,6 +1,6 @@ -#include #include "TgClientFacade.h" +#include #include #include #include @@ -17,6 +17,7 @@ TgClientFacade::TgClientFacade(ITgClient& client) : client_(client) { chats_controller_ = std::make_unique(client_); history_controller_ = std::make_unique(client_); message_controller_ = std::make_unique(client_); + label_controller_ = std::make_unique("labels.txt"); } std::string TgClientFacade::auth_state_to_string(ITgClient::AuthState state) { @@ -45,9 +46,9 @@ void TgClientFacade::print_usage() { << " tgcli logout\n" << " tgcli chats\n" << " tgcli search-chats \n" - << " tgcli chat-info \n" - << " tgcli history [limit]\n" - << " tgcli send \n" + << " tgcli chat-info \n" + << " tgcli history [limit]\n" + << " tgcli send \n" << std::endl; } @@ -81,13 +82,17 @@ int TgClientFacade::run(int argc, char** argv) { } else if (command == "logout") { return handle_logout(); } else if (command == "chats") { - int limit = 20; + int limit; try { if (argc < 3) { limit = std::stoi(argv[2]); + if (limit <= 0) { + limit = 20; + } } } catch (...) { std::cerr << "[tgcli] Invalid limit, using default 20\n"; + limit = 20; } return handle_get_chats(limit); } else if (command == "search-chats") { @@ -115,8 +120,6 @@ int TgClientFacade::run(int argc, char** argv) { std::cerr << "[tgcli] Invalid limit, using default 20\n"; } } - auto x = client_.get_chat_history(argv[2], limit); - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // you saw nothing... return handle_history(argv[2], limit); @@ -212,7 +215,7 @@ int TgClientFacade::handle_logout() { // CHATS команды // ===================== -int TgClientFacade::handle_get_chats(int limit = 20) { +int TgClientFacade::handle_get_chats(int limit) { if (!auth_controller_->is_authorized()) { std::cerr << "[tgcli] Not authorized. Use login-phone/login-code first.\n"; return 1; @@ -220,7 +223,11 @@ int TgClientFacade::handle_get_chats(int limit = 20) { try { auto chats = chats_controller_->get_chats(limit); - + + if (label_controller_) { + label_controller_->rebuild_from_chats(chats); + } + if (chats.empty()) { std::cout << "[tgcli] No chats found\n"; return 0; @@ -231,9 +238,14 @@ int TgClientFacade::handle_get_chats(int limit = 20) { for (size_t i = 0; i < chats.size(); ++i) { const auto& chat = chats[i]; + const std::string label = label_controller_ ? label_controller_->label_for_chat_id(chat.chatId) + : std::string{}; + std::cout << std::setw(3) << (i + 1) << ". " - << "ID: " << chat.chatId - << " | Title: " << chat.title << "\n"; + << "Label: " << (label.empty() ? "-" : label) + << " | Title: " << chat.title + << " | ID: " << chat.chatId + << "\n"; } std::cout << "========================================\n"; @@ -266,9 +278,16 @@ int TgClientFacade::handle_search_chats(const std::string& query) { for (size_t i = 0; i < chats.size(); ++i) { const auto& chat = chats[i]; + + std::string label; + if (label_controller_) { + label = label_controller_->label_for_chat_id(chat.chatId); + } + std::cout << std::setw(3) << (i + 1) << ". " - << "ID: " << chat.chatId - << " | Title: " << chat.title << "\n"; + << "Label: " << (label.empty() ? "-" : label) + << " | Title: " << chat.title + << " | ID: " << chat.chatId << "\n"; } std::cout << "========================================\n"; @@ -288,7 +307,9 @@ int TgClientFacade::handle_chat_info(const std::string& chat_id) { } try { - auto chat = chats_controller_->get_chat_info(chat_id); + const std::string resolved_id = label_controller_ ? label_controller_->resolve_chat_id(chat_id) + : chat_id; + auto chat = chats_controller_->get_chat_info(resolved_id); if (chat.chatId.empty()) { std::cerr << "[tgcli] Chat not found: " << chat_id << "\n"; @@ -296,6 +317,9 @@ int TgClientFacade::handle_chat_info(const std::string& chat_id) { } std::cout << "[tgcli] Chat info:\n"; + std::cout << " Label: " + << (label_controller_ ? label_controller_->label_for_chat_id(chat.chatId) : std::string{"-"}) + << "\n"; std::cout << " ID: " << chat.chatId << "\n"; std::cout << " Title: " << chat.title << "\n"; @@ -318,7 +342,13 @@ int TgClientFacade::handle_history(const std::string& chat_id, int limit) { } try { - auto messages = history_controller_->get_chat_history(chat_id, limit); + const std::string resolved_id = label_controller_ ? label_controller_->resolve_chat_id(chat_id) + : chat_id; + auto messages = history_controller_->get_chat_history(resolved_id, limit); + + std::this_thread::sleep_for(std::chrono::milliseconds(800)); // you saw nothing... + messages = client_.get_chat_history(resolved_id, limit); + if (messages.empty()) { std::cout << "[tgcli] No messages found in chat: " << chat_id << "\n"; @@ -355,7 +385,9 @@ int TgClientFacade::handle_send(const std::string& chat_id, } try { - bool success = message_controller_->send_message(chat_id, message); + const std::string resolved_id = label_controller_ ? label_controller_->resolve_chat_id(chat_id) + : chat_id; + bool success = message_controller_->send_message(resolved_id, message); if (success) { std::cout << "[tgcli] Message sent to chat " << chat_id << "\n"; diff --git a/src/facade/TgClientFacade.h b/src/facade/TgClientFacade.h index a24141c..a22ae83 100644 --- a/src/facade/TgClientFacade.h +++ b/src/facade/TgClientFacade.h @@ -3,6 +3,10 @@ #include "../controllers/SendMessageController.h" #include "../controllers/GetChatsController.h" #include "../controllers/ChatHistoryController.h" +#include "../controllers/LabelsController.h" +#include "../label/Label.h" +#include "../label/LabelsParser.h" +#include class TgClientFacade { private: @@ -10,12 +14,12 @@ class TgClientFacade { std::unique_ptr message_controller_; std::unique_ptr history_controller_; std::unique_ptr chats_controller_; + std::unique_ptr label_controller_; ITgClient& client_; static std::vector collect_args(int argc, char** argv); static void print_usage(); - int handle_auth_status(); int handle_login_phone(const std::string& phone); int handle_login_code(const std::string& code); @@ -31,6 +35,8 @@ class TgClientFacade { int handle_set_target_chat(const std::string& chat_id); int handle_get_target_history(int limit); + std::map labels; + public: explicit TgClientFacade(ITgClient& client); ~TgClientFacade() = default;