Skip to main content

Как подключиться к раунду

Подключиться к раунду можно с помощью webSocket по API /ws/rounds/{id} по ID раунда.
При первом подключении, необходимо сразу отправить json объект с access_token юзера в параметре token.
Пример:
final wsUrl = Uri.parse('ws://api-dev.monyfix.tech/ws/rounds/$roundId');
    
// Создаем подключение
_channel = WebSocketChannel.connect(wsUrl);

// Отправляем токен сразу после подключения
_channel?.sink.add(jsonEncode({
  'type': 'token',
  'token': 'user jwt token'
}));
Если токен не передан, сервер вернет ошибку и завершит websocket соединение
{
  "type": "error.auth",
  "message": "Token not provided"
}
Если передан некорректный токен, сервер вернет ошибку и завершит websocket соединение
{
  "type": "error.auth",
  "message": "Invalid authentication data format"
}
Если передан корректный токен, но юзера в него не приглашали, сервер вернет ошибку и закроет websocket соединение
{
  "type": "error.round",
  "message": "Round access error"
}
Если передан корректный токен, сервер отправит ивент participant_connected и participant_update

// participant_connected

{
  "type": "participant_connected",
  "message": "Participant connected",
  "user_id": "user_id"
}

// participant_update

{
  "type": "participant_update",
  "message": "Participants updated",
  "participants": [
    {
      "id": "user_id",
      "phone": "user_phone",
      "status": "user_status",
      "name": "{first_name} {last_name}"
    }] // Participants List
}
В любом другом случае, сервер вернет
{
  "type": "error.auth",
  "message": "HTTPException.detail"
}

Статусы и ивенты

Статусы раундов и участников

Основные ивенты

Как отправлять ивенты на сервер

Каждая отправка ивента с клиента сопровождается json сообщением с type ивента и параметрами data с token и другими.
{
  "type": "participant_update|participant_answered", // тип события
  "data": {
    "token": "user access token",
    "status": "READY | NOT_READY", // для смены статуса
    "answer": "answer_id" // для ответа на вопрос
  }
}

Как принимать ивенты с сервера

Каждая отправка ивента с сервера сопровождается json сообщением с type и message.
{
  "type": "participant_update|participant_disconnected...", // тип события
  "message": "message" // описание
}

Ивенты, которые отправляет сервер

Participant connected

Название ивента participant_connected Отправляется при первом подключении юзера. Отправляется всем участникам. Отправляет json
{
  "type": "participant_connected",
  "message": "Participant connected",
  "user_id": "user_id"
}
и после этого отправляет ивент participant_update.

Participant disconnected

Название ивента participant_disconnected Отправляется при разрыве websocket соединения. Отправляется всем участникам, кроме текущего.
  1. Отключает юзера от webscocket
  2. Изменяет статус юзера на WAITING
  3. Отправляет ивент participant_disconnected
  4. Отправляет ивент participant_update
Отправляет json

// participant_disconnected

{
  "type": "participant_disconnected",
  "message": "Participant disconnected",
  "user_id": "user_id"
}

// participant_update

{
  "type": "participant_update",
  "message": "Participants updated",
  "participants": [
    {
      "id": "user_id",
      "phone": "user_phone",
      "status": "user_status",
      "name": "{first_name} {last_name}"
    }] // Participants List
}

Participant update

Название ивента participant_update Отправляется при изменении статуса готовности юзера, удалении или добавлении юзера из раунда. Отправляется всем участникам. Отправляет json
{
  "type": "participant_update",
  "message": "Participants updated",
  "participants": [
    {
      "id": "user_id",
      "phone": "user_phone",
      "status": "user_status",
      "name": "{first_name} {last_name}"
    }] // Participants List
}

Round countdown

Название ивента round_countdown Отправляется, когда все участники имеют статус READY, для перехода на экран таймера. Отправляется всем участникам. Отправляет json
{
  "type": "round_countdown",
  "message": "Countdown started: {countdown} seconds",
  "countdown": 60 // секунды
}

Round question

Название ивента round_question Отправляется, когда время таймера истекло, для перехода на экран вопроса. Отправляется всем участникам. Отправляет json
{
  "type": "round_question",
  "message": "Question started: {countdown_sec} seconds",
  "question_start": "dt_now.isoformat()",
  "question_end": "countdown_end.isoformat()",
  "countdown": 60, // отсчет для таймера в секундах
  "question": {
    "id": "int",
    "question_text": "str",
    "picture_url": "str",
    "question_type": "str",
    "answers": {
      "id": "int",
      "answer_text": "str",
      "is_correct": "bool"
    },
    "category": {
      "id": "int",
      "name": "str"
    }
  }
}

Round results

Название ивента round_results Отправляется, когда все участники ответили на вопрос или таймер ответа на вопрос закончился, для перехода на экран результатов. Отправляется всем участникам. Отправляет json
{
  "type": "round_results",
  "message": "Round results",
  "results": [
    {
        "id": "77eb8d8e-79ba-4871-9061-035f1321b22a", // id вопроса
        "name": "Nikolai Pavlov",
        "avatar": "mock_avatar_13.jpg",
        "answer_time": "43:25.312", // реальное время ответа строкой
        "answer_text": "Тихий", // вариант ответа текстом
        "is_correct": true,
        "total_time": 2605.312, // реальное время ответа в секундах
        "is_winner": true
    }
  ]
}

