Skip to content

Latest commit

 

History

History
638 lines (446 loc) · 26.8 KB

File metadata and controls

638 lines (446 loc) · 26.8 KB

WebSocket API

en

Модуль для Apostol + db-platformApostol CRM1.

Описание

WebSocket API предоставляет возможность подключения к API системы по протоколу WebSocket. Реализует лёгкий RPC-протокол поверх WebSocket в формате JSON, систему подписки на события (паттерн «Наблюдатель») и REST-эндпоинт для отправки данных подключённым клиентам.

Модуль базы данных

WebSocketAPI тесно связан с модулями observer, notification, notice, message и log платформы db-platform.

C++ модуль отвечает за WebSocket-транспорт и маршрутизацию сессий. Всё состояние подписок, реестр издателей и данные событий находятся исключительно в базе данных:

Модуль db-platform Назначение
observer Реестр издателей и подписчиков: хранит издателей (observer.publisher) и активные подписки-слушатели (observer.listener) по сессиям
notification Источник событий издателя notify — срабатывает при каждом взаимодействии пользователя с объектом системы (создание/обновление/удаление/переход)
notice Источник событий издателя notice — системные извещения, сгруппированные по категориям
message Источник событий издателя message — входящие и исходящие сообщения из сущности message
log Источник событий издателя log — записи журнала событий (M/W/E/D)

Ключевые объекты базы данных:

Объект Назначение
observer.publisher Зарегистрированные издатели (notify, notice, message, log, geo)
observer.listener Активные подписки: сессия → издатель с фильтром и параметрами
api.observer_subscribe(publisher, filter, params) Создаёт или обновляет слушателя для текущей сессии
api.observer_unsubscribe(publisher) Удаляет слушателя для текущей сессии
api.observer_publisher(code) Возвращает метаданные издателя
api.observer_listener(publisher, session) Возвращает состояние слушателя для сессии

Настройка

[module/WebSocketAPI]
enable=true

Установка

Следуйте указаниям по сборке и установке Апостол.

Запрос клиента

Чтобы установить с сервером соединение WebSocket, клиентское приложение должно выполнить «Рукопожатие» («Opening Handshake»), как описано в RFC 6455, раздел 4.

Сервер накладывает дополнительные ограничения на URL-адрес WebSocket, подробно описанные ниже.

URL подключения

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

URL подключения содержит код сессии и идентификатор сеанса связи.

Формат URL подключения:

ws[s]://[ws.]example.com/session/<code>[/<identity>]

Где:

  • <code>Обязательный. Код сессии (40 символов).
  • <identity>Необязательный. Идентификатор сеанса связи в рамках сессии. Используется для установки нескольких соединений к одной сессии.

Примеры:

wss://ws.example.com/session/c83b2f85321f95341707624546ca6ac4fa6d1115
wss://ws.example.com/session/c83b2f85321f95341707624546ca6ac4fa6d1115/user1

RPC-протокол

Протокол WebSocket сам по себе не даёт возможности отправлять сообщения в режиме запрос/ответ. Чтобы обеспечить эту возможность, был создан небольшой RPC-протокол поверх WebSocket в формате JSON.

Описание JSON-ключей

Ключ Расшифровка Тип данных Назначение, примечания
t MessageTypeId INTEGER Тип сообщения (описание ниже).
u UniqueId UUID Уникальный идентификатор сообщения. Если сообщение от сервера является ответом на запрос от клиента, UniqueId будет одинаковым.
a Action STRING Действие (маршрут к конечной точке API).
c ErrorCode INTEGER Код ошибки.
m ErrorMessage STRING Сообщение об ошибке.
p Payload JSON Полезная нагрузка.

Тип сообщения (MessageTypeId)

Тип сообщения Номер Направление Описание
OPEN 0 Клиент → Сервер Авторизация. Открытие ранее созданной сессии.
CLOSE 1 Клиент → Сервер Закрытие сессии (выход из системы).
CALL 2 Клиент ↔ Сервер Запрос или серверная инициатива.
CALLRESULT 3 Сервер → Клиент Ответ на запрос.
CALLERROR 4 Сервер → Клиент Ответ на запрос с ошибкой.

Авторизация

После подключения клиенту необходимо авторизоваться перед отправкой API-запросов.

Авторизация может быть выполнена в автоматическом режиме при условии, если в момент установки связи были указаны соответствующие HTTP-заголовки:

Authorization: Bearer <token>

