Привет, друзья. Захватывающие новости о 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:

Учебник
Чтобы упростить вам задачу и погрузиться в разработку собственного плагина, давайте рассмотрим, как создать простой плагин для 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 теперь готов к использованию, разработке, отладке и тестированию. Далее вам нужно выполнить два действия:
- Сначала отредактируйте внутри контейнера файл
/etc/manticoresearch/manticore.confи добавьте тудаbuddy_pathс нашими исходниками. Это позволит Manticore Search понять, что нам нужно использовать пользовательский путь к Buddy из исходников, а не из установленных модулей. Добавьте это в разделsearchd:buddy_path = manticore-executor /workdir/src/main.php --debug - Затем попробуйте запустить
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. Итак:
- Откройте https://github.com/manticoresoftware/buddy-plugin-template .
- Нажмите
Use this template, а затемCreate a new repository. - Заполните форму названием вашего репозитория и создайте его. Убедитесь, что имя репозитория начинается с
buddy-plugin-, так как это обязательно. - Выполните
git cloneвашего нового репозитория в каталогpluginsрепозитория Manticore Buddy, который вы ранее развернули. Учтите, что лучше делать это вне контейнера, особенно если вы клонируете из приватного репозитория.
В
https://github.com/manticoresoftware/buddy-plugin-show-hostname
вы можете найти полностью реализованную задачу. Если вы не хотите вдаваться в детали, можете просто git clone его вместо вашего форка. Однако, если вы хотите освоить создание плагина, продолжим.
Добавьте реальный код
Теперь нам нужно выполнить следующие шаги и обновить наш шаблон соответствующими данными для нашего нового плагина.
- Сначала откройте
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": [
- Нам также нужно обновить пространства имён двух классов в вашем плагине —
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;
- В качестве последнего шага не забудьте установить новую зависимость, запустив
composer installвнутри контейнера (в/workdir).
Поток запросов от Manticore Search к вашему плагину и обратно
Мы готовы реализовать нашу логику. Но сначала давайте немного разберёмся, как это обрабатывается внутри.

Предположим, мы отправляем запрос 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 плагином. Чтобы использовать его, просто:
- В корневом каталоге Buddy выполните команду
composer require [your-plugin-name]:dev-main, чтобы подключить плагин.your-plugin-name— это имя изcomposer.jsonвашего плагина, которое вы редактировали ранее. - Перезапустите
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 по ссылке built-in plugin code , чтобы лучше понять, как он работает в более сложных сценариях.
С уважением,
Команда Manticore.
