콘텐츠로 이동
AstroWay/api v2.325.0 · ko
모든 시스템 정상 작동 중

Slack: команда /horoscope

Last updated Markdown으로 보기 에이전트 설정

이 콘텐츠는 아직 번역되지 않았습니다.

Хтось у каналі пише /horoscope leo, і в канал приходить гороскоп Лева на сьогодні. Slack надсилає команду POST-запитом на ваш сервер і чекає відповіді не довше за 3 секунди, тож серверу потрібна публічна адреса з HTTPS. Бібліотека Bolt не потрібна: увесь обмін це один запит і одна відповідь.

  1. На api.slack.com/apps натисніть Create New App → From scratch і виберіть робочий простір.
  2. Slash Commands → Create New Command: команда /horoscope, Request URL https://bot.example.com/slack/horoscope, Usage Hint leo.
  3. Basic Information → App Credentials: скопіюйте Signing Secret.
  4. Install App → Install to Workspace.
  5. Ключ AstroWay Тільки сервер з областю public/horoscope/*, як описано в розділі Ключ для автоматизації.
Terminal window
export ASTROWAY_API_KEY="aw_live_..."
export SLACK_SIGNING_SECRET="..."

Збережіть як slack.mjs і запустіть node slack.mjs:

slack.mjs
// Node 22 or newer, no dependencies.
import { createServer } from 'node:http';
import { createHmac, timingSafeEqual } from 'node:crypto';
const ASTROWAY = 'https://api.astroway.info/v1';
const LANG = 'uk';
// One text per sign per day: at most 12 calls a day, whatever the traffic.
const cache = new Map();
const SIGNS = ['aries', 'taurus', 'gemini', 'cancer', 'leo', 'virgo',
'libra', 'scorpio', 'sagittarius', 'capricorn', 'aquarius', 'pisces'];
function signedBySlack(raw, timestamp, signature) {
// Older than five minutes reads as a replay.
if (!timestamp || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = 'v0=' + createHmac('sha256', process.env.SLACK_SIGNING_SECRET)
.update(`v0:${timestamp}:${raw}`).digest('hex');
return signature?.length === expected.length && timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
async function horoscope(sign) {
const key = `${new Date().toISOString().slice(0, 10)} ${sign}`;
if (!cache.has(key)) {
const res = await fetch(`${ASTROWAY}/public/horoscope/daily?sign=${sign}&lang=${LANG}`, {
headers: { 'X-Api-Key': process.env.ASTROWAY_API_KEY },
});
const json = await res.json();
if (!json.ok) return { response_type: 'ephemeral', text: `AstroWay: ${json.error.message}` };
cache.set(key, `*${sign}, ${json.data.date}*\n${json.data.horoscope}`);
}
return { response_type: 'in_channel', text: cache.get(key) };
}
createServer(async (req, res) => {
const chunks = [];
for await (const chunk of req) chunks.push(chunk);
const raw = Buffer.concat(chunks).toString();
if (!signedBySlack(raw, req.headers['x-slack-request-timestamp'], req.headers['x-slack-signature'])) {
res.writeHead(401).end();
return;
}
const sign = new URLSearchParams(raw).get('text')?.trim().toLowerCase() ?? '';
const reply = SIGNS.includes(sign)
? await horoscope(sign)
: { response_type: 'ephemeral', text: `Usage: /horoscope leo\n${SIGNS.join(', ')}` };
res.writeHead(200, { 'Content-Type': 'application/json' }).end(JSON.stringify(reply));
}).listen(process.env.PORT ?? 3000);
  • Підпис. Slack підписує кожен запит: HMAC-SHA256 від v0:<timestamp>:<тіло> вашим Signing Secret. Код перевіряє підпис і відкидає запит, старший за п’ять хвилин, тож чужий або повторений запит отримує 401.
  • in_channel чи ephemeral. Гороскоп бачать усі в каналі, а підказку чи помилку бачить лише той, хто набрав команду.
  • 3 секунди. Перший запит знака за день іде в API, наступні беруться з кешу за кілька мілісекунд. Якщо замінити гороскоп на щось повільніше, наприклад PDF-звіт, відповідайте одразу, а результат надсилайте пізніше на response_url із тіла запиту.
  • Ліміт. Ключ Free на /v1/public/* рахується як запит без ключа, 30 на годину з IP сервера; кеш тримає бот у межах 12 запитів на добу. Неправильний ключ тут не дає 401, а мовчки отримує той самий анонімний ліміт.