Skip to content

Instantly share code, notes, and snippets.

@iliakonnov
Last active March 8, 2022 08:40
Show Gist options
  • Save iliakonnov/68ecac56055dc3342146e4fdc14e158c to your computer and use it in GitHub Desktop.
Save iliakonnov/68ecac56055dc3342146e4fdc14e158c to your computer and use it in GitHub Desktop.

Версия 1.0, на баше

Это простейший CGI-скрипт, который в ответ на json от телеграма дергает РУЗ, берет другой json и выдаёт ещё один json с сообщением. Не вижу смысла для перекладывания джсонов тащить что-то сложнее баша, так что вот.

Чтобы его поднять, нужно:

  1. Иметь nginx, домен и настроенный https к нему (можно self-signed).
  2. Поднять в нём поддержку CGI. Например, при помощи fcgiwrap.
  3. Установить зависимости: curl и jq.
  4. Сделать, чтобы на запрос по выбранному URL запускался скрипт hse-schedule.sh.
    • Можно просто взять конфиг ruz201bot.nginx и не забыть поправить пути.
    • Не забудьте перезагрузить конфиги! systemctl reload nginx
  5. Наконец, чтобы telegram делал запросы на этот URL.

Версия 2.0, для Cloudflare Workers

Поскольку Oracle решил прикрыть для меня их бесплатную впску, произошёл переезд на Cloudflare Workers. Код находится в файле cloudflare_worker.js.

addEventListener("fetch", (event) => {
event.respondWith(
handleRequest(event.request).catch(
(err) => new Response(err.stack, { status: 500 })
)
);
});
function dateToYMD(date) {
var d = date.getDate();
var m = date.getMonth() + 1; //Month from 0 to 11
var y = date.getFullYear();
return '' + y + '.' + (m<=9 ? '0' + m : m) + '.' + (d <= 9 ? '0' + d : d);
}
async function handleRequest(request) {
const { pathname } = new URL(request.url);
if (!pathname.startsWith("/superSecret")) {
return new Response(JSON.stringify({ "error": "access denied" }))
}
const tg = await request.json();
let now = new Date();
now = now.getTime() + (now.getTimezoneOffset() * 60000);
now = new Date(now + 3*3600*1000);
const date = dateToYMD(now);
const ruz = await fetch(`https://ruz.hse.ru/api/schedule/group/54906?start=${date}&finish=${date}&lng=1`).then(r => r.json());
const message = ruz
.map(x => ({
url1: (x.url1 ?? ""),
url2: (x.url2 ?? ""),
url1_desc: (x.url1_description ?? x.url1 ?? "").replace(/\p{Cc}/ug, " "),
url2_desc: (x.url2_description ?? x.url2 ?? "").replace(/\p{Cc}/ug, " "),
offset: (new Date(date + " " + x.beginLesson) - now) / 60000,
discipline: x.discipline,
auditorium: x.auditorium,
beginLesson: x.beginLesson,
}))
.filter(x => (x.offset >= -20 && x.offset <= 20))
.map(x => `<b>${x.discipline}</b> в ${x.beginLesson} (${Math.round(x.offset)} мин)\nСсылка: <a href="${x.url1}">${x.url1_desc}</a> | <a href="${x.url2}">${x.url2_desc}</a>\nАудитория: ${x.auditorium}`)
.join("\n------\n")
;
const result = {
method: "sendMessage",
chat_id: tg.message.chat.id,
reply_to_message_id: tg.message.message_id,
text: (`[${now.toLocaleString('ru-RU')}] Ближайшие пары:\n` + message),
parse_mode: "HTML",
disable_web_page_preview: true,
};
return new Response(
JSON.stringify(result, null, 2), {
headers: {
'content-type': 'application/json;charset=UTF-8',
}
}
);
}
#!/bin/bash
set -e
printf 'Content-type: application/json\n\n'
date=$(date +"%Y.%m.%d")
tg="$(cat /dev/stdin | head -c 16384 | jq -r)"
if echo "$tg" | jq -e '.message.text as $text
| [
.message.entities[]
| select(.type == "bot_command")
| $text[.offset:.offset+.length]
| startswith("/ruz")
] | any | not' 2>&1 >/dev/null
then
# Not for me
exit 0
fi
curl -s "https://ruz.hse.ru/api/schedule/group/54906?start=$date&finish=$date&lng=1" | jq --argjson tg "$tg" '[.[]
| {
discipline: .discipline,
auditorium: .auditorium,
url1: (.url1 // ""),
url2: (.url2 // ""),
url1_desc: (.url1_description // .url1 // "") | gsub("\\p{Cc}"; " "),
url2_desc: (.url2_description // .url2 // "") | gsub("\\p{Cc}"; " "),
beginLesson: .beginLesson,
offset: ((
(now | strftime("%Y.%m.%d ")) + .beginLesson
| strptime("%Y.%m.%d %H:%M")
| mktime - 10800 - now
) / 60)
}
| select(.offset >= -20 and .offset <= 20)
| "<b>\(.discipline)</b> в \(.beginLesson) (\(.offset | round) мин)\nСсылка: <a href=\"\(.url1)\">\(.url1_desc)</a> | <a href=\"\(.url2)\">\(.url2_desc)</a>\nАудитория: \(.auditorium)"
] | join("\n------\n") | {
method: "sendMessage",
chat_id: $tg.message.chat.id,
reply_to_message_id: $tg.message.message_id,
text: ("Ближайшие пары:\n" + .),
parse_mode: "HTML",
disable_web_page_preview: true,
}'
# Put this to your sites-enabled/ruz201bot.conf
server {
server_name YOURDOMAIN.EXAMPLE;
listen 80;
listen [::]:80;
listen 443 ssl;
listen [::]:443 ssl;
# Assuming self-signed certificate
ssl_certificate /opt/ruz201bot/YOURPUBLIC.pem;
ssl_certificate_key /opt/ruz201bot/YOURPRIVATE.key;
location / {
fastcgi_param SCRIPT_FILENAME /opt/ruz201bot/hse-schedule.sh;
# fastcgi_params often already exists, but if not:
# cp /usr/share/doc/fcgiwrap/examples/nginx.conf /etc/nginx/fcgiwrap_params
include fastcgi_params;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment