LINUX.ORG.RU

Проблемы с Telegram Bot API (webhooks)

 , ,


0

4

День добрый.

Написал бота на C++, работающего через webhook.

Написал две версии, работающие через:

  • stunnel4
  • встроенный openssl

Обе версии испытывают одну и ту же проблему: данные приходят только после разрыва соединения с противоположного конца (когда у сервера Telegram проходит таймаут ожидания ответа). Т.е. у меня вызываются функции recv() или SSL_read() соответственно, которые:

  • на блокирующих сокетах возвращают все пришедшие данные, но уже после разрыва соединения, либо возвращают ничего по истечению таймаута, установленного через setsockopt(newsock, SOL_SOCKET, SO_RCVTIMEO, ...)
  • не неблокирующих сокетах возвращают ничего мгновенно и так 100500 раз в цикле, пока ТГ не разорвёт соединение - тогда за один вызов возвращаются все данные

Интересно то, что эта проблема только с серверами Telegram: по крайней мере, если я выполняю запрос curl -X POST -d 'тут json' -k https://MYBOTURL со своего компа к боту (бот на VPS), то всё выполняется успешно.

Может кто знает, с чем это может быть связано…



Последнее исправление: cetjs2 (всего исправлений: 1)

В cpp не силен, но могу предложить тебе работать не через вебхуки, а ходить в телегу за обновлениями самостоятельно. Если тебе не надо раскидывать код на несколько инстансов с балансером, то большой необходимости в webhook у тебя нет.

Aswed ★★★★★
()
Ответ на: комментарий от Aswed

Если тебе не надо раскидывать код на несколько инстансов с балансером, то большой необходимости в webhook у тебя нет.

+1

Да и выбор языка для бота довольно странный. ТС, налабай лучше своего бота в «две строчки» на каком-нибудь Python. За то время, которое ты потратил на попытку решения какой-то тривиальной проблемы ты бы уже бы два раза написал бота своего. Чем обусловлен выбор C++? Тем более на VPS.

EXL ★★★★★
()
Последнее исправление: EXL (всего исправлений: 1)

Кстати, да, если ты умеешь в питон, то советую взять его, т.к. для него есть готовые решения. Например вот это https://python-telegram-bot.org/

Aswed ★★★★★
()
Ответ на: комментарий от EXL

C++ потому, что я в питоне буду разбираться дольше, чем это напишу.

Да и так-то оно так, да вот проблема всё равно останется. В смысле на питоне если писать, то там её не будет, но я так не решу проблему, а обойду её. Интересно все же, почему так происходит.

Architector
() автор топика
Ответ на: комментарий от Architector

C++ потому, что я в питоне буду разбираться дольше, чем это напишу.

Не будешь, питон это практически декларативный язык по типу SQL, главное знать что вызывать.

import telebot

bot = telebot.TeleBot("TOKEN")

@bot.message_handler(commands=['start', 'help'])
def send_welcome(message):
	bot.reply_to(message, "Howdy, how are you doing?")

@bot.message_handler(func=lambda message: True)
def echo_all(message):
	bot.reply_to(message, message.text)

bot.polling()
MOPKOBKA ★★★★
()
Ответ на: комментарий от MOPKOBKA

декларативный язык

Хм, а кто мешает написать библиотеку под Сишечку, поведение которой будет определяться глобальными переменными и процедурами, и с таким же успехом назвать Сишечку декларативной?

Bagrov ★★★★★
()
Ответ на: комментарий от Bagrov

Тем что на сишечке так не делают, а питон изначально клей.

MOPKOBKA ★★★★
()

Так в чём проблема то была? Неужели только в неправильном выборе плюсцов вместо питона?

vvn_black ★★★★★
()
Ответ на: комментарий от Architector

И кому охото с этим разбираться

Три человека кроме тебя на тему подписались. Я раз день заглядываю. Интересно же, чем закончится.

vvn_black ★★★★★
()
Ответ на: комментарий от Architector

c++

Use TDlib, Luke.

Если уж хотите страдать с голыми сокетами, то зачем вебхуки тогда? Поллилили бы getUpdates и не имели таких проблем ;) Для вебхуков достаточно любой простейшей либы для работы с http, а у Вас какая-то кошмарная портянка, парсящая http на коленке. Нам когда-то дали очень простой, но мудрый совет по этому поводу ;)

Выдернуть назначенный сокету BIO и плясать с ним (BIO_flush и пр.) пробовали?

mertvoprog
()

Две вещи:

SSL_read() постоянно возвращает 0, при этом в это же время recv(..,..,..,MSG_PEEK) возвращает несколько сотен, и так каждый раз (в цикле)

Я, конечно, понимаю, что на TCP сокете могут быть служебные данные для TLS взаимодействия, не предназначенные для меня, но openssl же должен их забирать, а он их не забирает…

Architector
() автор топика
Ответ на: комментарий от Architector

Логи stunnel4. Там remote server указан как 10.8.5.1 - это я порт пробросил до своего ПК. Если запускать на vps - всё то же самое.

2021.01.17 12:25:41 LOG7[ui]: Clients allowed=500
2021.01.17 12:25:41 LOG5[ui]: stunnel 5.56 on x86_64-pc-linux-gnu platform
2021.01.17 12:25:41 LOG5[ui]: Compiled with OpenSSL 1.1.1c  28 May 2019
2021.01.17 12:25:41 LOG5[ui]: Running  with OpenSSL 1.1.1f  31 Mar 2020
2021.01.17 12:25:41 LOG5[ui]: Threading:PTHREAD Sockets:POLL,IPv6,SYSTEMD TLS:ENGINE,FIPS,OCSP,PSK,SNI Auth:LIBWRAP
2021.01.17 12:25:41 LOG7[ui]: errno: (*__errno_location ())
2021.01.17 12:25:41 LOG5[ui]: Reading configuration from file /etc/stunnel/stunnel.conf
2021.01.17 12:25:41 LOG5[ui]: UTF-8 byte order mark not detected
2021.01.17 12:25:41 LOG5[ui]: FIPS mode disabled
2021.01.17 12:25:41 LOG7[ui]: Compression disabled
2021.01.17 12:25:41 LOG7[ui]: No PRNG seeding was required
2021.01.17 12:25:41 LOG6[ui]: Initializing service [service]
2021.01.17 12:25:41 LOG7[ui]: Ciphers: HIGH:!aNULL:!SSLv2:!DH:!kDHEPSK
2021.01.17 12:25:41 LOG7[ui]: TLSv1.3 ciphersuites: TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256
2021.01.17 12:25:41 LOG7[ui]: TLS options: 0x02100004 (+0x00000000, -0x00000000)
2021.01.17 12:25:41 LOG6[ui]: Loading certificate from file: /etc/stunnel/keys-orig/clientcert.pem
2021.01.17 12:25:41 LOG6[ui]: Certificate loaded from file: /etc/stunnel/keys-orig/clientcert.pem
2021.01.17 12:25:41 LOG6[ui]: Loading private key from file: /etc/stunnel/keys-orig/clientkey.pem
2021.01.17 12:25:41 LOG6[ui]: Private key loaded from file: /etc/stunnel/keys-orig/clientkey.pem
2021.01.17 12:25:41 LOG7[ui]: Private key check succeeded
2021.01.17 12:25:41 LOG6[ui]: DH initialization not needed
2021.01.17 12:25:41 LOG7[ui]: ECDH initialization
2021.01.17 12:25:41 LOG7[ui]: ECDH initialized with curves X25519:P-256:X448:P-521:P-384
2021.01.17 12:25:41 LOG5[ui]: Configuration successful
2021.01.17 12:25:41 LOG7[ui]: Binding service [service]
2021.01.17 12:25:41 LOG7[ui]: Listening file descriptor created (FD=9)
2021.01.17 12:25:41 LOG7[ui]: Setting accept socket options (FD=9)
2021.01.17 12:25:41 LOG7[ui]: Option SO_REUSEADDR set on accept socket
2021.01.17 12:25:41 LOG6[ui]: Service [service] (FD=9) bound to 0.0.0.0:443
2021.01.17 12:25:41 LOG7[main]: Created pid file /var/lib/stunnel4/stunnel4.pid
2021.01.17 12:25:41 LOG7[cron]: Cron thread initialized
2021.01.17 12:25:41 LOG6[cron]: Executing cron jobs
2021.01.17 12:25:41 LOG6[cron]: Cron jobs completed in 0 seconds
2021.01.17 12:25:41 LOG7[cron]: Waiting 86400 seconds
2021.01.17 12:25:42 LOG7[main]: Found 1 ready file descriptor(s)
2021.01.17 12:25:42 LOG7[main]: FD=4 events=0x2001 revents=0x0
2021.01.17 12:25:42 LOG7[main]: FD=9 events=0x2001 revents=0x1
2021.01.17 12:25:42 LOG7[main]: Service [service] accepted (FD=3) from 10.8.5.1:58278
2021.01.17 12:25:42 LOG7[0]: Service [service] started
2021.01.17 12:25:42 LOG7[0]: Setting local socket options (FD=3)
2021.01.17 12:25:42 LOG7[0]: Option TCP_NODELAY set on local socket
2021.01.17 12:25:42 LOG5[0]: Service [service] accepted connection from 10.8.5.1:58278
2021.01.17 12:25:42 LOG6[0]: Peer certificate not required
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): before SSL initialization
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): before SSL initialization
2021.01.17 12:25:42 LOG7[0]: Decrypt session ticket callback
2021.01.17 12:25:42 LOG7[0]: SNI: no virtual services defined
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): SSLv3/TLS read client hello
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): SSLv3/TLS write server hello
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): SSLv3/TLS write certificate
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): SSLv3/TLS write key exchange
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): SSLv3/TLS write certificate request
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): SSLv3/TLS write server done
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): SSLv3/TLS write server done
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): SSLv3/TLS read client certificate
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): SSLv3/TLS read client key exchange
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): SSLv3/TLS read change cipher spec
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): SSLv3/TLS read finished
2021.01.17 12:25:42 LOG7[0]: Generate session ticket callback
2021.01.17 12:25:42 LOG7[0]: Deallocating application specific data for session connect address
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): SSLv3/TLS write session ticket
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): SSLv3/TLS write change cipher spec
2021.01.17 12:25:42 LOG7[0]: TLS state (accept): SSLv3/TLS write finished
2021.01.17 12:25:42 LOG7[0]:      1 server accept(s) requested
2021.01.17 12:25:42 LOG7[0]:      1 server accept(s) succeeded
2021.01.17 12:25:42 LOG7[0]:      0 server renegotiation(s) requested
2021.01.17 12:25:42 LOG7[0]:      0 session reuse(s)
2021.01.17 12:25:42 LOG7[0]:      0 internal session cache item(s)
2021.01.17 12:25:42 LOG7[0]:      0 internal session cache fill-up(s)
2021.01.17 12:25:42 LOG7[0]:      0 internal session cache miss(es)
2021.01.17 12:25:42 LOG7[0]:      0 external session cache hit(s)
2021.01.17 12:25:42 LOG7[0]:      0 expired session(s) retrieved
2021.01.17 12:25:42 LOG6[0]: TLS accepted: new session negotiated
2021.01.17 12:25:42 LOG6[0]: TLSv1.2 ciphersuite: ECDHE-RSA-AES256-GCM-SHA384 (256-bit encryption)
2021.01.17 12:25:42 LOG7[0]: Compression: null, expansion: null
2021.01.17 12:25:42 LOG6[0]: s_connect: connecting 127.0.0.1:80
2021.01.17 12:25:42 LOG7[0]: s_connect: s_poll_wait 127.0.0.1:80: waiting 10 seconds
2021.01.17 12:25:42 LOG7[0]: FD=6 events=0x2001 revents=0x0
2021.01.17 12:25:42 LOG7[0]: FD=11 events=0x2005 revents=0x1
2021.01.17 12:25:42 LOG5[0]: s_connect: connected 127.0.0.1:80
2021.01.17 12:25:42 LOG6[0]: persistence: 127.0.0.1:80 cached
2021.01.17 12:25:42 LOG5[0]: Service [service] connected remote server from 127.0.0.1:55304
2021.01.17 12:25:42 LOG7[0]: Setting remote socket options (FD=11)
2021.01.17 12:25:42 LOG7[0]: Option TCP_NODELAY set on remote socket
2021.01.17 12:25:42 LOG7[0]: Remote descriptor (FD=11) initialized
2021.01.17 12:26:10 LOG6[0]: Read socket closed (readsocket)
2021.01.17 12:26:10 LOG7[0]: Sending close_notify alert
2021.01.17 12:26:10 LOG7[0]: TLS alert (write): warning: close notify
2021.01.17 12:26:10 LOG6[0]: SSL_shutdown successfully sent close_notify alert
Architector
() автор топика
Ответ на: комментарий от mertvoprog

