ruvipers-plugin-system
v1.0.5
Published
`RCM` представляет собой высокоуровневый программный модуль и серверную платформу для реализации и управления системой плагинов на основе протокола WebSocket. Модуль предназначен для построения масштабируемой архитектуры взаимодействия между сервером и вн
Downloads
20
Readme
Описание
RCM представляет собой высокоуровневый программный модуль и серверную платформу для реализации и управления системой плагинов на основе протокола WebSocket. Модуль предназначен для построения масштабируемой архитектуры взаимодействия между сервером и внешними плагинами посредством типизированных событий.
Платформа обеспечивает поддержку как локальных, так и удалённых плагинов с возможностью автоматической загрузки из директории, а также динамическое подключение через Socket.IO. Важной составляющей является автоматическая установка npm-зависимостей плагинов, что упрощает сопровождение и развёртывание.
Установка
- Склонируйте репозиторий:
git clone <repo-url>
cd <repo-directory>- Установите зависимости:
npm installФункциональные возможности
- Двунаправленный обмен событиями между сервером и плагинами с гарантированной типовой безопасностью, реализованной через расширение интерфейсов
EventsFromServerиEventsFromPlugin. Это позволяет избежать ошибок интеграции и гарантировать строгий контракт взаимодействия. - Автоматическая загрузка локальных плагинов из заданной директории с соблюдением требований к структуре и наименованию.
- Поддержка подключения как локальных, так и удалённых плагинов посредством WebSocket (Socket.IO).
- Регистрация и асинхронная обработка пользовательских событий от плагинов с возможностью возврата результатов выполнения.
- Гибкая фильтрация плагинов на основе пользовательских фильтров для адресной отправки событий и управления нагрузкой.
- Управление коллекцией подключённых плагинов с возможностью получения списка, фильтрации и прямого взаимодействия с каждым плагином.
- Автоматическая установка и кеширование npm-зависимостей плагинов, что облегчает управление внешними библиотеками и модулями.
- Выбор стратегии агрегации ответов на события: получение всех результатов либо только первого успешного.
Архитектура и способы использования
Клиентская сторона: класс Plugin
Отвечает за создание экземпляра плагина с подключением к серверу по заданному WebSocket адресу, либо прямой обработки из файловой системы.
Структура плагинов
Плагины должны содержать package.json с указанием основного файла. Именование плагина всегда должно иметь суффикс *-plugin:
{
"name": "example-plugin",
"main": "index.js"
}Создание экземпляра плагина
import { Plugin } from "ruvipers-plugin-system";
const plugin = new Plugin("ws://127.0.0.1:8080");
// Либо, если этот плагин будет использоваться только оффлайн
const offlinePlugin = new Plugin();
plugin.ready(()=>{
console.log("Я работаю!");
});
export default plugin; // Обязательно должен быть экспортирован по умолчанию.Основные методы
send({ eventName, args? })— отправка события серверу с необязательными аргументами.use(eventName, handler)— регистрация обработчика события, вызываемого сервером.setFilters(filters)— установка фильтров (метаданных) для идентификации плагина на сервере.ready(callback)— регистрация события, вызываемого сервером после полной готовности плагина.
Отправка событий серверу с передачей аргументов
Для удобства и гарантии типовой безопасности при отправке событий серверу рекомендуется определить интерфейс EventsFromPlugin, где описываются все допустимые события и их параметры. Это позволяет IDE подсказывать корректные имена событий и типы аргументов, а также предотвращает ошибки на этапе компиляции.
plugin.send({ eventName: "query.setProfileName", args: "test" });
plugin.send({ eventName: "query.getAllResults" });
plugin.send({ eventName: "query.setProfileInfo", args: { userName: "test", password: "123456" } });Установка фильтров
Фильтры позволяют серверу отфильтровать необходимые плагины для последующего взаимодействия
const parameters: Record<string, string | boolean | number> = {
testFilter: "123"
};
plugin.setFilters(parameters);Обработка на сервере:
// Получение плагинов
const plugins = pluginServer.getPlugins({
testFilter: "123"
});
// Или отправка ивента всем плагинам
const result = await pluginServer.emit({
eventName: "testEvent", args: "anyArgs", returnAllResults: true, filters: {
testFilter: "123"
}
})Серверная сторона: класс PluginServer
краткое описание
Основные методы
use(eventName, handler)— регистрация асинхронного обработчика для входящих событий от плагинов.emit(options)— отправка события плагинам с возможностью получить результаты (все или первый успешный).getPlugins(filters?)— получение списка подключённых плагинов с возможностью фильтрации по параметрам.getPlugin(name)— получение конкретного плагина по имени для адресного взаимодействия.
Инициализация сервера с заданным портом:
import { PluginServer } from "ruvipers-plugin-system";
const server = new PluginServer(8080);
const offlineServerWithParameters = new PluginServer(0, {
autoStart: false, // Автоматический старт socket-сервера
disabledPlugins: [], // Список имён отключенных плагинов (package.json>name)
executionTimeout: 30, // Время ожидания выполнения запроса удалённго плагина
npmCachePath: "data/.npm_cache", // Директория хранения кеша плагинов
pluginsDataDir: "data/", // Директория хранения данных плагинов (не используется)
pluginsDir: "plugins/", // Директория с плагинами
throwOnErrors: true, // Возвращать ошибку при отсутствии данных? Если нет - будет возвращаться null
});
await offlineServerWithParameters.runServer();При создании экземпляра PluginServer можно передать объект с опциями, которые позволяют гибко настроить поведение сервера плагинов.
Регистрация обработчиков событий от плагинов:
server.use("query.getAllResults", async () => {
return ['test', 'test2'];
});
server.use("query.setProfileName", async (userName) => {
return { userName, id: "1" };
});Получение списка подключенных плагинов
const allPlugins = server.getPlugins();
const filteredPlugins = server.getPlugins({ clientId: '123' });Адресное взаимодействие с конкретным плагином
const plugin = server.getPlugin("pluginName");
await plugin?.emit({ eventName: "client.uptime" });Массовая отправка событий
Массовая отправка событий плагинам с опциями получения всех ответов или первого положительного результата, а также с применением фильтров
const allResults = await server.emit({ eventName: "client.uptime", returnAllResults: true });
for (const result of allResults){
const [r, plugin] = result; // Результат и плагин, обработавший данный результат
}При следующем вызове, выполнение завершится на первом успешном результате.
const [firstResult, plugin] = await server.emit({
eventName: "client.uptime",
returnAllResults: false,
filters: { clientId: "123" }
});Типизация событий
В библиотеке предусмотрен удобный способ добавления собственных событий, расширяя интерфейсы:
declare module 'ruvipers-plugin-system' {
interface EventsFromServer {
"client.uptime": () => string;
}
interface EventsFromPlugin {
"query.getAllResults": () => string[];
"query.setProfileName": (userName: string) => { userName: string, id: string };
"query.setProfileInfo": (params: { userName: string, password?: string }) => { userName: string, id: string };
}
}Это позволяет строго следить за контрактом взаимодействия, уменьшать количество багов и комфортно использовать автокомплит в IDE.
Варианты использования
PluginServer поддерживает несколько сценариев развертывания и интеграции плагинов, что позволяет гибко адаптировать его под архитектуру конкретного проекта.
Удалённое подключение плагинов
Сервер запускается отдельно, как централизованный сервис. Плагины разворачиваются независимо — на тех же или других хостах, и подключаются к серверу через WebSocket автоматически по заданному адресу.
Особенности:
- Не требуется ручное управление подключением.
- Поддержка масштабируемой архитектуры (удалённые инстансы, распределённая сеть плагинов).
- Плагины могут быть запущены как отдельные процессы или сервисы.
Локальные плагины из директории (pluginsDir)
Плагины располагаются в файловой системе в директории, указанной в параметре pluginsDir. При запуске сервера они автоматически подгружаются, устанавливаются (если нужно), и запускаются в рамках основного процесса.
Особенности:
- Упрощённая локальная разработка и тестирование.
- Плагины могут быть написаны как модули Node.js.
- Поддержка горячей загрузки при перезапуске сервера.
Плагины в виде архивов (ZIP) в директории
Плагины загружаются как .zip-архивы, размещённые в той же pluginsDir. При старте сервера архивы автоматически распаковываются, и плагин инициализируется на основе данных из package.json.
Особенности:
- Удобно для доставки плагинов без раскрытия исходного кода.
- Поддержка дистрибуции в виде единого архива (например, через CI/CD).
- После распаковки кешируются и используются как обычные локальные плагины.
- Возможно использование собранных плагинов (обфускация, сборка проекта). Важно лишь указать верный индексный файл.
