В этой статье я расскажу вам, как можно с помощью Nim разработать Telegram Web App, используя HappyX и telebot.
Nim
Nim - высокоуровневый язык программирования, компилируемый в C, C++, Objective-C и в JavaScript. Это позволяет нам разрабатывать как клиентские, так и серверные приложения.
HappyX
HappyX - это полнофункциональный веб-фреймворк, сочетающий в себе возможности бэкенда и фронтенда. В этой статье мы будем рассматривать исключительно его клиентскую часть.
telebot
Речь идет о библиотеке для Nim - telebot.nim. Она позволяет взаимодействовать нам с Telegram API. С ее помощью разработаем небольшого бота для этой статьи.
Окей, с чего начнем?
Установка
Если у вас не установлен Nim - установите его, следуя инструкции.
Затем с помощью встроенного в Nim пакетного менеджера nimble ставим последние версии необходимых нам библиотек - happyx и telebot:
nimble install happyx@#head
nimble install telebot@#head
Разработка бота
Создаем папку /bot
, в ней файл main.nim
. Импортируем нужные библиотеки:
import
telebot, # работа с Telegram API
std/asyncdispatch, # async
std/logging, # логирование
std/strutils # работа со строками
Теперь давайте создадим самого бота в Telegram. Для этого необходимо написать боту BotFather и написать /newbot
:
Также укажем поведение для кнопки рядом с полем ввода сообщения:
Для этого используем команду /setmenubutton
Важное примечание - указывайте ссылку на свой сайт, либо на будущий сайт на GitHub Pages.
Теперь возвращаемся в папку /bot
и создаем файл /bot/secret.key
. Лучше всего сразу занести его в .gitignore
:
ВАШ_API_КЛЮЧ
Далее переходим в main.nim
и подгружаем наш API ключ:
# Функция slurp прочитает содержимое файла на этапе компиляции
# а функция strip - обрежет пробелы в начале и конце строки
const API_KEY = slurp("secret.key").strip()
Следом пишем обработчик событий:
# Обработчик всех входящих событий
proc updateHandler(b: Telebot, u: Update): Future[bool] {.gcsafe, async.} =
# Получаем сообщение пользователя
var response = u.message
# Проверяем, если пользователь отправил хоть какое-то сообщение
if response.text.len > 0:
# Отсылаем обратно сообщение с единственной кнопкой
discard await b.sendMessage(
response.chat.id, "Play in this now!",
# Создаем inline клавиатуру
replyMarkup = InlineKeyboardMarkup(
kind: kInlineKeyboardMarkup,
inlineKeyboard: @[@[InlineKeyboardButton(
# Текст кнопки
text: "Play now!",
# Здесь в ссылке я указал сайт, на котором находится наше приложение на HappyX
webApp: WebAppInfo(url: "https://ethosa.github.io/tg-webapp-happyx/#/")
)]]
)
)
Осталось совсем чуть-чуть - запуск бота в коде:
# Блок ниже скомпилируется только в том случае,
# если мы запускаем этот файл напрямую.
#
# аналог питоновского if __name__ == '__main__'
when isMainModule:
# Подрубаем логирование
var L = newConsoleLogger()
addHandler(L)
# Создаем экземпляр бота
let bot = newTeleBot(API_KEY)
# Запускаем слушатель
bot.onUpdate(updateHandler)
bot.poll(timeout=300, clean = true)
Теперь запустим нашего бота и проверим, что происходит:
nim c -r -d:ssl ./bot/main
Если мы нажмем сейчас на кнопку - то ничего не увидим. Давайте теперь займемся самим приложением.
Приложение
Для начала создадим проект нашего приложения:
hpx create --name client --kind SPA --use-tailwind --language Nim
Теперь заходим в /client/src/main.nim
и меняем импорт:
import
happyx,
telebot/webapp
Затем пишем следующее:
# Задаем переменную для удобства
var tg = Telegram.WebApp
# Создаем реактивный счетчик
var counter = remember 0
# Настраиваем внешний вид главной кнопки снизу приложения
discard tg.MainButton.setText("Click me!")
discard tg.MainButton.show()
discard tg.MainButton.onClick(proc() =
# При клике на кнопку увеличиваем наш счетчик
counter->inc()
)
# Разворачиваем приложение на весь экран (mobile only)
tg.expand()
А теперь время верстки!
# Объявляем наше приложение
appRoutes "app":
# Основная страница
"/{p:string}":
tDiv(
class = fmt"flex flex-col justify-content items-center w-screen min-h-screen h-screen p-12 bg-[{tg.themeParams.bgColor}] text-[{tg.themeParams.textColor}]",
):
tDiv(class = "w-full h-full flex flex-col items-center justify-center"):
tP(class = "text-xl"):
"Hello from Nim, "
tSpan(class = fmt"text-[{tg.themeParams.buttonColor}]"):
{tg.initDataUnsafe.user.first_name}
"!"
tP(class = "text-9xl"):
{counter}
tDiv(class = "fixed bottom-4 right-4 opacity-70"):
"Your telegram version is v"
{tg.version}
И что же дальше, как мы увидим результат в Telegram?
Публикация
Под публикацией имеется ввиду загрузка на хостинг нашего приложения. В этой статье мы будем использовать GitHub pages.
Сперва удостоверимся, что структура двух наших приложений выглядит следующим образом:
Если все так, можем переходить к следующему шагу. Создаем папку ./.github/workflows/
, а в ней файл gh-pages.yml
:
name: Github Pages ?
on:
push
permissions:
contents: write
jobs:
docs:
runs-on: ubuntu-latest
env:
nim_version: '2.0.6'
steps:
- uses: actions/checkout@v4
- name: Install Nim ?
run: |
curl https://nim-lang.org/download/nim-${{ env.nim_version }}-linux_x64.tar.xz --output nim.tar.xz
tar -xf nim.tar.xz
sudo mkdir -p /home/.nimble
sudo mv -if nim-${{ env.nim_version }}/* /home/.nimble/
export PATH=/home/.nimble/bin:$PATH
nim -v
nimble refresh
nimble install happyx@#head telebot@#head -y
- name: Build website ?
timeout-minutes: 2
run: |
export PATH=/home/.nimble/bin:$PATH
nim js -d:release --opt:size --hints:off --warnings:off ./client/src/main
mkdir -p ./docs/
mkdir -p ./docs/public/
cp ./client/src/index.html ./docs/
cp ./client/src/main.js ./docs/
- name: Deploy documents ?
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
if: github.ref == 'refs/heads/master'
Теперь можно загружать все это дело в GitHub. После короткого ожидания выполнения GitHub Actions мы можем зайти в Telegram к нашему боту и открыть приложение.