Closed frak0d closed 1 year ago
I mean, the #async branch had src folder as well. Why doesn't #master have that ?
I have made bots using tgbot-cpp in the past, but your library is confusing me.
What the the things User is expected to implement ?
A bare minimum docs/info on working of this library would be nice.
I mean, the #async branch had src folder as well. Why doesn't #master have that ?
I tried to make async http client. Curl has some issues when integrating with boost asio, it is not finished.
What the the things User is expected to implement ?
Check the project in archive that I attached. There is complete example. Also see in that tpost that you need to implement http client with two methods.
The thing is that the most reliable way of writing telegram bots is to use their official tdlib (https://github.com/tdlib/td). Libraries that implement TgBotAPI are very simple as you see: one file + html parser that parses their docs and generates some API code.
Hi,
Yes it is complete.
To use it, you need to implement some http client with methods
struct curl_http_client { std::string make_request(const std::string &url, const tgbot::http_request_arguments &args) const; std::string make_request(const std::string &url, const std::string &json) const; ... };
Then use it
tgbot::bot<curl_http_client> bot; auto me = bot.api().getMe();
See complete example in archive. report_detection_bot.zip
Download sw client, run
sw build
orsw generate
to generate VS solution in case you are on win.
Error while trying to sw build:
C:\Users\User\report detection bot>sw build
[137/140] [config pch]
[138/140] C:/Users/User/report detection bot/sw.cpp
[139/140] C:/Users/User/.sw/storage/pkg/a0/ef/79bd/src/sdir/src/sw/driver/misc/delay_load_helper.cpp
[140/140] C:/Users/User/report detection bot/.sw/cfg/175713/loc.sw.self.535bd2-0.0.30.dll
Downloading: [pub.egorpugin.tgbot-1.1.4.6.0]/[Source Archive]
Downloading: [pub.egorpugin.tgbot.apitool-1.1.4.6.0]/[Source Archive]
Unpacking : [pub.egorpugin.tgbot.apitool-1.1.4.6.0]/[Source Archive]
Unpacking : [pub.egorpugin.tgbot-1.1.4.6.0]/[Source Archive]
[138/144] C:/Users/User/.sw/storage/pkg/0e/1e/7261/src/sdir/sw.cpp
[139/144] C:/Users/User/.sw/storage/pkg/9c/45/a31b/src/sdir/sw.cpp
[141/144] C:/Users/User/.sw/storage/pkg/87/aa/d8ea/src/sdir/sw.cpp
[142/144] C:/Users/User/.sw/storage/tmp/cfg/175713/loc.sw.self.dd6076-0.0.30.dll
[143/144] C:/Users/User/.sw/storage/tmp/cfg/175713/loc.sw.self.d6a81c-0.0.30.dll
[144/144] C:/Users/User/.sw/storage/tmp/cfg/175713/loc.sw.self.66f298-0.0.30.dll
Exception in file D:/dev/cppan2/client2/src/sw/builder/command.cpp:840, function execute1: When executing: C:/Users/User/.sw/storage/tmp/cfg/175713/loc.sw.self.d6a81c-0.0.30.dll
LINK : fatal error LNK1104: 㤠 䠩 "C:\Users\User\.sw\storage\tmp\cfg\175713\loc.sw.self.d6a81c-0.0.30.dll"
command failed: exit code = 1104 (0x450)
Total errors: 1
Try to 1) re-run, 2) re-run after removing sw storage dir C:/Users/User/.sw/storage
.
Try to 1) re-run...
It worked! But not the bot itself
Errors in build process:
Инструкция точки останова (оператор __debugbreak() или аналогичный вызов) выполнена в report_detection_bot-0.0.1.exe.
Visual Studio issue:
Try to run sw generate
, open VS solution, build debug version there and run. You will see exact issue.
Try to run
sw generate
, open VS solution, build debug version there and run. You will see exact issue.
Same problem as it was recently... started the debug building, got the cmd with "Not Found" text and then the last two screenies.
Well, try to stop process, open call stack. Check what is wrong. Probably you did not provide your bot token or settings or something like this.
Well, try to stop process, open call stack. Check what is wrong. Probably you did not provide your bot token or settings or something like this.
Oh, my bad... but what I need to fill here if I haven't any proxy?
Leave empty.
Leave empty.
A-a-and this appears When I'm doing this
You need to set these in settings file, not here.
sw<setting>
takes setting name argument, not setting value.
And bot token is invalid setting name.
Just remove those settings lines completely and write your token in place where this variable is used.
Just remove those settings lines completely...
I can't because they are used in code.
Delete code that uses them.
Delete code that uses them.
Deleted, but still it doesn't work... and all what I know that error with 'std::visit' has 'E03E04' code in Visual Studio.
Close that window. It is bad. Never look at it.
Always look at Output window and send messages from there.
Always look at Output window and send messages from there.
main.cpp code:
#include "curl_http_client.h"
#include <primitives/http.h>
#include <primitives/sw/main.h>
#include <primitives/sw/settings.h>
#include <fstream>
#include <iostream>
#include <thread>
struct tg_bot : tgbot::bot<curl_http_client> {
using base = tgbot::bot<curl_http_client>;
std::string botname;
std::string botvisiblename;
static const int default_update_limit = 100;
static const int default_update_timeout = 10;
int net_delay_on_error = 1;
public:
using base::base;
void init() {
auto me = api().getMe();
if (!me.username)
throw SW_RUNTIME_ERROR("Empty bot name");
botname = *me.username;
botvisiblename = me.first_name;
printf("bot username: %s (%s)\n", me.username->c_str(), me.first_name.c_str());
}
tgbot::Integer process_updates(
tgbot::Integer offset = 0,
tgbot::Integer limit = default_update_limit,
tgbot::Integer timeout = default_update_timeout,
const tgbot::Optional<tgbot::Vector<String>> &allowed_updates = {}) {
// update timeout here for getUpdates()
((curl_http_client&)http_client()).set_timeout(timeout);
auto updates = api().getUpdates(offset, limit, timeout, allowed_updates);
for (const auto &item : updates) {
// if updates come unsorted, we must check this
if (item.update_id >= offset)
offset = item.update_id + 1;
process_update(item);
}
return offset;
}
void process_update(const tgbot::Update &update) {
try {
handle_update(update);
}
catch (std::exception &e) {
printf("error: %s\n", e.what());
std::this_thread::sleep_for(std::chrono::seconds(net_delay_on_error));
if (net_delay_on_error < 30)
net_delay_on_error *= 2;
}
}
void long_poll(
tgbot::Integer limit = default_update_limit,
tgbot::Integer timeout = default_update_timeout,
const tgbot::Optional<tgbot::Vector<String>> &allowed_updates = {}) {
tgbot::Integer offset = 0;
while (1) {
try {
offset = process_updates(offset, limit, timeout, allowed_updates);
} catch (std::exception &e) {
printf("error: %s\n", e.what());
}
}
}
///
virtual void handle_update(const tgbot::Update &update) = 0;
};
struct user_data {
};
struct tg_report_detection_bot : tg_bot {
static inline auto fn = "users.txt";
std::unordered_map<tgbot::Integer, user_data> users;
using tg_bot::tg_bot;
tg_report_detection_bot(auto &&token, auto &&client) : tg_bot(token, client) {
std::ifstream ifile(fn);
std::string s;
while (std::getline(ifile, s)) {
if (s.empty())
continue;
auto id = std::stoull(s.substr(1));
if (s[0] == '+')
users.emplace(id, user_data{});
else
users.erase(id);
}
}
std::ofstream &file() {
static std::ofstream of(fn, std::ios::out | std::ios::app);
return of;
}
void add_user(auto id) {
users.erase(id);
users.emplace(id, user_data{});
file() << '+' << id << std::endl;
}
void remove_user(auto id) {
users.erase(id);
file() << '-' << id << std::endl;
}
void handle_update(const tgbot::Update &update) override {
if (update.message)
handle_message(*update.message);
}
void handle_message(const tgbot::Message &message) {
if (!message.text || !message.text->starts_with("/"sv))
return;
if (message.chat && message.chat->id < 0 && !users.empty()) {
if (*message.text == "/report"sv) {
for (auto &&member : api().getChatAdministrators(message.chat->id)) {
std::visit([this, &message](auto &&u) {
if (!users.contains(u.user->id))
return;
tgbot::sendMessageRequest r;
r.chat_id = u.user->id;
r.text = "report is called";
if (mess age.chat->username) {
r.text += " in chat t.me/" + *message.chat->username + "/" + std::to_string(message.message_id);
};
else {
r.text += " in private chat";
};
api().sendMessage(r);
}, member);
}
}
}
else {
handle_command(message);
}
}
void handle_command(const tgbot::Message &message) {
auto &t = *message.text;
auto cmd = t.substr(1, t.find_first_of(" @"));
if (cmd == "start"sv) {
add_user(message.from->id);
api().sendMessage(message.from->id, "ok");
} else if (cmd == "stop"sv) {
remove_user(message.from->id);
api().sendMessage(message.from->id, "ok");
} else if (cmd == "help"sv) {
auto text =
"Available commands:\n"
"/start\n"
"/stop\n"
"/help\n"
;
api().sendMessage(message.from->id, text);
} else {
auto text = "Command '" + *message.text + "' is not implemented.";
api().sendMessage(message.from->id, text);
}
}
};
int main(int argc, char *argv[]) {
primitives::http::setupSafeTls();
sw::setting<std::string> bot_token("bot_token");
// read
sw::getSettings(sw::SettingsType::Local);
curl_http_client client;
// setup
{
auto curl = client.curl_settings();
primitives::http::setup_curl_ssl(curl);
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
//curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace);
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
}
// setup proxy
//{
// auto curl = client.curl_settings();
// if (!proxy_host.getValue().empty()) {
// curl_easy_setopt(curl, CURLOPT_PROXY, proxy_host.getValue().c_str());
// curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
// if (proxy_host.getValue().find("socks5") == 0) {
// curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
// curl_easy_setopt(curl, CURLOPT_SOCKS5_AUTH, CURLAUTH_BASIC);
// curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
// }
// if (!proxy_user.getValue().empty())
// curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_user.getValue().c_str());
// }
//}
auto bot = std::make_unique<tg_report_detection_bot>(bot_token, client);
bot->init();
bot->long_poll();
return 0;
}
Output errors:
2>C:\Users\User\report_detection_bot\src\main.cpp(130,34): error C2760: синтаксическая ошибка: непредвиденный элемент "идентификатор". Ожидается ")" 2>C:\Users\User\report_detection_bot\src\main.cpp(130,52): error C2760: синтаксическая ошибка: непредвиденный элемент ")". Ожидается ";" 2>C:\Users\User\report_detection_bot\src\main.cpp(130,52): error C2760: синтаксическая ошибка: непредвиденный элемент ")". Ожидается "}" 2>C:\Users\User\report_detection_bot\src\main.cpp(130,52): error C2059: синтаксическая ошибка: ) 2>C:\Users\User\report_detection_bot\src\main.cpp(130,1): error C2143: синтаксическая ошибка: отсутствие ";" перед "{" 2>C:\Users\User\report_detection_bot\src\main.cpp(131,29): error C2065: r: необъявленный идентификатор 2>C:\Users\User\report_detection_bot\src\main.cpp(133,1): error C2181: недопустимый else без парного if 2>C:\Users\User\report_detection_bot\src\main.cpp(134,29): error C2065: r: необъявленный идентификатор 2>C:\Users\User\report_detection_bot\src\main.cpp(136,43): error C2065: r: необъявленный идентификатор 2>C:\Users\User\report_detection_bot\src\main.cpp(137,22): error C2059: синтаксическая ошибка: , 2>C:\Users\User\report_detection_bot\src\main.cpp(137,1): error C2059: синтаксическая ошибка: ) 2>C:\Users\User\report_detection_bot\src\main.cpp(141,9): error C2059: синтаксическая ошибка: else 2>C:\Users\User\report_detection_bot\src\main.cpp(141,1): error C2143: синтаксическая ошибка: отсутствие ";" перед "{" 2>C:\Users\User\report_detection_bot\src\main.cpp(141,1): error C2447: {: отсутствует заголовок функции (возможно, используется формальный список старого типа) 2>C:\Users\User\report_detection_bot\src\main.cpp(144,5): error C2059: синтаксическая ошибка: } 2>C:\Users\User\report_detection_bot\src\main.cpp(144,1): error C2143: синтаксическая ошибка: отсутствие ";" перед "}" 2>C:\Users\User\report_detection_bot\src\main.cpp(145,56): error C2143: синтаксическая ошибка: отсутствие ";" перед "{" 2>C:\Users\User\report_detection_bot\src\main.cpp(145,56): error C2447: {: отсутствует заголовок функции (возможно, используется формальный список старого типа) 2>Сборка проекта "report_detection_bot-0.0.1.vcxproj" завершена с ошибкой.
Did you check line 130?
Did you check line 130?
if (mess age.chat->username) {
See error?
See error?
I don't know exactly, but I think that there's no error.
Space in variable name.
Space in variable name.
I found all mistakes in code, but still error (but new):
Вызвано исключение по адресу 0x00007FFEED554FD9 в report_detection_bot-0.0.1.exe: исключение Microsoft C++: std::runtime_error по адресу памяти 0x0000004ABB6FF480.
Main.cpp:
#include "curl_http_client.h"
#include <primitives/http.h>
#include <primitives/sw/main.h>
#include <primitives/sw/settings.h>
#include <fstream>
#include <iostream>
#include <thread>
struct tg_bot : tgbot::bot<curl_http_client> {
using base = tgbot::bot<curl_http_client>;
std::string botname;
std::string botvisiblename;
static const int default_update_limit = 100;
static const int default_update_timeout = 10;
int net_delay_on_error = 1;
public:
using base::base;
void init() {
auto me = api().getMe();
if (!me.username)
throw SW_RUNTIME_ERROR("Empty bot name");
botname = *me.username;
botvisiblename = me.first_name;
printf("bot username: %s (%s)\n", me.username->c_str(), me.first_name.c_str());
}
tgbot::Integer process_updates(
tgbot::Integer offset = 0,
tgbot::Integer limit = default_update_limit,
tgbot::Integer timeout = default_update_timeout,
const tgbot::Optional<tgbot::Vector<String>> &allowed_updates = {}) {
// update timeout here for getUpdates()
((curl_http_client&)http_client()).set_timeout(timeout);
auto updates = api().getUpdates(offset, limit, timeout, allowed_updates);
for (const auto &item : updates) {
// if updates come unsorted, we must check this
if (item.update_id >= offset)
offset = item.update_id + 1;
process_update(item);
}
return offset;
}
void process_update(const tgbot::Update &update) {
try {
handle_update(update);
}
catch (std::exception &e) {
printf("error: %s\n", e.what());
std::this_thread::sleep_for(std::chrono::seconds(net_delay_on_error));
if (net_delay_on_error < 30)
net_delay_on_error *= 2;
}
}
void long_poll(
tgbot::Integer limit = default_update_limit,
tgbot::Integer timeout = default_update_timeout,
const tgbot::Optional<tgbot::Vector<String>> &allowed_updates = {}) {
tgbot::Integer offset = 0;
while (1) {
try {
offset = process_updates(offset, limit, timeout, allowed_updates);
} catch (std::exception &e) {
printf("error: %s\n", e.what());
}
}
}
///
virtual void handle_update(const tgbot::Update &update) = 0;
};
struct user_data {
};
struct tg_report_detection_bot : tg_bot {
static inline auto fn = "users.txt";
std::unordered_map<tgbot::Integer, user_data> users;
using tg_bot::tg_bot;
tg_report_detection_bot(auto &&token, auto &&client) : tg_bot(token, client) {
std::ifstream ifile(fn);
std::string s;
while (std::getline(ifile, s)) {
if (s.empty())
continue;
auto id = std::stoull(s.substr(1));
if (s[0] == '+')
users.emplace(id, user_data{});
else
users.erase(id);
}
}
std::ofstream &file() {
static std::ofstream of(fn, std::ios::out | std::ios::app);
return of;
}
void add_user(auto id) {
users.erase(id);
users.emplace(id, user_data{});
file() << '+' << id << std::endl;
}
void remove_user(auto id) {
users.erase(id);
file() << '-' << id << std::endl;
}
void handle_update(const tgbot::Update &update) override {
if (update.message)
handle_message(*update.message);
}
void handle_message(const tgbot::Message &message) {
if (!message.text || !message.text->starts_with("/"sv))
return;
if (message.chat && message.chat->id < 0 && !users.empty()) {
if (*message.text == "/report"sv) {
for (auto &&member : api().getChatAdministrators(message.chat->id)) {
std::visit([this, &message](auto &&u) {
if (!users.contains(u.user->id))
return;
tgbot::sendMessageRequest r;
r.chat_id = u.user->id;
r.text = "report is called";
if (message.chat->username)
r.text += " in chat t.me/" + *message.chat->username + "/" + std::to_string(message.message_id);
else
r.text += " in private chat";
api().sendMessage(r);
}, member);
}
}
}
else {
handle_command(message);
}
}
void handle_command(const tgbot::Message &message) {
auto &t = *message.text;
auto cmd = t.substr(1, t.find_first_of(" @"));
if (cmd == "start"sv) {
add_user(message.from->id);
api().sendMessage(message.from->id, "ok");
} else if (cmd == "stop"sv) {
remove_user(message.from->id);
api().sendMessage(message.from->id, "ok");
} else if (cmd == "help"sv) {
auto text =
"Available commands:\n"
"/start\n"
"/stop\n"
"/help\n"
;
api().sendMessage(message.from->id, text);
} else {
auto text = "Command '" + *message.text + "' is not implemented.";
api().sendMessage(message.from->id, text);
}
}
};
int main(int argc, char *argv[]) {
primitives::http::setupSafeTls();
sw::setting<std::string> bot_token("bot_token");
// read
sw::getSettings(sw::SettingsType::Local);
curl_http_client client;
// setup
{
auto curl = client.curl_settings();
primitives::http::setup_curl_ssl(curl);
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
//curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace);
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
}
// setup proxy
//{
// auto curl = client.curl_settings();
// if (!proxy_host.getValue().empty()) {
// curl_easy_setopt(curl, CURLOPT_PROXY, proxy_host.getValue().c_str());
// curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
// if (proxy_host.getValue().find("socks5") == 0) {
// curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
// curl_easy_setopt(curl, CURLOPT_SOCKS5_AUTH, CURLAUTH_BASIC);
// curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
// }
// if (!proxy_user.getValue().empty())
// curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_user.getValue().c_str());
// }
//}
auto bot = std::make_unique<tg_report_detection_bot>(bot_token, client);
bot->init();
bot->long_poll();
return 0;
}
Hi,
Yes it is complete.
To use it, you need to implement some http client with methods
Then use it
See complete example in archive. report_detection_bot.zip
Download sw client, run
sw build
orsw generate
to generate VS solution in case you are on win.