Chat history

Название ивента chat_history Отправляется, когда участник открывает чат для загрузки сообщений в ответ на ивент participant_open_chat. Отправляется только конкретному участнику. Отправляет json
{
  "type": "chat_history",
  "message": "Participant open chat",
  "messages": [
    {
      "user": {
        "id": "str",
        "name": "str",
        "avatar": "str"
      },
      "content": "str",
      "create_time": "datetime utc",
      "variant": "TEXT",
      "is_me": true // всегда true
    }
  ]
}

New message

Название ивента new_message Отправляется, когда участник отправил сообщение в чат в ответ на ивент chat_message. Отправляется всем участникам. Отправляет json
{
  "type": "new_message",
  "message": "Participant send new message",
  "messages": [
    {
      "user": {
        "id": "str",
        "name": "str",
        "avatar": "str"
      },
      "content": "str",
      "create_time": "datetime utc",
      "variant": "TEXT",
      "is_me": true // всегда true
    }
  ]
}

Ивенты, которые отправляет клиент

Participant update

Ивент, который вызывается для обновления основных данных участников, таких как: name, phone, id, status. В основном срабатывает при первом подключении каждого пользователя и при смене статуса участника на READY или NOT_READY
Во всех ивентах, сервер ожидает token юзера в data параметре
Название ивента participant_update JSON BODY
data: {
  "token": "user access token",
  "status": "READY | NOT_READY"
}
Пример
void sendMessage(String type, Map<String, dynamic> data) {
  if (_channel == null) return;
  
  final message = {
    'type': type,
    'data': data
  };
  
  _channel?.sink.add(jsonEncode(message));
}

ws.sendMessage('participant_update', {
  'token': 'user access token',
  'status': 'READY'
});

Round Countdown End

Отправляется, когда время таймера истекло. Название ивента round_countdown_end Пример
ws.sendMessage('round_countdown_end', {
  'token': 'user access token'
});

Round Question End

Отправляется, когда время таймера для ответа на вопрос истекло. Название ивента round_question_end Пример
ws.sendMessage('round_question_end', {
  'token': 'user access token'
});

Participant answered

Отправляется, когда участник ответил на вопрос в викторине.
Время ответа участника передается строго в формате mm:ss.SSS (22:45.343) с учётом времени до тысячных долей секунды.
Название ивента participant_answered JSON BODY
data: {
  "token": "user access token",
  "answer_id": "answer_id", // указывается id ответа из ранее полученного вопроса с ответами
  "response_time": "22:45.343" // время таймера в момент ответа с миллисекундами (3 символа после запятой)
}
Пример
ws.sendMessage('participant_answered', {
  'token': 'user access token',
  'answer_id': '5',
  'response_time': "22:45.343"
});
В случае, если ответ участника был последним (5 из 5), сервер пришлет ивент round_results с результатами раунда для перехода на экран результатов.

Participant open chat

Отправляется конкретному участнику, когда он открыл окно чата для получения сообщений. Название ивента participant_open_chat Пример
ws.sendMessage('participant_open_chat', {
  'token': 'user access token'
});
В ответ сервер отправит ивент chat_history с массивом сообщений:
{
  "type": "participant_open_chat",
  "message": "Participants open chat",
  "messages": [
    {
      "user": {
        "id": "str",
        "name": "str",
        "avatar": "str"
      },
      "content": "str",
      "create_time": "datetime utc",
      "variant": "TEXT",
      "is_me": true // true, если это сообщение юзера, который отправил запрос. false, если сообщение не его
    }
  ]
}

Chat message

Отправляется всем участникам, когда один из них отправляет сообщение в чат. Название ивента chat_message Пример
ws.sendMessage('chat_message', {
  'token': 'user access token',
  'content': 'user message',
  'type': 'TEXT' // пока статика, будет меняться в зависимости от типа сообщения (изображение, видео и т.д.)
});
В ответ сервер отправит ивент всем участникам new_message с массивом сообщений:
{
  "type": "new_message",
  "message": "Participant send new message",
  "messages": [
    {
      "user": {
        "id": "str",
        "name": "str",
        "avatar": "str"
      },
      "content": "str",
      "create_time": "datetime utc",
      "variant": "TEXT",
      "is_me": true // всегда true
    }
  ]
}

Коды ошибок

Сервер может отправлять ошибки в виде сообщений с типом error, а также закрывать соединения с определенными WebSocket кодами. Вот список возможных кодов и ошибок:
Код ошибкиОписаниеКогда возникает
WS_1008_POLICY_VIOLATION Политика безопасности нарушена (некорректный токен)Токен аутентификации отсутствует, неверный или не передан в нужном формате
WS_1011_INTERNAL_ERROR Внутренняя ошибка сервераВ случае непредвиденной ошибки на сервере
errorОбщие ошибкиВ случаях непредвиденной ошибки
error.roundОшибки с доступом к раундуПри подключении юзера
error.authОшибки авторизацииВ случае некорректного токена или его отсутствия
error.chatОшибки чатаВ случае отсутствия параметров content или type в ивенте chat_message