⚠️ Эта страница автоматически переведена, и перевод может быть несовершенным.
blog-post

Manticore Buddy: архитектура плагинов v2

author image
View as markdown

Привет, друзья. Захватывающие новости о Manticore Buddy: мы завершили миграцию на архитектуру плагинов! Это означает, что вы можете создать собственный запрос Manticore Search SQL/JSON в виде плагина, опубликовать его на packagist.org и установить с помощью SQL-команды CREATE PLUGIN. Давайте погрузимся в архитектуру системы плагинов и простой учебник, который поможет вам начать.

Архитектура плагинов

Введение

Если вы не знакомы с Buddy, рекомендуем прочитать блоги:

которые мы опубликовали ранее.

Изначально Buddy разрабатывался на PHP, все расширения и дополнительные обработчики команд находились в одной кодовой базе. После выхода Manticore Search 6 мы получили вопросы о добавлении пользовательского функционала и поняли, что текущая система недостаточно гибка. Поэтому мы решили перейти к архитектуре плагинов.

Мы считаем, что главный принцип разработки программного обеспечения — не изобретать велосипед и сохранять простоту. В результате мы не тратили много времени на обсуждения и выбрали самый известный и популярный менеджер пакетов в мире PHP для управления системой плагинов — Packagist .

Типы плагинов

Существует три типа плагинов:

  • core — включён по умолчанию в Buddy и является частью пакета, который вы получаете при установке Manticore.
  • local — используется для разработки и отладки перед публикацией.
  • external — устанавливается с помощью команды CREATE PLUGIN.

В этом учебнике объясняется, как сначала создать local-плагин, а затем превратить его в external, позволяя любому пользователю Manticore улучшать свою конфигурацию, используя ваш плагин.

Поток запрос → ответ

Чтобы это работало, мы вынесли часто используемые компоненты Buddy и всех плагинов в новый пакет — Buddy Core . Его следует включать при разработке вашего плагина, чтобы упростить работу в IDE и поддерживать подсказки и автодополнение.

Код, который позволяет Buddy работать как демон и выполнять внутренние задачи, включая соединение Core и исходного кода плагина, называется Buddy Base. Это приложение на ReactPHP, которое также использует Buddy Core и содержит базовую логику, обеспечивающую работу системы и поиск нужного плагина для запуска по команде.

Для более ясного понимания процесса представляем диаграмму, иллюстрирующую поток Request → Response:

Путь от запроса до ответа в Manticore Buddy

Учебник

Чтобы упростить вам задачу и погрузиться в разработку собственного плагина, давайте рассмотрим, как создать простой плагин для Buddy, поддерживающий команду SHOW HOSTNAME и возвращающий имя текущего хоста машины. Это поможет вам понять процесс, который следует соблюдать при создании собственного плагина, и также представляет собой чрезвычайно простой пример для начала. Если мы посмотрим, как работает SHOW HOSTNAME в Manticore Search до реализации логики, мы можем ожидать такой результат:

mysql> SHOW HOSTNAME;
ERROR 1064 (42000): sphinxql: syntax error, unexpected identifier, expecting VARIABLES near 'HOSTNAME'

Подготовка

Первое, что нам нужно сделать, — подготовить среду разработки. Делать это нужно только один раз, а позже можно обновлять Buddy из GIT-репозитория , чтобы получать последние обновления. Откройте терминал, клонируйте Buddy на свою машину в папку manticoresearch-buddy и перейдите в склонированные каталоги.

git clone --depth 1 https://github.com/manticoresoftware/manticoresearch-buddy.git
cd manticoresearch-buddy

Теперь у вас есть весь исходный код Buddy, но ни один из пакетов не установлен. Buddy использует Composer для управления зависимостями, и нам нужно сначала установить их, чтобы запустить приложение. Однако перед этим мы запустим специальный Docker-контейнер, подготовленный специально для разработки. Образ Manticore Executor Kit содержит все необходимые инструменты для комфортной разработки Manticore Buddy, будь то создание новых плагинов или вклад в сам Buddy.

docker pull ghcr.io/manticoresoftware/manticoresearch:test-kit-latest
docker create --privileged --entrypoint bash \
  -v $(pwd):/workdir -w /workdir --name manticore-buddy \
  --network host -it ghcr.io/manticoresoftware/manticoresearch:test-kit-latest
docker start manticore-buddy

Поздравляем! Вы запустили Docker-контейнер с Manticore Search и Manticore Executor для разработки Buddy и плагинов. Текущий рабочий каталог сопоставлен с /workdir внутри контейнера. Следующий шаг — установить зависимости Composer. Помните, что эта и все последующие команды должны выполняться внутри контейнера manticore-buddy.