На сайты несколько раз цеплял интернет-эквайринги - там только через webhook. По привычке и тут так же начал - оно как-то понятнее, нежели long-polling

Architector
() автор топика
Ответ на: комментарий от Architector

Там в репозиторий есть файлик simple.cpp, который есть example с сайта openssl - просто принимает соединение и выводит на экран полученную инфу. Так вот. У него та же самая проблема.

Architector
() автор топика
Ответ на: комментарий от Architector

Прикол в том, что иногда все работает как надо, т.е. из 30 запросов сервера телеги, мой сервер обрабатывает как надо одно.

А остальные не может прочитать и все

Architector
() автор топика
Ответ на: комментарий от mertvoprog

Дык, я вот говорю, проблема не совсем в моей программе, а что-то явно не совсем так с телегой. И вообще видимо тему надо было по-другому назвать.

Вот репозиторий, который не мой. Там программа работает с сокетами и передаёт полученные данные в движок ssl. И всё та же проблема: данные приходят только после разрыва соединения. Ещё раз подчеркну, что при запросах к серверу (моему) с других VPS или просто через curl - всё всегда работает как надо.

https://github.com/darrenjs/openssl_examples

Architector
() автор топика
Ответ на: комментарий от Architector

А под strace всё зависает на recvfrom() или read()

