Satont.
300 subscribers
318 photos
52 videos
1 file
201 links
Download Telegram
9❤‍🔥1
9❤‍🔥1
❤‍🔥102😱1🦄1
104❤‍🔥3
Я сегодня на квадроциклах катался.

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

Аппараты мощные, крутые, я бы с удовольствием это повторил.
❤‍🔥8
🚀 Twitch EventSub: от Webhook к WebSocket и Conduit! 🕸

Привет! 👾 Сегодня расскажу, как я перевёл своего бота с Webhook на WebSocket и Conduit для обработки ивентов на Twitch. Поделюсь что изменилось и почему это круто.

Twitch раньше: IRC + WebSocket 📡
Раньше Twitch использовал IRC через WebSocket для чатов, банов и прочего.
IRC сам по себе довольно устаревший морально, с некоторыми ограничениями, в том числе от твича.
Это был не самый удобный вариант, потому что:

- Жёсткие лимиты на подключение к чатам (не более 10ти за 2 секунды)
- Ограничения по количеству каналов и WS-соединений с одного IP
- Не самый надёжный способ для масштабирования

Twitch сейчас: EventSub 🌍

Twitch шагнул вперёд, внедрив EventSub с разными типами транспорта. Давайте сравним их:

1️⃣ Webhook

Плюсы: Легко настраивать, просто масштабировать.
Минусы: Нужен HTTPS-домен, что усложняет разработку. HTTP 1.1 и WAF (например, Cloudflare) тормозят доставку. Не идеально для real-time.

2️⃣ WebSocket

Плюсы: Real-time, минимум ресурсов, идеально для локальной разработки.
Минусы: Нужно следить за стабильностью WS-соединения и восстанавливать подписки, работает только по принципу 1 соединение = 1 канал.

3️⃣ Conduit — король масштабирования! 👑

Это транспорт, объединяющий WebSocket и Webhook в шарды. Twitch сам роутит ивенты, балансирует нагрузку и отбрасывает неактивные подключения.

Плюсы:
- Подписки на ивенты не теряются при сбоях.
- Поддержка множества транспортов (до 20к шардов!).
- Можно роутить разные подписки на разные Conduit — масштабирование почти бесконечное! 🚀

Минусы: Наследует ограничения WebSocket/Webhook, плюс нужно обновлять шарды через API.

Что я получил?
Conduit спасает подписки!

- У меня 20к+ подписок на ивенты. Раньше при долгом downtime они обрубались, и приходилось удалять -> создавать их по одному запросу. Теперь подписки висят на Conduit и не умирают при сбоях.
- Мы очень быстрые

С WebSocket бот отвечает быстрее, чем Fossabot и Nightbot в 50% случаев:
SatontMiyamo: !speedtest
TwirApp: speedtest 🚀
Fossabot: speedtest 🐢
Nightbot: speedtest 🐢


- Масштабирование и ещё раз масштабирование
Сохранил несколько реплик приложения, все на WebSocket. Масштабирование работает как в одном приложении (несколько WS), так и горизонтально по репликам.
- Прощай, Webhook! 👋

Убрал долгий путь: Twitch → Cloudflare HTTP (WAF, e.t.c) → Cloudflare Tunnels → Traefik → TwirEventsub → обратно. Теперь всё проще и быстрее.
- Своя библиотека для EventSub
Позволяет быстрее внедрять правки, новые ивенты.

Итог: WebSocket + Conduit = скорость, масштабируемость и надёжность. Если работаете с Twitch EventSub, попробуйте этот подход. Так же можете взглянуть на либу, которую делает kvizix, и в которую я активно контрибьючу.
5👍9🔥4😁2🆒1
Satont.
🚀 Twitch EventSub: от Webhook к WebSocket и Conduit! 🕸 Привет! 👾 Сегодня расскажу, как я перевёл своего бота с Webhook на WebSocket и Conduit для обработки ивентов на Twitch. Поделюсь что изменилось и почему это круто. Twitch раньше: IRC + WebSocket 📡 Раньше…
Забыл упомянуть, что теперь все действия с чатом/каналом происходят через вызовы api методов. От отправки сообщений, банов, до запуска опросов, рекламы.
О боже, у YouTube появился real-time траспорт в апи для сообщений со стримов, не может быть.

НОО.
Что вы думаете, какой траспорт они выбрали? WS? IRC? Webhooks? SSE? Может быть Long-polling?
Да нифига подобного, чуваки решили выбрать grpc стримы. Пожалуй самый малоудобный транспорт из всех.

Гугл клоуны, я не удивлён.
🥴5😁1
Channel photo updated
🚀 Blazingly fast twir builds
3min -> 1min