docker exec -it manticore-buddy bash
composer install

Ваш Buddy теперь готов к использованию, разработке, отладке и тестированию. Далее вам нужно выполнить два действия:

  1. Сначала отредактируйте внутри контейнера файл /etc/manticoresearch/manticore.conf и добавьте туда buddy_path с нашими исходниками. Это позволит Manticore Search понять, что нам нужно использовать пользовательский путь к Buddy из исходников, а не из установленных модулей. Добавьте это в раздел searchd:
    buddy_path = manticore-executor /workdir/src/main.php --debug
    
  2. Затем попробуйте запустить searchd (сервер Manticore Search) и убедитесь, что он работает.
    # Launch daemon inside the container and keep it foreground
    searchd --nodetach
    
    Вы должны увидеть несколько строк, начинающихся с [BUDDY].

На данном этапе всё готово для подготовки среды разработки Buddy и начала реализации нового плагина. Вы всё ещё можете экспериментировать с ним и попытаться выполнить несколько запросов, чтобы убедиться в его корректной работе. Например, откройте другое окно терминала и выполните следующее:

$ docker exec -it manticore-buddy mysql -h0 -P9306
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 6.0.5 3bcbd00fa@230320 dev (columnar 2.0.5 8171c1a@230320) (secondary 2.0.5 8171c1a@230320) git branch HEAD (no branch)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> show queries;
+------+--------------+----------+-----------------+
| id   | query        | protocol | host            |
+------+--------------+----------+-----------------+
|   10 | select       | http     | 127.0.0.1:19148 |
|    9 | show queries | mysql    | 127.0.0.1:54484 |
+------+--------------+----------+-----------------+
2 rows in set (0.008 sec)

MySQL [(none)]>

Вы только что отправили команду SHOW QUERIES в Manticore Search, которая была перенаправлена в Buddy и успешно выполнена. Вы можете увидеть, что получил Buddy и его ответ, в журнале searchd в первой вкладке терминала. Таким образом, мы можем подтвердить, что Buddy работает корректно и всё настроено правильно.

Когда захотите остановить процесс searchd, просто нажмите Ctrl + C в первом окне/вкладке терминала.

Шаблон плагина

Мы создали специальный шаблон репозитория GitHub , который настоятельно рекомендуем использовать для создания любого плагина Manticore Buddy. Все плагины должны иметь префикс buddy-plugin-[your-name], где [your-name] — название вашего плагина. Например, поскольку мы разрабатываем плагин выбора имени хоста, назовём его buddy-plugin-show-hostname. Итак:

  1. Откройте https://github.com/manticoresoftware/buddy-plugin-template .
  2. Нажмите Use this template, а затем Create a new repository.
  3. Заполните форму названием вашего репозитория и создайте его. Убедитесь, что имя репозитория начинается с buddy-plugin-, так как это обязательно.
  4. Выполните git clone вашего нового репозитория в каталог plugins репозитория Manticore Buddy, который вы ранее развернули. Учтите, что лучше делать это вне контейнера, особенно если вы клонируете из приватного репозитория.

В https://github.com/manticoresoftware/buddy-plugin-show-hostname вы можете найти полностью реализованную задачу. Если вы не хотите вдаваться в детали, можете просто git clone его вместо вашего форка. Однако, если вы хотите освоить создание плагина, продолжим.

Добавьте реальный код

Теперь нам нужно выполнить следующие шаги и обновить наш шаблон соответствующими данными для нашего нового плагина.

  1. Сначала откройте composer.json в каталоге вашего клонированного плагина и обновите имя плагина, описание и пространства имён. В итоге ваши изменения должны выглядеть так (убедитесь, что используете имя репозитория вашего плагина):
