Эта статья написана для Buddy v1.x. Проверьте обновлённую версию для последней здесь .
Привет, друзья. Захватывающие новости о Manticore Buddy: мы завершили миграцию к модульному дизайну! Это означает, что вы можете создать свой собственный запрос Manticore Search SQL/JSON в виде плагина, опубликовать его на
packagist.org
, и установить его с помощью SQL‑команды CREATE PLUGIN. Давайте погрузимся в архитектуру модульной системы и простой учебник, который поможет вам начать.
Architecture
Intro
Если вы не знакомы с Buddy, рекомендуем прочитать блоги:
которые мы опубликовали ранее.
Изначально Buddy разрабатывался на PHP, со всеми расширениями и дополнительными обработчиками команд в одной кодовой базе. После выпуска Manticore Search 6 мы получили вопросы о добавлении пользовательского функционала и поняли, что текущая система недостаточно гибка. Поэтому мы решили перейти к модульной архитектуре.
Мы считаем, что главный принцип разработки программного обеспечения — не изобретать велосипед и сохранять простоту. В результате мы не тратили много времени на обсуждения и выбрали самый известный и популярный менеджер пакетов в мире PHP для управления системой плагинов — Packagist .
Plugin Types
Существует три типа плагинов:
core— включён по умолчанию в Buddy и является частью пакета, который вы получаете при установке Manticore.local— используется для разработки и отладки перед публикацией.external— устанавливается с помощью командыCREATE PLUGIN.
В этом учебнике объясняется, как сначала создать local‑плагин, а затем превратить его в external, позволяя любому пользователю Manticore улучшать свою конфигурацию, используя ваш плагин.
Request -> response flow
Чтобы это работало, мы вынесли часто используемые компоненты Buddy и всех плагинов в новый пакет — Buddy Core . Его следует включать при разработке вашего плагина, чтобы упростить работу в IDE и поддерживать подсказки и автодополнение.
Код, который позволяет Buddy работать как демон и выполнять внутренние задачи, включая соединение Core и исходного кода плагина, называется Buddy Base. Это приложение на ReactPHP, которое также использует Buddy Core и содержит базовую логику, чтобы всё работало и находило нужный плагин для запуска по команде.
Для более ясного понимания процесса представлена диаграмма, иллюстрирующая поток Запрос → Ответ:

Tutorial
Чтобы упростить задачу и погрузиться в разработку собственного плагина, рассмотрим, как создать простой плагин для Buddy, поддерживающий команду SHOW HOSTNAME и возвращающий имя текущего хоста машины. Это поможет вам понять процесс создания собственного плагина, а также представляет собой чрезвычайно простой пример для начала. Если мы посмотрим, как SHOW HOSTNAME работает в Manticore Search до реализации логики, мы можем ожидать такой результат:
mysql> SHOW HOSTNAME;
ERROR 1064 (42000): sphinxql: syntax error, unexpected identifier, expecting VARIABLES near 'HOSTNAME'
Preparation
Первое, что нам нужно сделать, — подготовить среду разработки. Это требуется сделать только один раз, а позже можно обновлять Buddy из
GIT‑репозитория
, чтобы получать последние обновления. Откройте терминал, клонируйте Buddy в папку manticoresearch-buddy и перейдите в склонированные каталоги.
git clone https://github.com/manticoresoftware/manticoresearch-buddy.git
cd manticoresearch-buddy
git checkout v1.x
Теперь у вас есть весь исходный код Buddy, но ни один из пакетов не установлен. Buddy использует Composer для управления зависимостями, и нам нужно сначала установить их, чтобы запустить приложение. Однако перед этим мы запустим специальный Docker‑контейнер, подготовленный специально для разработки. Образ Manticore Executor Kit содержит все необходимые инструменты для комфортной разработки Manticore Buddy, будь то создание новых плагинов или участие в разработке самого Buddy.
docker pull ghcr.io/manticoresoftware/manticoresearch:test-kit-6.2.12
docker create --privileged --entrypoint bash \
-v $(pwd):/workdir -w /workdir --name manticore-buddy \
-it ghcr.io/manticoresoftware/manticoresearch:test-kit-6.2.12
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]. Чтобы остановить процесс, просто нажмите Ctrl + C.
На данном этапе всё готово для подготовки среды разработки 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 работает корректно и всё настроено правильно.
Шаблон плагина
Мы создали
специальный шаблон репозитория на GitHub
, который настоятельно рекомендуем использовать для создания любого плагина Manticore Buddy. Все плагины должны иметь префикс buddy-plugin-[your-name], где [your-name] — название вашего плагина. Например, поскольку мы разрабатываем плагин выбора имени хоста, мы назовём его buddy-plugin-show-hostname. Итак:
- Откройте https://github.com/manticoresoftware/buddy-plugin-template .
- Выберите ветку
v1.x - Нажмите
Use this templateи затемCreate a new repository. - Заполните форму названием вашего репозитория и создайте его. Убедитесь, что имя вашего репозитория начинается с
buddy-plugin-, так как это обязательно. git cloneваш новый репозиторий в каталогpluginsрепозитория Manticore Buddy, который вы ранее развернули. Обратите внимание, что лучше делать это вне контейнера, особенно если вы клонируете из приватного репозитория.
В
https://github.com/manticoresoftware/buddy-plugin-show-hostname
(ветка: v1.x) вы можете найти полностью реализованную задачу. Если вы не хотите вдаваться в детали, вы можете просто 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 будет выглядеть так:
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внутри контейнера.
Поток запросов от Manticore Search к вашему плагину и обратно
Мы готовы реализовать нашу логику. Но сначала давайте узнаем немного больше о том, как это обрабатывается внутри.

Предположим, мы отправляем запрос SHOW HOSTNAME запущенному процессу searchd с помощью MySQL‑клиента. Manticore Search не может обработать его и передаёт его Buddy, ожидая ответ. Buddy может вернуть точный ответ, который просто будет проксирован обратно к MySQL‑клиенту.
Как только Buddy получает запрос от Manticore Search, он разбирает его и проводит проверку во всех плагинах: сначала в основных плагинах, затем во внешних. Для выполнения этой проверки он вызывает метод Payload::hasMatch($request), передавая ему запрос, который содержит сам запрос и некоторые метаданные, такие как запрашиваемый endpoint, тип (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. Именно так базовая система понимает, что должна использовать этот плагин, если мы получаем запрос, который выводит имя хоста.
Итоговый diff, который мы сделали в 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 будет выглядеть следующим образом:
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(Runtime $runtime): 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::createInRuntime(
Отладка и разработка
Теперь, когда вы завершили реализацию, пришло время протестировать и отладить (при необходимости) ваш плагин. Существует специальный тип плагина под названием 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 'v1.x';
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, уже доступной в the Linux dev packages и в скором выпуске (после Manticore 6.0.4, так что если к моменту чтения этой статьи существует более новая версия, она, вероятно, уже включена). Вы можете сразу приступить к разработке вашего плагина, следуя предоставленным инструкциям. Хотя это базовое введение в подключаемую систему, мы планируем создать и опубликовать более продвинутую статью о разработке сложного плагина. Не стесняйтесь задавать нам вопросы в наших чатах Slack или Telegram , и смело предлагайте темы для руководства по сложному плагину.
Помните, что также стоит взглянуть на наш core plugin's code , чтобы глубже разобраться и лучше понять, как он работает в более сложных случаях.
С уважением,
Команда Manticore.