Первым делом я посмотрел, и подумал. А зачем мне билдить 2 билеотеки types+api, которые являются deprecated. То есть они обе потихоньку выпиливаются, и я могу убрать их из пайплайна, и убрать их из гитигнора. Там ничего не меняется, потому конфликтов не будет в будующдем.
Результат: -40 секунд.

Потом я пошёл курить почему у меня каждый раз выкачиваются зависимости при билде, хотя кэшы у меня настроены.
Поправил этот моментик.
Результат: -30 секунд.

Потом я обратил внимание, что почему-то сам go build приложений не работает.
Случилось так, потому что у меня матрица на билд всех моих (микро)сервисов. Оно просто не может конкуретно записать билд кэш из-за параллельных билдов.
Добавил каждому приложению свой уникальный кэш-ключ с хэшом на go.mod, что позволило мне сильно сократить скорость билда.
      - name: Compute Go files hash
if: ${{ matrix.folders.runtime == 'go' && env.run-build == 'true' }}
id: go-files-hash
run: |
echo "hash=$(sha256sum go.work go.work.sum ${{ matrix.folders.path }}/go.mod ${{ matrix.folders.path }}/go.sum 2>/dev/null | sha256sum | awk '{print $1}')" >> $GITHUB_ENV

- name: Cache Go build
if: ${{ matrix.folders.runtime == 'go' && env.run-build == 'true' }}
uses: actions/cache@v4
with:
path: |
~/.cache/go-build
key: ${{ runner.os }}-go-${{ matrix.folders.path }}-${{ env.hash }}
restore-keys: |
${{ runner.os }}-go-${{ matrix.folders.path }}-


Итог: -30 секунд.

Далее я увидел, что gha кэш на докер образы почему-то тоже как-то непорядочно медленно распаковывается. Я решил потестить кэш через свой registry:
      - name: Build docker image
if: env.run-build == 'true'
uses: docker/build-push-action@v5
with:
context: .
file: ./${{ env.folder }}/${{ env.app }}/Dockerfile
push: true
tags: |
registry.twir.app/twirapp/${{ env.app }}:latest
cache-from: type=registry,ref=registry.twir.app/twirapp/${{ env.app }}:latest
cache-to: type=inline

И билд докер образа теперь занимает 10!!!! секунд.

И того, теперь у меня приложения билдятся не 2.5-3 минуты, а одну.

https://github.com/twirapp/twir/blob/main/.github/workflows/dockerv3.yml
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥111😁1
Сделал вот такой вот виджет валорант статистики.
Стата берётся за стрим текущий.

Дизайн взял у зрителя с проекта https://beta.valory.su
❤‍🔥8🔥2
Вернул https://twir.app за cloudflare, потому те кто из России сообщите доступен ли домен без впн, запретов, и прочего.
Anonymous Poll
41%
Доступен
14%
Не доступен
45%
Посмотреть результат
Satont.
Вернул https://twir.app за cloudflare, потому те кто из России сообщите доступен ли домен без впн, запретов, и прочего.
Проголосуйте те, кто не проголосовал. Кому лень печатать адрес, вот: https://twir.app
1
Satont.
Вернул https://twir.app за cloudflare, потому те кто из России сообщите доступен ли домен без впн, запретов, и прочего.
Перевёл реверс прокси на другой хост, теперь проблем с доступом из России быть не должно.
Spotify представили loselss кач-во музыки.

2025 год...
Пути-безопасный i18n на Golang бэкенде в Twir.

Захотелось мне поюзать i18n на бэке твира, и сразу в голове появилась мысль: а почему бы мне не сделать type-safe путь до строк? Например в TypeScript это легко решается декларированием глобального типа в одном месте, с базой от импорта .json, с последующей трансформацией в плоскую структуру.
Я захотел так же в го.

В итоге написал реализацию генератора через AST дерево, смотрит в yaml файлики и ключи внутри, и в итоге генерирует мне вложенные структуры ключей, с типизированными переменными внутри строк перевода. Склееный контент всех файлов тоже выплёвывается в .go файл, потому не нужно эмбедить переводы в бинарь, они уже и так есть в map.

То есть, если мой генератор видит строку вида Error happend, {reason}, он автоматом сгенерит структуру с филдом Reason внутри.

Использование либы максимально простое получилось:
i18n.GetCtx(
ctx,
locales.Translations.Commands.Seventv.Errors.ProfileNotFound.SetVars(locales.KeysCommandsSeventvErrorsProfileNotFoundVars{Reason: err.Error()}
)



Контекст нужен, чтобы достать из него локаль для последующего использования (с дефолтом внутри), а SetVars выступает как конструктор по сути, просто мне так удобнее в плане нейминга здесь. Ну и для каждого ключа свой SetVars, с конкретным типом структуры.

Ни и вот пример сгенерированного файла: https://github.com/twirapp/twir/blob/main/apps/parser/locales/locales.go

Осталось только действительно взять и написать переводы. =)
😁2👍1