diff --git a/composer.json b/composer.json
index 23c252b..f36cb6e 100644
--- a/composer.json
+++ b/composer.json
@@ -1,11 +1,11 @@
 {
- "name": "manticoresoftware/buddy-plugin-template",
- "description": "The Buddy template handler plugin",
+ "name": "manticoresoftware/buddy-plugin-show-hostname",
+ "description": "The Buddy SHOW hostname handler plugin",
  "type": "library",
  "license": "GPL-2.0-or-later",
  "autoload": {
    "psr-4": {
-     "Manticoresearch\\Buddy\\Plugin\\Template\\": "src/"
+     "Manticoresearch\\Buddy\\Plugin\\ShowHostname\\": "src/"
    }
  },
  "authors": [
  1. Нам также нужно обновить пространства имён двух классов в вашем плагине — Payload и Handler. Дифф должен выглядеть так:
diff --git a/src/Handler.php b/src/Handler.php
index 3756dc3..07fcfd0 100644
--- a/src/Handler.php
+++ b/src/Handler.php
@@ -8,7 +8,7 @@
   version. You should have received a copy of the GPL license along with this
   program; if you did not, you can find it at http://www.gnu.org/
 */
-namespace Manticoresearch\Buddy\Plugin\Template;
+namespace Manticoresearch\Buddy\Plugin\ShowHostname;

 use Manticoresearch\Buddy\Core\Plugin\BaseHandler;
 use Manticoresearch\Buddy\Core\Task\Task;
diff --git a/src/Payload.php b/src/Payload.php
index b170340..a35f201 100644
--- a/src/Payload.php
+++ b/src/Payload.php
@@ -8,7 +8,7 @@
   version. You should have received a copy of the GPL license along with this
   program; if you did not, you can find it at http://www.gnu.org/
 */
-namespace Manticoresearch\Buddy\Plugin\Template;
+namespace Manticoresearch\Buddy\Plugin\ShowHostname;

 use Manticoresearch\Buddy\Core\Network\Request;
 use Manticoresearch\Buddy\Core\Plugin\BasePayload;
  1. В качестве последнего шага не забудьте установить новую зависимость, запустив composer install внутри контейнера (в /workdir).

Поток запросов от Manticore Search к вашему плагину и обратно

Мы готовы реализовать нашу логику. Но сначала давайте немного разберёмся, как это обрабатывается внутри.

Путь запроса к плагину в Manticore Buddy

Предположим, мы отправляем запрос SHOW HOSTNAME запущенному процессу searchd с помощью MySQL-клиента. Manticore Search не может обработать его и передаёт Buddy, ожидая ответ. Buddy может вернуть точный ответ, который просто будет проксирован обратно к MySQL-клиенту.

Как только Buddy получает запрос от Manticore Search, он разбирает его и проводит проверку во всех плагинах: сначала в основных плагинах, затем во внешних. Для выполнения этой проверки он вызывает метод Payload::hasMatch($request), передавая ему запрос, который содержит сам запрос и некоторые метаданные, такие как запрашиваемый эндпоинт, тип (JSON или SQL) и т.д.

Payload представляет структуру, содержащую все необходимые данные для обработки команды. Если Payload плагина возвращает true в методе hasMatch, это означает, что мы будем использовать этот плагин для обработки запроса. Он создаётся из Request, и на этом этапе нам нужно разобрать запрос, извлечь полезную информацию и записать её в данные payload, которые будут переданы Handler.

Handler — это класс, который фактически исполняет реализованную команду. Он делает это в потоковой среде, используя расширение parallel, не блокируя основной цикл сервера. Есть простой метод run, который создаёт замыкание, которое должно выполнить задачу и вернуть ответ обратно в Manticore Search, который затем проксируется пользователю.

В нашем случае нам просто нужно добавить проверку поддержки синтаксиса запроса SHOW HOSTNAME, а затем написать логику Handler, вызывающую PHP-функцию gethostname и возвращающую её в качестве ответа. Вот и всё! Начнём с Payload.

Реализация Payload

Когда вы откроете src/Payload.php, вы увидите, что там есть всего два метода: fromRequest и hasMatch. Мы пометили строки, которые нужно отредактировать, комментариями TODO, поэтому будет легко найти, что требуется сделать. В нашем случае запрос очень простой и вовсе не гибкий, поэтому менять метод fromRequest не нужно. Мы можем просто удалить комментарии TODO. Нам нужно обновить статическую функцию hasMatch(). В ней необходимо реализовать проверку, что запрос строго соответствует строке SHOW HOSTNAME без учёта регистра. Если совпадение найдено, следует вернуть true. В противном случае — false. Так базовая система понимает, что должна использовать этот плагин, если получит запрос, показывающий имя хоста.

Итоговый дифф, который мы сделали в Payload, должен выглядеть так:

diff --git a/src/Payload.php b/src/Payload.php
index a35f201..bd0795e 100644
--- a/src/Payload.php
+++ b/src/Payload.php
@@ -26,7 +26,6 @@ final class Payload extends BasePayload {
   */
  public static function fromRequest(Request $request): static {
    $self = new static();
-   // TODO: add logic of parsing request into payload here
    // We just need to do something, but actually its' just for PHPstan
    $self->path = $request->path;
    return $self;
@@ -37,7 +36,6 @@ final class Payload extends BasePayload {
   * @return bool
   */
  public static function hasMatch(Request $request): bool {
-   // TODO: validate $request->payload and return true, if your plugin should handle it
-   return $request->payload === 'template';
+   return stripos($request->payload, 'show hostname') !== false;
  }
 }

Мы завершили изменения в Payload и можем перейти к Handler для реализации реальной логики.

Реализация Handler

Теперь откройте src/Handler.php и изучите пометки TODO, а также краткое описание происходящего. Нам нужно перейти к методу run и обновить его.

Мы видим замыкание, которое возвращает TaskResult — специальный тип результата, оборачивающий стандартный JSON-ответ.

Мы включим вызов gethostname() и подготовим ответ, обернув его в TaskResult, который будет возвращён клиенту. Итоговый дифф будет выглядеть следующим образом:

diff --git a/src/Handler.php b/src/Handler.php
index 07fcfd0..944899b 100644
--- a/src/Handler.php
+++ b/src/Handler.php
@@ -11,6 +11,7 @@
 namespace Manticoresearch\Buddy\Plugin\ShowHostname;

 use Manticoresearch\Buddy\Core\Plugin\BaseHandler;
+use Manticoresearch\Buddy\Core\Task\Column;
 use Manticoresearch\Buddy\Core\Task\Task;
 use Manticoresearch\Buddy\Core\Task\TaskResult;
 use RuntimeException;
@@ -33,9 +34,11 @@ final class Handler extends BaseHandler {
   * @throws RuntimeException
   */
  public function run(): Task {
-   // TODO: your logic goes into closure and should return TaskResult as response
    $taskFn = static function (): TaskResult {
-     return TaskResult::none();
+     $hostname = gethostname();
+     return TaskResult::withRow([
+       'hostname' => $hostname,
+     ])->column('hostname', Column::String);
    };

    return Task::create(

Разработка и отладка плагина

Теперь, когда вы завершили реализацию, пришло время протестировать и отладить (при необходимости) ваш плагин. Существует специальный тип плагина под названием local, предназначенный именно для этой цели. Поскольку ваш плагин уже находится в каталоге plugins, он автоматически становится local плагином. Чтобы использовать его, просто:

  1. В корневом каталоге Buddy выполните команду composer require [your-plugin-name]:dev-main, чтобы подключить плагин. your-plugin-name — это имя из composer.json вашего плагина, которое вы редактировали ранее.
  2. Перезапустите searchd, чтобы убедиться, что код обновлён.

Этот метод позволяет разрабатывать, отлаживать, редактировать и тестировать ваш плагин в реальном времени без необходимости отправлять его в Git-репозиторий и публиковать на packagist.org .

Публикация и установка

Когда вы закончите отладку и будете готовы опубликовать свой плагин, просто зафиксируйте изменения в репозитории Git и опубликуйте пакет на packagist.org .

Затем проверьте, что всё работает как ожидается, выполнив команду CREATE PLUGIN [your-plugin-name] TYPE 'buddy' VERSION 'dev-main', которая попытается загрузить плагин с помощью Composer и установить его в plugin_dir.

Вот так:

$ docker exec -it manticore-buddy mysql -h0 -P9306
MySQL [(none)]> CREATE PLUGIN manticoresoftware/buddy-plugin-show-hostname type 'buddy' VERSION 'dev-main';

Query OK, 0 rows affected (1 min 12.213 sec)

MySQL [(none)]> show hostname;
+----------+
| hostname |
+----------+
| dev      |
+----------+
1 row in set (0.011 sec)

MySQL [(none)]>

Поздравляем! Ваш плагин работает исправно и позволяет получить имя хоста, используя запрос SHOW hostname.

Заключение

Надеемся, вам понравилась эта статья и вы получили более глубокое понимание новой подключаемой архитектуры Buddy, доступной начиная с версии Manticore 6.0.4. Вы можете сразу приступить к разработке своего плагина, следуя предоставленным инструкциям. Хотя это базовое введение в подключаемую систему, мы планируем создать и опубликовать более продвинутую статью о разработке сложного плагина. Не стесняйтесь задавать нам вопросы в наших чатах Slack или Telegram , а также предлагать темы для руководства по сложному плагину.

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

С уважением,
Команда Manticore.

Установить Manticore Search

Установите Manticore Search одной командой в Linux или macOS:

curl https://manticoresearch.com | sh

Для расширенных вариантов установки см. полное руководство по установке и документацию .

Установить Manticore Search