Перейти к основному содержанию
Разработчикам Обновления вживую

Обновляйте сообщения вживую

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

Что можно сделать

  • Обновляйте карточкуМеняйте текст, цвет и кнопки прямо на месте.
  • Показывайте ход работыИндикатор загрузки, который проходит по шагам, а затем результат.
  • УдаляйтеУбирайте сообщение, когда оно перестало быть актуальным.
  • СлушайтеОтветы, реакции и нажатия кнопок на вашем сообщении, вживую.

В приложении

Опубликовано с индикатором загрузки

Обновлено: шаг 2 из 3

Обновлено: готово, с кнопкой

Одно сообщение, дважды обновлённое через callback URL. Никто не видит три сообщения, только одно, которое меняется.

Быстрый старт

  1. Сохраните callback URL

    Каждая публикация через вебхук и каждый запрос команды приходят с callback_url для этого сообщения.

    bash
    BODY='{"message_container": {"color": "blue", "loader": true, "loader_text": "Deploying…"}}'
    SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$MSSGS_WEBHOOK_SECRET" | sed 's/^.* //')
    
    curl -X POST "$MSSGS_WEBHOOK_URL" -H "Content-Type: application/json" \
      -H "X-Mssgs-Signature: sha256=$SIG" -d "$BODY"
    
    # {"success": true, "message_id": "...", "callback_url": "https://mss.gs/api/v1/trigger-callback/8f14e45f-..."}
  2. PUT, чтобы обновить

    Отправьте новое состояние. Карточка изменится на месте для всех.

    bash
    curl -X PUT "$CALLBACK_URL" -H "Content-Type: application/json" \
      -d '{"message_container": {"color": "green", "title": "Deploy complete", "description": "v2.1 is live."}}'
  3. DELETE, чтобы удалить

    Тело не нужно.

    bash
    curl -X DELETE "$CALLBACK_URL"

Обновление сообщения

Отправьте JSON методом PUT на callback_url. Передавайте только то, что хотите изменить.

ПолеТипЧто делает
message_containerobjectНовая карточка. См. карточки сообщений.
actionsarrayНовые кнопки. "actions": [] убирает их все; если не передать поле, кнопки останутся.
contentstringНовый текст.
title, description, color, loader, ...stringСокращение: поля карточки на верхнем уровне автоматически оборачиваются в карточку.
Новый message_container заменяет старую карточку целиком: поле, которое вы не передали, исчезнет. Сохраняются только её тип, имя и аватар. Поэтому каждый раз отправляйте карточку полностью.

Ответы

СтатусКодЧто означает
200{"success": true}Принято. Обновление последует сразу же.
400MISSING_FIELDSВ теле нечего обновлять.
400INVALID_BODYТело не является корректным JSON.
400код ошибки кнопкиЧто-то не так с кнопкой, см. кнопки.
401INVALID_TOKENURL недействителен.
404TOKEN_NOT_FOUNDСрок действия URL истёк, или через него уже удалили сообщение.
502PUBLISH_FAILEDОбновление не удалось доставить. Повторите попытку.

Сколько это работает

30 минут с момента публикации сообщения или использования команды. Обновление этот срок не продлевает. После удаления сообщения URL больше не действует. Через обновление нельзя добавить файлы.

Показ хода работы

Опубликуйте карточку с индикатором загрузки, обновляйте её дополнительную строку по мере продвижения задачи и закончите результатом. Индикатор загрузки представляет собой спиннер со строкой и строкой поменьше под ней (loader_text, loader_sub_text).

javascript
const { callback_url } = await post({
  message_container: { color: 'blue', loader: true, loader_text: 'Deploying…', loader_sub_text: 'Step 1 of 3: building' }
});

const update = (body) => {
  return fetch(callback_url, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });
};

await build();
await update({ message_container: { color: 'blue', loader: true, loader_text: 'Deploying…', loader_sub_text: 'Step 2 of 3: running migrations' } });

await migrate();
await update({
  message_container: { color: 'green', title: 'Deploy complete', description: 'v2.1 is live on production.' },
  actions: [{ type: 'url:https://ci.example.com/deploys/218', text: 'View logs', color: 'green' }]
});

Удаление сообщения

Отправьте DELETE на callback_url, и сообщение исчезнет у всех. После этого URL использовать нельзя.

Прослушивание сообщения

stream_url представляет собой живой поток (Server-Sent Events) того, что происходит с вашим сообщением. Откройте его, и события будут приходить по мере того, как они происходят, каждое в виде JSON-строки data:, в которой type говорит, что это за событие:

sse
curl -N "$STREAM_URL"

data: {"type": "reaction", "message_id": "...", "emoji": ":tada:", "action": "add", "member_guid": "...", "member": {...}, "ts": 1790000000000}

data: {"type": "action", "message_id": "...", "action_id": "approve", "action": {"id": "approve", "payload": {"deploy": 218}, ...}, "member_guid": "...", "member": {...}, "ts": 1790000004200}

data: {"type": "reply", "message_id": "...", "content": "Ship it!", "member_guid": "...", "member": {...}, "ts": 1790000009800}

event: expired
data: {}
СобытиеКогдаДанные
actionНажата кнопка.action_id и сохранённая кнопка в action с её payload
reactionРеакция добавлена или удалена.emoji и action: add, remove или removeall
replyКто-то ответил на сообщение.content ответа
expiredПоток закрывается. Отправляется как именованное событие.Нет
События не сохраняются на потом. Открывайте поток, как только получили URL: то, что произошло до подключения, не отправляется. Каждое событие также содержит message_id, кто его совершил (member_guid, member) и когда (ts). Строка-комментарий каждые 20 секунд держит соединение открытым.

Прослушивание на JavaScript

javascript
const events = new EventSource(streamUrl);

// Every event arrives as a plain message; its kind is in "type".
events.onmessage = (e) => {
  const ev = JSON.parse(e.data);
  if ((ev.type === 'action') && (ev.action_id === 'approve')) {
    startDeploy(ev.action.payload.deploy);
  }
};

// The one named event: the stream is closing.
events.addEventListener('expired', () => {
  events.close();
});

Где его взять

Откуда он берётсяОткрыт в течение
Публикация через вебхук с кнопками10 минут или час с "sse_event_extended_timeout": true
Каждый запрос команды10 минут

Ошибки

СтатусКодЧто означает
401INVALID_TOKENНеверный токен в URL.
404NOT_FOUNDСрок действия потока истёк, или его никогда не было.

Что дальше