СЛЕГ! <Z> ️
524 subscribers
678 photos
20 videos
12 files
307 links
Здесь создают авторских телеграм-ботов. Когда не справляются конструкторы и веб-студии - есть СЛЕГ.

Статистика ботов:
https://ssleg.tech/bots_view.html

Написать автору: @yesitsnew

TW: ещё тут политота, утечки баз и игры в товарища майора на минималках
加入频道
У asyncio есть очень удобные методы вызова функций, как обычных, так и асинхронных, через произвольное время в секундах, но есть ньюанс.

В потоке событий телеграм это эксплуатируется вот так (для обычных функций)

from telethon import TelegramClient
client: TelegramClient
client.loop.call_later(delta.seconds, basegen) - задержка в секундах, имя функции.

Соответственно мне нужно, чтобы функция бота basegen выполнялась каждый день в три часа ночи. В реальности она выполнилась несколько сотен раз в момент 2:59:59-3:00:00.

Потому что я забыл о тонкостях самого питоновского класса timedelta. На слайде подробно разбирается, что пошло не так под дебагером.

Из за неточностей таймера компа, asуncio гарантирует секунду, в которою все запустится, но не её доли. И функцию первый раз вызвало в 2:59:59.522.

Все бы хорошо, но timedelta вычитая разницу времени, даёт все что больше суток как дни и секунды. Получилось 1 день и ноль секунд.

Правильный вариант считать задержку через timedelta это 13 строка. :)
Тележенька взорвалась от выборов в Белоруссии. За сутки в чаты залетело 4905 человек.

Основная движуха здесь:

@minsk_new +772 человек. Чат Минска.
@majakrainablr +1899 чат выборов.

И наш "протестный" чат канала ateo
@Ateo_Chat +570

Приятного аппетита :)
Таракан протест кажется все. Сдувается. Приток ощутимо сократился, не смотря на все попытки его раздуть. График и табличка с данными по новым юзерам в политчатиках с начала августа.

Туда и дорога, ибо тема белоруссии мне лично уже надоела.
СЛЕГ! <Z> ️
Photo
Чао, бамбино, сорри 😁
+4059, на треть меньше пика.
Итоги выходных - стабилизация на уровне +2700 в сутки. Тема протеста окончательно протухла. Не смотря на истерику в каналах тг-оналитегов.
Вы будете удивлены, но эти 44 строчки это все что нужно, чтобы принимать платежи в боте через Qiwi.

Звание самого простого API года, не менее. Понятно, что нужно ещё обмазываться проверкой кодов ответа сервера (если на той стороне что-то пошло не так), но минимальный набор выглядит так.

Три функции.

Создание счета на сумму и валидного до даты/времени (на входе str(datetime)). Даёт ссылку на платёжную форму, в которой клиент платит любой картой российского банка.

Проверка состояния счета (не оплачен, оплачен, просрочен)

Отмена вовремя не оплаченных счетов (не обязательно, это опция).

Всё!
qiwi_module.py
3.2 KB
Полностью готовый модуль для киви. Обмазан перехватом ошибок, логированием, проверками кода ответа сервера и комментариями. Надеюсь, это ускорит разработку парочки дружественных проектов.

UPD: это устаревшая версия. Актуальная версия и документация лежит на https://git.ssleg.tech/anton/qiwi_module

Вопросы, замечания и благодарности можно складывать под этим постом
https://yangx.top/ssleg/322
Поскольку Паша у нас либертарианец, то стандарты ему не писаны и у телеграм свое понимание языка markdown. Причём не описанное в документации, но легко излекающееся из сообщений.

Держите рабочую шпаргалку, как форматировать текст в сообщениях.

В результате получится такая строка:

123 123 123 123 123 123 123 123 123
Когда написал реально большого бота. Это промежуточный итог, в релиз вышло 1636 строк кода и ещё 400+ в текстовых блоках.

Один четыре восемь восемь, кодить мы питон не бросим! 😁
И тут со дна постучали в зелёный люк. 😂
Говорят, что на линкус сложно играть. Мне тут захотелось в танчики какие-нибудь погонять - без проблем и даже бесплатно.

Устанавливаешь steam, а там игр на любой вкус. Это пятый час игры с нуля, в первый попавшийся бесплатный симулятор.
Асинхронное программирование это очень круто. Но надо иметь в виду, что все части программы исполняются в произвольном порядке, как будет удобнее планировщику и все что может пойти не так, рано или поздно произойдет.

Например, мы собираем информацию о сообщениях в чате и на ее основании принимаем автоматические решения (разрешить или запретить юзеру что-то делать).

В телеграм для этого используются два разных хандлера.
Один - events.ChatAction(), для событий входа в чат и/или добавления юзера.
Второй - events.NewMessage(), срабатывает на сообщения в чате.

Все это крутится в потоке asyncio и вроде бы логично, что юзер сначала входит в чат, а потом что-то пишет. И времени должно хватать на обработку по порядку (нет).

