Как это устроено
Приложение — это веб-страница в рамке
Приложение ReMeet — это веб-страница на вашем https-адресе и манифест remeet.json. Во встрече ReMeet открывает страницу в изолированной рамке (iframe с sandbox). Страница не видит саму страницу встречи, cookie и токены ReMeet, аккаунт человека и видео других участников. Со встречей она говорит только через мост: сообщения JSON-RPC 2.0 через postMessage. Обе стороны проверяют, кто прислал сообщение, — конкретную рамку и её origin. Файл SDK делает это за вас; если хотите говорить напрямую, протокол описан.
┌──────────────── Встреча ReMeet (remeet.video) ─────────────────┐
│ сетка видео │ боковая панель │
│ ┌──────────────────────────┐ │ ┌─────────────────────────┐ │
│ │ сцена: your-site/stage │ │ │ панель: your-site/panel│ │
│ │ (iframe, sandbox) │ │ │ (iframe, sandbox) │ │
│ └────────────▲─────────────┘ │ └────────────▲────────────┘ │
│ └──── мост: JSON-RPC 2.0 через postMessage ───┘ │
│ только то, что разрешил человек │
└────────────────────────────────────────────────────────────────┘Где показывается приложение
| Место | Что это | Кто открывает |
|---|---|---|
panel | Боковая панель рядом с чатом. Личная: каждый участник открывает свою. | Любой: Ещё → приложение. |
stage | Общая область поверх сетки видео — для того, что смотрят вместе: доска, игра, презентация. | Любой для себя; ведущий может открыть её для всех через app.stage.open({ everyone: true }) (право stage.start). |
У приложения может быть одно место или оба. Рамка живёт, пока место открыто. Когда человек закрывает панель или сцену, рамка удаляется — храните важное в хранилище или на своём сервере либо спрашивайте текущее состояние у других копий при старте (см. ниже).
У каждого участника своя копия
Общего «сервера приложения» во встрече нет. Каждый участник, открывший приложение, запускает свою копию в своём браузере. Копии общаются через app.broadcast(): сообщение идёт по каналу реального времени самой встречи и доходит до копий вашего приложения (тот же key) у всех остальных участников, у кого оно открыто. Своя копия свои сообщения не получает.
Обычный приём для общего состояния:
const app = await ReMeet.ready();
let state = { votes: {} };
// Новая копия просит текущее состояние…
app.broadcast({ type: 'hello' });
app.on('broadcast', ({ data }) => {
// …а остальные отвечают.
if (data.type === 'hello') app.broadcast({ type: 'state', state });
if (data.type === 'state') state = data.state;
if (data.type === 'vote') state.votes[data.option] = (state.votes[data.option] || 0) + 1;
});Бета: приложение должно быть установлено у каждого
Сейчас приложение работает только у участников, которые установили его в своём аккаунте ReMeet. Те, кто не установил, и гости без аккаунта не видят общую сцену, которую открыл ведущий, и не получают сообщения broadcast. Открытие приложения для всех во встрече без отдельной установки — в планах.
Личность
Каждый участник получает id для вашего приложения: p_ и 24 шестнадцатеричных символа. Он одинаковый у одного человека во всех встречах и разный в разных приложениях. По нему нельзя узнать аккаунт человека в ReMeet. Используйте его в app.badges.set() и чтобы различать участников.
Чтобы на своём сервере доверять тому, кто на той стороне, используйте контекст-токен: подписанный JWT, который ReMeet выдаёт приложению при старте.
Права и согласие
Всё, кроме показа своего окна, — это права. Манифест перечисляет, что просит приложение; окно установки показывает это человеку простыми словами; приложение получает только то, что человек разрешил. Вызов без права завершается ошибкой 403.
Тема и язык
app.context.theme — light или dark; когда человек переключает тему, приходит событие theme, а SDK ставит data-theme на ваш <html>, так что CSS вида :root[data-theme="dark"] { … } просто работает. app.context.locale — язык человека: en, ru или ar. Для арабского поставьте на странице dir="rtl" сами.