Или:

Session: <session>
Secret: <secret>

Если заполнение HTTP-заголовков блокируется используемым клиентским фреймворком, авторизация выполняется путём отправки пакета OPEN с данными авторизации, выданными сервером авторизации: маркером доступа (token) или секретным кодом сессии (secret).

После успешной авторизации можно отправлять API-запросы с типом сообщения CALL. Маршрут к конечной точке API указывается в ключе Action (a), JSON-тело запроса — в ключе Payload (p).

Попытка отправить запрос до выполнения успешной авторизации приведёт к ответу с типом CALLERROR.

Пример — код сессии не найден или сессия закрыта:

{"t":4,"u":"<uuid>","c":400,"m":"Код сессии не найден."}

Авторизация по секретному коду сессии

Запрос:

{"t":0,"u":"<uuid>","p":{"secret": "MWCJ14k/RJyiHskQB8DoVbliiwDeNGKsgsAMugp3OZt+M0Zj44hDykwRuFoWEwuG"}}

Положительный ответ:

{"t":3,"u":"<uuid>","p":{"authorized": true, "code": "amAJmzkxvDE+ad7KwkRtZU1qkUod+3XuycBbxRqHOOjBdeOkkR+lSExI4L8LAcb+", "message": "Успешно."}}

Где code — новый код авторизации для получения маркера доступа (не путать с секретным кодом сессии).

Отрицательный ответ:

{"t":4,"u":"<uuid>","c":401,"m":"Выход из системы. Секретный код сессии не прошёл проверку."}

ВНИМАНИЕ: При передаче неверных данных авторизации сессия будет закрыта, но не соединение.

Авторизация по маркеру доступа

Запрос:

{"t":0,"u":"<uuid>","p":{"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiIDogImFjY291bnRzLnBsdWdtZS5ydSIsICJhdWQiIDogInNlcnZpY2UtcGx1Z21lLnJ1IiwgInN1YiIgOiAiYzgzYjJmODUzMjFmOTUzNDE3MDc2MjQ1NDZjYTZhYzRmYTZkMTExNSIsICJpYXQiIDogMTYwNjIxMDcwNiwgImV4cCIgOiAxNjA2MjE0MzA2fQ.ZI82FKXAgA1CZm3gx9XCpgpq_WyZJvwqYI4nOdccVts"}}

ВНИМАНИЕ: Маркер доступа имеет ограниченный срок жизни.

Положительный ответ:

{"t":3,"u":"<uuid>","p":{"authorized": true, "message": "Успешно."}}

Отрицательный ответ:

{"t":4,"u":"<uuid>","c":403,"m":"Verification failed: Token expired."}

Передача данных

Предусмотрена возможность отправки произвольных данных клиентскому приложению, подключённому по WebSocket.

Для этого нужно отправить на сервер REST API запрос:

POST /ws/<code>[/<identity>]

<anydata>

Где:

  • <code>Обязательный. Код сессии WebSocket-соединения, на которое необходимо передать данные.
  • <identity>Необязательный. Идентификатор сеанса связи в рамках сессии (при наличии).
  • <anydata>Необязательный. Любые данные в произвольном формате.

Данные будут отправлены запросом с типом сообщения CALL: в Action будет указано значение /ws, в Payload — произвольные данные из REST API запроса.

Пример запроса:

POST /ws/8c98085f34c83a0eea5f40791218fbf80f1858d3 HTTP/1.1
Host: localhost:8080
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.[...].9GI82ffkIhbUeWR8if3a8q78nfXAL4AFOMp3kWDTHOA
Content-Type: application/json

{"anydata":null}

Положительный ответ:

{"sent": true, "status": "Success"}

Отрицательный ответ:

{"sent": false, "status": "Session not found"}

Подписка на события

Для того чтобы получать данные от сервера без предварительных запросов со стороны клиентского приложения, нужно подписаться на события.

Для подписки необходимо выбрать издателя и настроить слушателя (установить фильтр и параметры).

Издатели

Уведомления (notify)

Издатель notify предоставляет возможность подписаться на системные события, которые возникают каждый раз, когда пользователь системы взаимодействует с тем или иным объектом.

Фильтр