А теперь реальность. В чат входит бот и сразу что-то постит. Лог с таймингами:

Хандлер ChatAction() получил информацию и поставил ее в общую очередь команд админки.
INFO module_one [2020-09-25 06:26:23,321]
вход в <...> #729730 1386306872
INFO module_one [2020-09-25 06:26:23,321]
команда: (6, 0, 1xxxxxxxxx, 0, 0, 1386306872)


Но поскольку мой сервер загружен, ботов там уже трое, а процессор один, поток asyncio сжался по времени и всего через 11 миллисекунд уже пошла обработка хандлера NewMessage():
ERROR updates [2020-09-25 06:26:23,332]
Unhandled exception on mytask
Traceback (most recent call last):
<...>
File "/home/admin_utils/module_three.py", line 25, in mytask
values (%s, %s, %s, %s, %s, %s, %s)''', entry)
psycopg2.errors.ForeignKeyViolation: insert or update on table "vino" violates foreign key constraint "vino_users_user_id_fk"
DETAIL: Key (user_id)=(1386306872) is not present in table "users".


С очевидным итогом "отсутвует такой юзер в бд", ведь он еще никуда не записан, он только поставлен в очередь. Бдыщ!

Вот за этим и нужны внешние ключи в базах данных. Обработчик в модуле упал (но встанет сам, с поступлением следующего сообщения), а база данных сохранила целостность.

Еще через 0,7 секунды (709 миллисекунд) поток доходит до своей очереди команд и записывает юзера в базу. Но уже поздно 😁
INFO module_one [2020-09-25 06:26:24,041]
обработчик начал
INFO module_one [2020-09-25 06:26:24,097]
(1386306872, 'Margarita Del Carmem', 'Peña Almonte', None, None)
INFO module_one [2020-09-25 06:26:24,098]
обработчик закончил


Основное, что нужно запомнить и предусматривать всегда. Любая отдельная функция, которая крутится в потоке asyncio, может быть выполнена перед любой другой, даже если по логике вещей этого быть не может.

Поэтому любые зависящие друг от друга функции должны иметь возможность обмениваться сигналами. Например, делать блокировку записи.

Об этом в следующем посте, не переключайтесь 👋
Как бы помягче объяснить, что Дуров и его команда плохие люди. (мат вырезан цензурой).

Без объявления войны, телеграм 1.5 часа назад изменил формат выдачи постов. Просто потому что может.

Есть канал и привязанный к нему чат. До сегодняшнего дня, посты канала, отображались в чате как форварды, но от пустого юзера. То есть поле from_id всегда было None.

Было два идентификатора: ID канала (2584) и ID чата (0549). Теперь появился третий, виртуальный "пользователь" с ID оканчивающимся на 8824.

Естественно, мне сейчас придётся быстро переписывать в паре мест логику Фомы (моего бота).

P. S. Судя по всему, этот костыль команда телеграм сделала, чтобы "администраторы чатов могли отправлять в чат анонимные сообщения" (из пресс релиза) .

Upd: Ситуация не настолько плоха, как казалось вначале. Они сделали единый ID для костыля, и во всех чатах посты из канала идут от бота телеги. Теперь всегда from_id=1087968824.
Прошло пять часов, и у команды телеграм переполнилась панамка.

Всё вернули как было раньше.

Чтобы вы понимали, в тг порядка 2 млн ботов, владельцы которых были "невероятно счастливы" необходимостью в авральном режиме обновлять свой код.

Начало истории
Давно не хвастался. База данных фейсконтроля чатов на 1 октября 2020 года :)
СЛЕГ! <Z> ️
Асинхронное программирование это очень круто. Но надо иметь в виду, что все части программы исполняются в произвольном порядке, как будет удобнее планировщику и все что может пойти не так, рано или поздно произойдет. Например, мы собираем информацию о сообщениях…
Проблему асинхронности пришлось решить радикально.

Ведь благодаря новым фичам, в чатах теперь могут писать люди, в них в принципе не состоящие.

Поэтому алгоритм получился такой:

1) ловим ошибку постгрес, с отсутствием ключа. Запись помещается в кэш (откройте для себя класс питон queue, не пожалеете)

2) раз в минуту этот кэш проверяет обработчик. Если запись находится в очереди менее 30 секунд, он её пропускает.

3) если запись древнее 30 секунд, то проверяется, есть ли юзер в базе. Если его все ещё нет, то его можно записать через запрос get entity, это точно мимопроходивший. После чего внести наконец то запись в таблицу.

P. S. К теме блокировок для разных процессов я ещё вернусь, но на другом материале.
Поскольку все равно пришлось срочно лезть в код, Фома научился ещё одной шутке, которую не умеют конкурирующие чатботы: автоматическая перезаливка длиннотекстов, которые форвардят в чат. Ибо бороться с этим обычным путем затратно и в целом бесполезно.