#include "manager.h" #include "spdlog/spdlog.h" #include "state.h" #include "td/telegram/td_api.h" #include "vk.h" #include #include #include #include using namespace manager; RepostManager::RepostManager(uv_loop_t *eventLoop, tg::AuthCodeProvider tgCodeProvider, tg::PasswordProvider tgPasswordProvider, state::AppState *appState, config::AppConfig *config) : m_vk(eventLoop), m_tg(eventLoop, config->tgApiId, config->tgApiHash, config->tgPhoneNumber) { m_appState = appState; m_appConfig = config; m_tg.authCodeProvider = tgCodeProvider; m_tg.passwordProvider = tgPasswordProvider; m_vk.set_service_api_key(config->vkServiceKey); } void RepostManager::start() { m_tg.add_update_handler([this](void*, td_api::Object &obj){ if (obj.get_id() == td_api::updateAuthorizationState::ID) { auto &authState = (td_api::updateAuthorizationState&)obj; if (authState.authorization_state_->get_id() == td_api::authorizationStateReady::ID) { //on_clients_ready(); spdlog::info("loading Telegram chats..."); m_tg.send_query(td_api::make_object(td_api::make_object(), 1000), [this](auto result){ spdlog::debug("loadChats done"); on_clients_ready(); }); } } else if (obj.get_id() == td_api::updateNewChat::ID) { auto &update = (td_api::updateNewChat&)obj; //spdlog::debug("chat loaded: {}", update.chat_->title_); } }); spdlog::info("starting Telegram authentication"); m_tg.start(); } void RepostManager::on_clients_ready() { auto posts = std::make_shared< std::optional>[] >(2); auto doWorkWithPosts = [this, posts]() -> void { spdlog::info("fetched some posts:"); int limit = 3; for (auto &i : *posts[0]) { if (limit-- == 0) { spdlog::info("..."); break; } spdlog::info("vk[#{}, {}] {}", i.id, i.date, i.text); } limit = 3; for (auto &i : *posts[1]) { if (limit-- == 0) { spdlog::info("..."); break; } spdlog::info("tg[#{}, {}] {}", i.id, i.date, i.text); } m_tg.send_query(td_api::make_object(m_appConfig->tgSourceId), [](auto result){ if (result->get_id() == td_api::chat::ID) { auto &chat = (td_api::chat&)*result; spdlog::info("source chat: #{} {}", chat.id_, chat.title_); } else { auto &e = (td_api::error&)*result; spdlog::error("getChat error: {} {}", e.code_, e.message_); } }); }; auto putVkPosts = [this, posts, doWorkWithPosts](std::vector vkPosts){ posts[0] = {to_abstract_posts(vkPosts)}; spdlog::info("fetched {} vk posts", posts[0]->size()); if (posts[1].has_value()) { doWorkWithPosts(); } }; auto putTgPosts = [this, posts, doWorkWithPosts](std::vector> tgPosts){ posts[1] = {to_abstract_posts(tgPosts)}; spdlog::info("fetched {} telegram posts", posts[1]->size()); if (posts[0].has_value()) { doWorkWithPosts(); } }; if (m_appState->vkLastPostId == 0) { spdlog::info("fetching ALL vk posts..."); collect_all_vk_posts(putVkPosts); } else { spdlog::info("fetching last 3 vk posts..."); collect_last_vk_posts(3, putVkPosts); } if (m_appState->tgLastPostId == 0) { spdlog::info("fetching ALL telegram posts..."); collect_all_tg_posts(putTgPosts); } else { spdlog::info("fetching last 3 telegram posts..."); collect_last_tg_posts(3, putTgPosts); } } void RepostManager::collect_all_vk_posts(std::function)> callback) { collect_last_vk_posts(std::numeric_limits::max(), callback); } void RepostManager::collect_last_vk_posts(int count, std::function)> callback) { collect_vk_posts_from(0, count, callback); } void RepostManager::collect_all_tg_posts(std::function>)> callback) { collect_last_tg_posts(std::numeric_limits::max(), callback); } void RepostManager::collect_last_tg_posts(int count, std::function>)> callback) { collect_tg_posts_from(0, count, callback); } void RepostManager::collect_vk_posts_from(int offset, int count, std::function)> callback) { m_vk.get_posts(m_appConfig->vkSource, offset, count, [=](std::optional chunk, int err){ if (err == 0) { callback(chunk->posts); } else { spdlog::error("failed to get {} VK posts at offset {}: error {}", count, offset, err); } }); } void RepostManager::collect_tg_posts_from(long from, int count, std::function>)> callback) { spdlog::debug("collecting {} telegram posts starting from {}", count, from); auto result = std::make_shared>>(); collect_tg_posts_from__intermediate(from, count, result, callback); } void RepostManager::collect_tg_posts_from__intermediate(long from, int count, std::shared_ptr>> intermediateResult, std::function>)> callback) { spdlog::debug("getting some messages ({})", count); m_tg.send_query(td_api::make_object(m_appConfig->tgSourceId, from, 0, count, false), [=, this](auto obj){ if (obj->get_id() == td_api::messages::ID) { td_api::messages &msgs = (td_api::messages&)*obj; if (msgs.messages_.size() == 0) { spdlog::debug("got all posts"); auto resultPtr = intermediateResult.get(); callback(std::move(*resultPtr)); return; } spdlog::debug("got {} posts", msgs.messages_.size()); size_t chunkSize = msgs.messages_.size(); size_t oldSize = intermediateResult->size(); long oldestId; intermediateResult->reserve(oldSize + chunkSize); for (auto i = msgs.messages_.begin(), end = msgs.messages_.end(); i != end; ++i) { //spdlog::debug("moving message {}", (*i)->id_); oldestId = (*i)->id_; intermediateResult->emplace_back(std::move(*i)); } collect_tg_posts_from__intermediate(oldestId, count - chunkSize, intermediateResult, callback); } else { auto &err = (td_api::error&)*obj; spdlog::error("failed to get posts: {} {}", err.code_, err.message_); } }); } std::vector RepostManager::to_abstract_posts(std::vector &posts) { std::vector result; result.reserve(posts.size()); for (auto &post : posts) { result.emplace_back(post.id, post.date, post.text); } return result; } std::vector RepostManager::to_abstract_posts(std::vector> &posts) { std::vector result; result.reserve(posts.size()); for (auto &post : posts) { // we don't want any posts other than plain text (yet) if (post->content_->get_id() == td_api::messageText::ID) { auto &content = (td_api::messageText&) *post->content_; result.emplace_back(post->id_, post->date_, content.text_->text_); } } return result; } void RepostManager::repost_all(std::vector posts) { for (auto &post : posts) { // TODO } }