{
  "entities": ["<код>", ...],
  "classes":  ["<код>", ...],
  "actions":  ["<код>", ...],
  "methods":  ["<код>", ...],
  "objects":  [<id>, ...]
}
Поле Тип Описание
entities JSON array Необязательный. Сущность. Массив кодов.
classes JSON array Необязательный. Класс. Массив кодов.
actions JSON array Необязательный. Действие. Массив кодов.
methods JSON array Необязательный. Метод. Массив кодов.
objects JSON array Необязательный. Объекты. Массив идентификаторов.

ВАЖНО: Фильтр по полям работает по условию И, по значениям в поле — по условию ИЛИ. Поля, в которых не заданы значения, игнорируются.

Параметры

{
  "type": "notify | object | mixed | hook",
  "hook": { ... }
}
Поле Тип Значение Описание
type STRING notify, object, mixed, hook Необязательный. Тип ответа.
hook JSON Hook Обязательный для типа hook. Ловушка.
  • notify — в ответ будут приходить сами уведомления.
  • object — в ответ будут приходить данные объекта в формате /get запроса.
  • mixed — в ответ будут приходить и уведомления, и данные объекта.
  • hook — ответом будет результат выполнения API-запроса из hook.

Hook (Ловушка)

Ловушка задаёт параметры выполнения запроса API. При каждом срабатывании условий подписки ответом будут данные из запроса ловушки.

{
  "method": "POST | GET",
  "path":   "<путь>",
  "payload": { ... }
}
Поле Тип Описание
method STRING Необязательный. HTTP-метод (POST или GET).
path STRING Обязательный. REST API путь к конечной точке.
payload JSON Вариативный. Полезная нагрузка. Зависит от запроса.

Извещения (notice)

Издатель notice предоставляет возможность подписаться на системные извещения.

Фильтр

{
  "categories": ["<код>", ...]
}
Поле Тип Описание
categories JSON array Необязательный. Категория. Массив кодов.

Параметры

{
  "type": "notify"
}
Поле Тип Описание
type STRING Необязательный. Тип ответа. В настоящий момент — notify.

Сообщения (message)

Издатель message предоставляет возможность подписаться на входящие и исходящие сообщения.

Фильтр

{
  "classes":   ["inbox", "outbox"],
  "types":     ["<код>", ...],
  "agents":    ["<код>", ...],
  "codes":     ["<код>", ...],
  "profiles":  ["<значение>", ...],
  "addresses": ["<значение>", ...],
  "subjects":  ["<значение>", ...]
}
Поле Тип Описание
classes JSON array Необязательный. Класс сообщения: inbox (входящее) или outbox (исходящее).
types JSON array Необязательный. Код типа агента.
agents JSON array Необязательный. Код агента.
codes JSON array Необязательный. Код сообщения.
profiles JSON array Необязательный. Профиль настроек или адрес отправителя.
addresses JSON array Необязательный. Адрес получателя. Для API запросов — это маршрут REST API.
subjects JSON array Необязательный. Тема сообщения.

Параметры

{
  "type": "notify"
}
Поле Тип Описание
type STRING Необязательный. Тип ответа. В настоящий момент — notify.

Журнал событий (log)

Издатель log предоставляет возможность подписаться на журнал событий.

Фильтр

{
  "types":      ["M", "W", "E", "D"],
  "codes":      [<число>, ...],
  "categories": ["<код>", ...]
}
Поле Тип Описание
types JSON array Необязательный. Тип записи: M (Message), W (Warning), E (Error), D (Debug).
codes JSON array Необязательный. Числовой код записи.
categories JSON array Необязательный. Категория.

Параметры

{
  "type": "notify"
}
Поле Тип Описание
type STRING Необязательный. Тип ответа. В настоящий момент — notify.

Геолокация (geo)

Издатель geo предоставляет возможность подписаться на поступающие данные геолокации.

Фильтр

{
  "codes":   ["<код>", ...],
  "objects": [<id>, ...]
}
Поле Тип Описание
codes JSON array Необязательный. Коды групп координат (мест положений). По умолчанию default.
objects JSON array Необязательный. Объекты. Массив идентификаторов.

Параметры

{
  "type": "notify"
}
Поле Тип Описание
type STRING Необязательный. Тип ответа. В настоящий момент — notify.

Наблюдатель (observer)

Подписаться

POST /api/v1/observer/subscribe

Подписаться на события издателя.

Параметры запроса:

Поле Тип Значение Описание
publisher STRING notify, notice, message, log, geo Обязательный. Код издателя.
filter JSON Необязательный. Фильтр отбора событий издателя.
params JSON Необязательный. Параметры слушателя.

