instrumentisto/medea

Dynamic control API exposed via gRPC

Closed this issue · 0 comments

Part of 0.2.0 Roadmap (#27)

Background

У medea предусмотренно динамическое Control API. На данный момент есть имплементация только статичекого Control API.

Problem to solve

Требуется разработать gRPC интерфейс для динамического обновления Control API спеки. На данном этапе нужно реализовать методы Create, Delete, Get. Метод Apply не является частью этой issue и будет реализован позже.

Possible solution

Выбор крейта для реализации gRPC сервера

На данный момент существует только два относительно популярных и живых крейта для реализации gRPC. Это grpc и grpcio, поэтому выбор можно ограничить ими двумя.

grpc

Плюсы:

  1. полностью написан на Расте
  2. не требует внешних зависимостей

Минусы:

  1. довольно скудная документация
  2. проблемы с производительностью

grpcio

Плюсы:

  1. достаточно полная документация
  2. хорошая производительность
  3. обертка над официальной библиотекой gRPC следовательно есть надежда на бОльшую проработанность

Минусы:

  1. это обертка над библиотекой написанной на C++, и там возможны segfault'ы и прочие радости C/C++
  2. есть внешние зависимости в виде go (в случае если мы используем secure feature)

Тут все довольно неоднозначно, но все же grpcio выглядит более симпатично из-за лучшей документации и производительности. Но вообще крейт можно будет, скорее всего, в любой момент сменить без сильной боли, поскольку для десериализации обоими крейтами используется rust-protobuf, а взаимодействие с самим сервером выглядит достаточно тривиально. Также в процессе реализации при надобности можно будет использовать абстракции в виде trait'ов, чтобы легко переехать на другой крейт в случае необходимости.

Интеграция с уже существующей реализацией Control API

Для начала требуется сделать абстракции над источником данных. На данный момент в статическом Control API используются структуры десериализуемые с помощью serde в случае с gRPC десериализация с помощью них не возможна, поэтому принято решение сделать trait'ы для всех необходимых на данный момент элементов, написать реализацию для уже существующих serde DTO и для gRPC DTO. Тут уже всплывает проблема, которая заключается в том, что DTO для grpcio генерируются автоматически и не очень хотелось бы дописывать что-то в автоматически сгенерированные файлы. Как вариант, конечно, не использовать build.rs, а генерировать DTO'шки с помощью protoc, но проблему пересборки protobuf спек с последующей перезаписью это не решает.
UPD: Все же было выбрано решение с реализацией TryFrom для уже существующих элементов Control API, так как это позоволяет удобно прокидывать и обрабатывать ошибки в спеках.

Абстракции над элементами Control API

Это устаревший блок, поскольку была выбрана реализация с помощью TryFrom.
Room:

trait RoomSpec {
    fn members(&self) -> HashMap<MemberId, Box<dyn MemberSpec>>;

    fn id(&self) -> RoomId;
}

Member:

trait MemberSpec {
    fn webrtc_play_endpoints(&self) -> HashMap<WebRtcPlayId, Box<dyn WebRtcPlayEndpoint>>;

    fn webrtc_publish_endpoints(&self) -> HashMap<WebRtcPublishId, Box<dyn WebRtcPublishEndpoint>>;

    fn credentials(&self) -> String;

    fn id(&self) -> MemberId;

    fn get_webrtc_play_by_id(&self, id: WebRtcPlayId) -> Option<Box<dyn WebRtcPlayEndpoint>>;

    fn get_webrtc_publish_by_id(&self, id: WebRtcPublishId) -> Option<Box<dyn WebRtcPublishEndpoint>>;
}

WebRtcPlayEndpoint:

trait WebRtcPlayEndpoint {
    fn src(&self) -> SrcUri;
}

WebRtcPublishEndpoint:

trait WebRtcPublishEndpoint {
    fn p2p(&self) -> P2pMode;
}