Во время этого, если смотреть через tcpdump, пакетов нет. Вообще.

При этом ошибок SSL/TLS перед вызовом SSL_read() тоже нет.

Architector
() автор топика
Последнее исправление: Architector (всего исправлений: 3)
Ответ на: комментарий от Architector

Иногда, используя curl, получаю такое:

* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=RU; ST=MC; L=Moscow; O=OOP; OU=POO; CN=KT; emailAddress=dpt@KT
*  start date: Jan 12 16:29:12 2021 GMT
*  expire date: Jan 10 16:29:12 2031 GMT
*  issuer: C=RU; ST=MC; L=Moscow; O=OOP; OU=POO; CN=KT; emailAddress=dpt@KT
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
> POST / HTTP/1.1
> Host: KT
> User-Agent: curl/7.68.0
> Accept: */*
> Content-Type: application/json
> Cache-Control: no-cache
> Content-Length: 332
> 
* upload completely sent off: 332 out of 332 bytes
* Empty reply from server
* Connection #0 to host KT left intact
curl: (52) Empty reply from server
Architector
() автор топика
Последнее исправление: Architector (всего исправлений: 1)
Ответ на: комментарий от mertvoprog

Проблема ОП и на ассемблере решается

Но сложно.

а о мнимой декларативности пердона

Что значит мнимой? С какими проблемами столкнется ОП?

MOPKOBKA ★★★★
()
Ответ на: комментарий от Architector

при запросах к серверу (моему)

На других не проверяли, конечно же?

mertvoprog
()
Ответ на: комментарий от MOPKOBKA

Но сложно.

Писать высокопроизводительный код на пердоне тоже сложно. И уж явно не на декораторах.

С какими проблемами столкнется ОП?

Очевидно, с теми, что при реализации чего-то сложнее хеллоуврота вся декларативность закончится ;)

mertvoprog
()
Последнее исправление: mertvoprog (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

И что? Провайдер может в танке сидеть ;) Трафик так-то проходит, но вот DPI его глушит.

mertvoprog
()
Ответ на: комментарий от mertvoprog

Писать высокопроизводительный код на пердоне тоже сложно. И уж явно не на декораторах.

На С++ тоже сложно.

Очевидно, с теми, что при реализации чего-то сложнее хеллоуврота вся декларативность закончится ;)

Она заканчивается если нужно сделать что то необычное, у ОПа вроде все стандартное.

MOPKOBKA ★★★★
()
Ответ на: комментарий от MOPKOBKA

Ага, после реализации обычного хэллоуврота на TeleBot внезапно оказывается, что телеграмовские сервера не очень стабильно держат связь с ботом, и приходится городить недекларативные костыли с циклами, чтобы это прозрачно обрабатывать, ибо сам он не умеет, а внешний супервизор ничего не заподозрит ;)

mertvoprog
()
Ответ на: комментарий от mertvoprog

Если вы про файлик simple.cpp, то он для того, чтобы просто проблему подтвердить. Там парс HTTP лишний, просто чистить не охото было.

Да, парс мб и на коленке, но в моем случае нужно всего лишь, чтобы из POST запроса json вытащить. Мне кажется подключение огромной (по сравнению с моей функцией) библиотеки для парса HTTP излишним. Я же не в продакшн это сую, а чтобы поиграться.

А сервер да, в РФ, я вот тоже думаю, что от части в этом может быть проблема. Пойду в AWS Amazon бесплатную возьму, там попробую

Architector
() автор топика
Ответ на: комментарий от MOPKOBKA

Я просто не особо люблю интерпретируемые языки, поэтому мне кажется, что писать на питоне бота для ТГ - то же самое, что на баше его писать. Кстати, по началу так и делал, всё даже работало.

Architector
() автор топика
Ответ на: комментарий от mertvoprog

Ахахах,хахахахахах,АХАХААХАХ

Хы-хы

Наши с вами предположения все же оказались верными. Со зла арендовал ещё три VPS не в РФ и оно работает

Изначально в РФ брал, потому что дешевле 30руб. больше нигде вроде нет, а мне всего лишь потестить.

Тему теперь точно отмечаю решённой.

Ор

Architector
() автор топика
Последнее исправление: Architector (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

Выкидывать-то выкидывает, только поллинг после этого нужно перезапускать :P Да и обработка исключений сама по себе уже ни разу не декларативщина.

mertvoprog
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.