Примеры:

Подписаться на все события издателя notify:

{"t":2,"u":"<uuid>","a":"/observer/subscribe","p":{"publisher":"notify"}}

Подписаться на события издателя notify с фильтром (классы: client, device) и типом ответа object:

{"t":2,"u":"<uuid>","a":"/observer/subscribe","p":{"publisher":"notify","filter":{"classes":["client","device"]},"params":{"type":"object"}}}

Подписаться на все входящие сообщения:

{"t":2,"u":"observer","a":"/observer/subscribe","p":{"publisher":"notify","filter":{"entities":["message"],"classes":["inbox"],"actions":["create"]},"params":{"type":"object"}}}

Отловить создание нового клиента и получить данные в виде списка клиентов:

{"t":2,"u":"<uuid>","a":"/observer/subscribe","p":{"publisher":"notify","filter":{"classes":["client"],"actions":["create"]},"params":{"type":"hook","hook":{"path":"/api/v1/client/list","payload":{}}}}}

Отписаться

POST /api/v1/observer/unsubscribe

Отписаться от событий издателя.

Параметры запроса:

Поле Тип Значение Описание
publisher STRING notify, notice, message, log, geo Обязательный. Код издателя.

Пример:

{"t":2,"u":"<uuid>","a":"/observer/unsubscribe","p":{"publisher":"notify"}}

Издатель (publisher)

Получить данные издателя

POST /api/v1/observer/publisher

Параметры запроса:

Поле Тип Значение Описание
code STRING notify, notice, message, log, geo Обязательный. Код издателя.
fields JSON array Необязательный. Массив имён полей для возврата. Если не указано — возвращаются все поля.

Данные издателя по коду

POST /api/v1/observer/publisher/get

Параметры запроса:

Поле Тип Значение Описание
code STRING notify, notice, message, log, geo Обязательный. Код издателя.
fields JSON array Необязательный. Массив имён полей для возврата. Если не указано — возвращаются все поля.

Количество издателей

POST /api/v1/observer/publisher/count

Параметры запроса: Общие параметры запроса для списка

Список издателей

POST /api/v1/observer/publisher/list

Параметры запроса: Общие параметры запроса для списка

Слушатель (listener)

Получить данные слушателя

POST /api/v1/observer/listener

Параметры запроса:

Поле Тип Значение Описание
publisher STRING notify, notice, message, log, geo Обязательный. Код издателя.
session STRING Необязательный. Код сессии.
fields JSON array Необязательный. Массив имён полей для возврата. Если не указано — возвращаются все поля.

Установить слушателя

POST /api/v1/observer/listener/set

Параметры запроса:

Поле Тип Описание
publisher STRING Обязательный. Идентификатор издателя.
session STRING Необязательный. Код сессии.
filter JSON Необязательный. Фильтр отбора событий издателя.
params JSON Необязательный. Параметры слушателя.

Данные слушателя по издателю

POST /api/v1/observer/listener/get

Параметры запроса:

Поле Тип Описание
publisher STRING Обязательный. Код издателя.
session STRING Необязательный. Код сессии.
fields JSON array Необязательный. Массив имён полей для возврата. Если не указано — возвращаются все поля.

Количество слушателей

POST /api/v1/observer/listener/count

Параметры запроса: Общие параметры запроса для списка

Список слушателей

POST /api/v1/observer/listener/list

Параметры запроса: Общие параметры запроса для списка

Примеры

Запрос "Кто я":

{"t":2,"u":"<uuid>","a":"/whoami"}

Запрос сущностей:

{"t":2,"u":"<uuid>","a":"/entity","p":{"fields":["id","code","name"]}}

Запрос классов:

{"t":2,"u":"<uuid>","a":"/class","p":{"fields":["id","entity","entitycode","entityname","code","label"]}}

Запрос действий:

{"t":2,"u":"<uuid>","a":"/action","p":{"fields":["id","code","name"]}}

Запрос методов:

{"t":2,"u":"<uuid>","a":"/method","p":{"fields":["id","class","classcode","classlabel","action","actioncode","actionname","code","label"]}}

Footnotes

  1. Apostol CRM — абстрактный термин, а не самостоятельный продукт. Он обозначает любой проект, в котором совместно используются фреймворк Apostol (C++) и db-platform через специально разработанные модули и процессы. Каждый фреймворк можно использовать независимо; вместе они образуют полноценную backend-платформу.