Skip to content

CreatingBackend RU

ameharoo edited this page Aug 15, 2024 · 2 revisions

Реализация своего бекенда

EN RU

Актуально с версии 1.0.0

💅 В этой статье будет описан алгоритм реализации своего бекенда для Mess на примере реализации "MyLangBackend" - бекенда для "MyLang"

---
title: Связи между компонентами бекенда
---
graph TD;
    backend.py:MyLangBackend-- Создание сообщения ---> mylang.py{{Сообщение реализовано в messages/mylang.py}}
    backend.py:MyLangBackend-- Рендеринг сообщения ---> mylang.py
    mylang.py --> |Да| messages/mylang.py
    mylang.py --> |Нет| messages/base.py
    messages/base.py-- Рендеринг сообщения --> d(NotImplementedException)
    messages/mylang.py-- Манглинг-->backend.py:MyLangBackend;
    messages/mylang.py-- Рендеринг сообщения -->templates/mylang/*.j2;
    templates/mylang/*.j2-- Получение информации о сообщении -->messages/mylang.py;
    
Loading

1. Реализация MyLangBackend - главного класса, описания бекенда

Наш класс бекенда, унаследоваемый от Backend, необходимо обьявить в backend.py, ниже всех обьявленных до него. Это необходимо для правильной работы автоматического поиска реализованных бекендов.

💁 На данный момент (версия 1.0.0), поиск бекендов происходит в mess.py, в последующих версиях это будет изменено и вынесено в отдельный файл

Итак, добавим этот код в конец файла backend.py:

class MyLangBackend(Backend):
    # Код бекенда
    name = "mylang"
    # Название директории с шаблонами
    path_to_templates = "mylang/"

    def render_message(self, message:  messages_base.Message):
        return super().render_message(message)

Здесь, мы создаем класс MyLangBackend, наследуемый от Backend, и определяем значения его default values полей.

Поле name определяет адресуемое имя бекенда, которое используется при выборе бекендов, когда пользователь запускает скрипт генерации mess.py <name> <out> <in>

Поле path_to_templates указывает на местоположение файлов шаблонов бекенда. Этот путь складывается таким образом - /templates/<path_to_templates>, то есть в данном случае: /templates/mylang/

💁 В данном примере специально оставлен метод MyLangBackend::render_message, хотя в данном случае его можно упустить. Сделано это было для того, чтобы показать, что здесь есть возможность переопределить дальнейший алгоритм, вместо стандартного (см. граф выше).

🙌 Полное описание базового класса Backend можно посмотреть тут, либо в файле Backend.py

2. Реализация всех сообщений для MyLangBackend

Бекенд создает экземпляры необходимых сообщений, встроенных, затем пользовательских (с ini файла). Для создания он использует, либо реализацию сообщения из messages/base.py, либо, если такое есть, из messages/mylang.py.

💁 Сделано это было для того, чтобы при добавлении в base.py нового сообщения, пока нет реализации этого сообщения у текущего бекенда, и оно используется в описании у пользователя , происходил выброс исключения NotImplementedException, которое позволяет сразу выявить такое сообщение.

В директории /messages/ необходимо создать mylang.py, в котором реализовать все сообщения из base.py, главное здесь - переопределить метод base.Message::render и base.Message::get_render_template, именно в них происходит выброс исключения.

🙌 Посмотреть список всех встроенных сообщений, зарегистрированных в Mess, можно тут или в файле messages/base.py

Приведем здесь пример одного такого сообщения (взято из imhex.py):

class Message(base.Message):
    def __init__(self, name=None, fields=None, generic_args=None, docs=None):
        super().__init__(name, fields, generic_args, docs)

    def render(self, backend: 'Backend'):
        return backend.get_template(self.get_render_template()) \
                      .render(data={'message': self, 'backend': backend})
    
    def get_render_template(self) -> str:
        return "Type.j2"

Здесь переопределяется метод mylang.Message::get_render_template, в котором происходит только возвращение имени шаблона, а также метод mylang.Message::render.

В методе mylang.Message::render получает шаблон и рендерит его, передавая data.

💁 Для реализации своего бекенда лучше скопировать base.py и реализовывать сообщения там, или же cpp.py, где уже есть работа с шаблоном.

Здесь есть большой потенциал к изменению входных параметров, это все зависит от того, что принимает шаблон.

3. Создание шаблонов для MyLangBackend

💁 Здесь начинается самое интересное! Именно тут и определяется как будет выглядеть результат рендеринга.

В директории /templates/mylang/ создаем файл Type.j2 с таким содержанием (взято из templates/imhex/Type.j2):

{% set msg = message %}
{# First simple fields (non variative), then complex, variative #}
{% set sorted_fields = msg.fields | sort(attribute="message.is_variative") %}

struct {{ msg | message_type }} {
    {% for field in sorted_fields %}
    {{ field | field_type }} {{ field | field_name }};
    {% endfor %}
};

🙌 Шаблон сильно упрощен, для лучшего понимания (например, здесь не хватает поддержки коментариев, хеширования протокола). Полные, реальные, примеры можно посмотреть в /templates/.

Данный шаблон реализует структуру с замангленным именем сообщения, используя фильтр message_type, и полями этого сообщения.

🙌 Посмотреть полный список фильтров можно тут или же в файле filters.py.


--

В конечном счете, надеюсь мне удалось хотя бы примерно обьяснить как происходит реализация своего бекенда. Эта статья и все остальные будут постепенно дополняться, чтобы сделать Mess более понятным для всех 🙆‍♀️

🙋 Если у вас есть вопросы, можно их задавать в Discussions или Issues репозитория Mess на Github. Также предложения и PR приветствуются!


Вернуться к: Главная | Реализация своего бекенда