193 lines
7.3 KiB
C++
193 lines
7.3 KiB
C++
#include "manager.h"
|
|
#include "spdlog/spdlog.h"
|
|
#include "state.h"
|
|
#include "td/telegram/td_api.h"
|
|
#include "vk.h"
|
|
#include <algorithm>
|
|
#include <limits>
|
|
#include <memory>
|
|
#include <optional>
|
|
|
|
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::loadChats>(td_api::make_object<td_api::chatListMain>(), 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<std::vector<AbstractPost>>[] >(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<td_api::getChat>(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<vk::Post> 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<td::tl::unique_ptr<td_api::message>> 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<void(std::vector<vk::Post>)> callback) {
|
|
collect_last_vk_posts(std::numeric_limits<int>::max(), callback);
|
|
}
|
|
|
|
void RepostManager::collect_last_vk_posts(int count, std::function<void(std::vector<vk::Post>)> callback) {
|
|
collect_vk_posts_from(0, count, callback);
|
|
}
|
|
|
|
void RepostManager::collect_all_tg_posts(std::function<void(std::vector<td::tl::unique_ptr<td_api::message>>)> callback) {
|
|
collect_last_tg_posts(std::numeric_limits<int>::max(), callback);
|
|
}
|
|
|
|
void RepostManager::collect_last_tg_posts(int count, std::function<void(std::vector<td::tl::unique_ptr<td_api::message>>)> callback) {
|
|
collect_tg_posts_from(0, count, callback);
|
|
}
|
|
|
|
void RepostManager::collect_vk_posts_from(int offset, int count, std::function<void(std::vector<vk::Post>)> callback) {
|
|
m_vk.get_posts(m_appConfig->vkSource, offset, count, [=](std::optional<vk::WallChunk> 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<void(std::vector<td::tl::unique_ptr<td_api::message>>)> callback) {
|
|
spdlog::debug("collecting {} telegram posts starting from {}", count, from);
|
|
auto result = std::make_shared<std::vector<td::tl::unique_ptr<td_api::message>>>();
|
|
collect_tg_posts_from__intermediate(from, count, result, callback);
|
|
}
|
|
|
|
void RepostManager::collect_tg_posts_from__intermediate(long from, int count, std::shared_ptr<std::vector<td::tl::unique_ptr<td_api::message>>> intermediateResult, std::function<void(std::vector<td::tl::unique_ptr<td_api::message>>)> callback) {
|
|
spdlog::debug("getting some messages ({})", count);
|
|
m_tg.send_query(td_api::make_object<td_api::getChatHistory>(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<AbstractPost> RepostManager::to_abstract_posts(std::vector<vk::Post> &posts) {
|
|
std::vector<AbstractPost> result;
|
|
result.reserve(posts.size());
|
|
for (auto &post : posts) {
|
|
result.emplace_back(post.id, post.date, post.text);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::vector<AbstractPost> RepostManager::to_abstract_posts(std::vector<td::tl::unique_ptr<td_api::message>> &posts) {
|
|
std::vector<AbstractPost> 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<AbstractPost> posts) {
|
|
for (auto &post : posts) {
|
|
// TODO
|
|
}
|
|
} |