Кроссплатформенный локальный API/консольное приложение для обработки списков блокировок интернет-ресурсов с поддержкой кастомных плагинов для любых операций с данными о новых блокировках!
[ Запретян лайт | Запретян / Discord бот / Domain Matcher | Запретян-Go ]Официальные встроенные плагины (Нажмите)
- ✅ LocalFS Записывает JSON полученного события на диск в .txt расширении
- ✅ Discord Sender Повторяет логику оригинальной Запретян в новой форме, присылая списки в чаты Discord сразу при наличии изменений, а также обновляет логику сообщений о изменениях в списках IP Адресов
- ✅ Daily Statistics Повторяет функцию аналитики оригинальной Запретян. Генерирует один ежедневный JSON и собирает аналитику в CSV таблицу
- ⏳ DiscordOnline В разработке. Повторяет функцию оригинальной Запретян, позволяя вашему Discord боту всегда оставаться в сети, пока ядро Запретян Go запущено
- ⏳ WebhookSender В разработке.
- ⏳ FTPWriter В разработке. Записывает JSON события по указанным FTP путям.
Tip
Если вы хотите использовать функционал оригинальной SHULKERPLAY/Zapretyan - Используйте ядро с включенными и настроенными плагинами Daily Statistics и Discord Sender!
Important
- Использование ядра
- Плагины
- Как создать свой плагин
- Прочее
Ядро Запретян-Go является консольным приложением доступным для Windows и дистрибутивов Linux архитектур amd64, arm64 и i386 (x86, 32-разрядные системы).
Ядро используется для периодического сбора списков блокировок из одного или нескольких источников (Отдельно домены и IP/CIDR), распространяемых в текстовом формате и их автоматического объединения с удалением дубликатов. Источники и частота проверки на наличие обновлений управляются вами в конфигурации приложения.
Important
Списки должны представлять собой обычный plain-text с новой строкой (\n) в качестве разделителя, где каждая строка — это один домен или один IP/CIDR
Подробнее о конфигурации приложения
При наличии обновлений ядро обрабатывает полученные списки и после записи новых списков создаёт событие с детальными данными об изменениях и отсылает его установленным и включеным в конфигурации плагинам. Установленные плагины могут совершать ЛЮБЫЕ действия с этими списками, которые смог придумать и написать кодом автор каждого из плагинов.
Плагины получают событие в JSON формате из данных которого они могут делать всё, что хотят.
Примеры которые сам смог придумать пока писал этот текст:
- При событии выгружать файл с новыми списками на свой сайт (Можно даже придумать свой фильтр результатов которые вы хотите испключить из этих списков)
- Отправлять список только что добавленных в список доменов или адресов в какой-либо мессенджер или соц.сеть постом с помощью ботов и подобного функционала (В Whatsapp, Telegram, Discord, и многие другие)
- Написать своего поискового бота или сервис по спискам, который всегда будет работать вместе с ядром, ядро будет поддерживать его жизнь.
- Обновлять счётчик заблокированых ресурсов (Доменов и адресов) находящийся где угодно
- Добавлять и удалять динамически адреса и домены из своего средства обхода блокировок
- Мониторить и собирать аналитику
И всё что угодно, но даже так не ограничиваясь, используя вот эти данные от ядра
Для того, чтобы ядро запустило ваш плагин, в момент первого запуска плагин обязан передать рукопожатие, в котором в том числе указывается режим плагина.
Плагин может иметь режим ONCE и STREAM.
- При режиме
ONCEвы можете выполнять разовые обработки (Получил данные->Сделал что надо->Процесс плагина закрывается). - При режиме
STREAMплагин живёт и слушает события всегда, не закрывая процесс. Этим плагином может быть целый сервис (Telegram бот, вебсервер, иной API или клиент с необходимостью бесперебойной работы встроенный в плагин) и он будет работать всё время пока запущено ядро. Если такой плагин крашнется, ядро автоматически перезапустит его процесс.
Вы можете писать свои плагины как на сложных языках программирования, так и на обычных скриптах, главное соответствовать критериям запуска.
Подробнее о режимах и о том как писать свои плагины
Примеры плагинов на разных языках программирования
Подготовьте папку для окружения. Несмотря на наличие защит и проверенную работу, вы можете расположить папку с ядром в пути без пробелов и кириллицы.
После установки, перед запуском, настройте config.toml желанным образом для работы. После этого вы сможете также установить процесс на автозапуск в вашей системе (Как системный юнит в Linux или как системный сервис в Windows)
- Операционная система
- Windows 10, Windows Server 2016 или новее
- Ядро Linux версии не ниже 3.2 (CentOS 7+, Ubuntu 16.04+ или Debian 8+)
- Процессор
- Совместимый с ОС на основе архитектур:
amd64,arm64,i386
- Совместимый с ОС на основе архитектур:
- ОЗУ
- Не менее 10МБ вплоть до 100МБ при очень больших списках изменений + Потребление включённых плагинов
- Диск
- ~200МБ свободного дискового пространства, (~10МБ ядро, ~100МБ списки при стандартных источниках, ~70МБ под временные файлы для скачивания списков) не учитывая нестандартные настройки ядра и данные настроенных плагинов.
- Стабильное подключение к интернету
- Перейдите на страницу последнего релиза
- Выберите подходящую вам сборку:
- Как выбрать на примере
zapretyan-go-linux-amd64.tar.gz:zapretyan-go- стандартный префикс всех сборок-linux-или-windows-- Операционная система, нужная вам-amd64- x64-разрядная система (Встречается чаще всего)-386- x86 (32-разрядная) система,-arm64- Система для ARM процессоров.
- Как выбрать на примере
- Распакуйте скачаный архив в заранее созданную папку (Например в
/usr/bin/zapretyangoилиC:\zapretyango) - Настройте
config.tomlи проверьте работу.- Windows: Вы можете запустить ядро двойным нажатием мыши на
zapretyanGo.exe - Linux: Вы можете запустить ядро находясь в директории прописав
./zapretyanGo. Если файл запрещён для исполнения используйтеchmod +X zapretyanGoи попробуйте запустить снова.
- Windows: Вы можете запустить ядро двойным нажатием мыши на
Функция доступна с версии v2.1.0.0
Для Windows:
- Запустите командную строку от имени администратора (или от имени обычного пользователя с версии
v2.1.1.0) - Переместитесь в папку с ядром с помощью
cd /d C:\zapretyango(Подставьте свой путь) - Исполните команду
zapretyanGo.exe --install. Для переустановки сервиса (Например если вы переместили ядро), исполните такую же команду. Она автоматически удалит старый сервис и создаст новый. - Готово. Удалить сервис можно используя
zapretyanGo.exe --uninstall
Warning
Запущеные консоли mmc.exe (например список служб) или диспетчер задач препятствуют удалению сервиса. Он будет помечен на удаление до закрытия всех таких консолей или перезагрузки системы.
В такой ситуации переустановка сервиса завершится с ошибкой.
Для Linux дистрибутивов:
Необходима система имеющая окружение systemd, OpenRC, SysVinit, Upstart. (Это почти все Kali, Debian, Ubuntu, CentOS, RedHat и прочие...)
- Зайдите от лица root просто или используя
su. Или используйтеsudo ./zapretyanGo --install. - Запустите
./zapretyanGo --installи следите за логом установки. - Готово. Удалить сервис можно используя
./zapretyanGo --uninstall- Для systemd: проверить работу сервиса можете с помощью
systemctl status zapretyango.service
- Для systemd: проверить работу сервиса можете с помощью
- Если вы устанавливали сервис на автозапуск, вне зависимости от системы сначала удалите его
- Для Linux
- Зайдите от лица root просто или используя
su. Или используйтеsudo ./zapretyanGo --uninstall. - Запустите
./zapretyanGo --uninstallи следите за логом удаления.
- Зайдите от лица root просто или используя
- Для Windows
- Запустите командную строку от имени администратора (или от имени обычного пользователя с версии
v2.1.1.0) - Переместитесь в папку с ядром с помощью
cd /d C:\zapretyango(Подставьте свой путь) - Исполните команду
zapretyanGo.exe --uninstallдля удаления сервиса.
- Запустите командную строку от имени администратора (или от имени обычного пользователя с версии
- Для Linux
- Закройте программу и просто удалите все её файлы
Скачайте новую сборку и замените файл zapretyanGo или zapretyanGo.exe и папку extensions. Проверьте изменения в стандартной конфигурации и исправьте конфиг под новый релиз если это необходимо, также при сменах конфигурации детали будут выписаны в описании релиза.
Масштабоность обновления выражается сменой конкретной цифры
- Мажорная версия:
v2.X.X.X- Поменяется только если изменения абсолютно полностью перевернут логику всего приложения - Важные изменения:
vX.2.X.X- Меняется при важных изменениях в логике, протоколе или конфигурации - Минорная версия:
vX.X.3.X- Любые обновления, не требующие дополнительных действий. Фиксы, улучшения производительности - Версия сборки:
vX.X.X.40- В ядро не было внесено никаких изменений, но есть обновления в комплекте предустановленных плагинов
В зависимости от ситуации вам могут понадобиться аргументы запуска программы. Вы можете использовать их запустив программу как zapretyanGo -arg1 --arg2.
-help- Выведет список всех доступных флагов-log- Позволяет управлять количеством логов в консоли и файле с помощью уровней вывода-log debug- Уровень журнала отладки. Выводится огромное количество необязательной отладочной информации-log info- Стандартный уровень вывода логов. Используется по умолчанию без флага-log warn- Отключает вывод информации о работе в логах и выводит только предупреждения с ошибками-log error- Выводить только ошибки
-logfile- Если флаг установлен - отключается цвет при выводе консоль и включается запись лога в файл-nocolor- Если флаг установлен - отключает цвет при выводе в консоль--install- Установить приложение на автозапуск как сервис--uninstall- Удалить приложение из автозапуска--dumpevent- Отладочная функция. Сохраняет каждое событие, отправляемое первому плагину в JSON файле в директории./data/debug--run- Не для использования. Применяется для запуска из системного сервиса. Включает файл лога, отключает цвета в выводе, отключает паузы при ошибках, включает механизмы взаимодействия с системой которые не нужны при работе в пользовательском пространстве
Конфигурация находится в файле config.toml. Он всегда должен находится рядом с ядром. Этот файл содержит конфигурацию ядра и всех ваших плагинов. Конфигурации плагинов передаются плагинам без изменений в JSON формате.
Подробно можно посмотреть в стандартных настройках плагина или в структуре конфигурации ниже
[core]
allow_custom_extensions(По умолчанию:false)- Если
true, позволяет запускать неофициальные плагины установленные в конфигурации
- Если
report_interval(По умолчанию:1, Минимум:1, Максимум:720)- Определяет, раз в сколько часов выполнять проверку на наличие обновлений в списках
send_empty_report(По умолчанию:true)- Определяет, нужно ли отправлять событие плагинам если ни в одном из списков нет изменений
once_ctx_deadline(По умолчанию:3300, Минимум:300, Максимум:2952000, Не может быть больше чемreport_interval * 3600)- Время в секундах которое даётся плагину с режимом
ONCEна обработку события и завершение работы. По достижении лимита времени плагину будет отправлена команда на закрытие, после при неисполнении процесс плагина будет принудительно завершён
- Время в секундах которое даётся плагину с режимом
disable_ip_comparsion(По умолчанию:false)- Если
true, списки IP адресов не будут загружаться и сравниваться. В событиях поля с разницой IP адресов будут всегда пустыми
- Если
disable_community(По умолчанию:true)- Если
false, включает загрузку и слияние дополнительных списков. В оригинальной задумке там находятся заблокированные домены сообществ. Эти списки только обновляются и записываются в файлcommunity.txtпри наличии изменений в источникахcommunity_domain_sourcesи не участвуют в сравнениях или событиях.
- Если
[core.data]
data_dir(По умолчанию:"./data")- Определяет расположение папки с данными для работы приложения и плагинов. Абсолютный путь автоматически передаётся плагинам.
- Вы можете использовать как полный путь к папке (Windows обязательно должен иметь двойные
\\при указании полного пути:"С:\\zapretyango\\data") - ...так и путь относительно приложения (Папка рядом с приложением:
"./data", папка уровнем выше для создания рядом с папкой приложения"../zapretyandata")
method(По умолчанию:"http")- При
"http"ядро перед загрузкой будет проверять наличие обновлений файлов на удалённом сервере при помощи чтения заголовкаLast-Modified. Если сервер возвращает этот заголовок корректно, то он будет сравнён с датой последнего обновления локального файла. Файлы будут скачиваться только в том случае, если хотя бы один файл из категории был обновлён на сервере. Далее после загрузки и слияния будет проверяться хэш файлов и ротация файлов (Загруженный->Новый->Старый) будет произведена только если хэш файловЗагруженныйиСтарыйбудет отличаться (они будут разными). - При
"hash"ядро пропускает проверку заголовкаLast-Modified, каждую итерацию скачивает и производит слияние всех файлов, которые нужно скачивать согласно настройкам. Далее после загрузки и слияния так же проверяться хэш файлов и ротация файлов будет произведена только если хэш файлов будет отличаться.
- При
Important
Параметры domain_source, ip_source и community_domain_sources это []массив ссылок (Они обязательно должны иметь http или https протокол), если вы хотите указать несколько источников, используйте синтаксис: ["ссылка_1","ссылка_2","ссылка_3"]
domain_source(По умолчанию:["https://antifilter.download/list/domains.lst"])- Ссылка на текстовые файл(ы) со списками доменов. Можно указать одну или несколько ссылок, ядро будет скачивать файлы и сливать их в один с удалением дубликатов строк.
ip_source(По умолчанию:["https://antifilter.download/list/ipresolve.lst","https://antifilter.download/list/subnet.lst"])- Ссылка на текстовые файл(ы) со списками IP адресов или CIDR (CIDR автоматически распакуются в список целых адресов). Можно указать одну или несколько ссылок, ядро будет скачивать файлы и сливать их в один с удалением дубликатов строк.
community_domain_sources(По умолчанию:["https://community.antifilter.download/list/domains.lst","https://raw.githubusercontent.com/1andrevich/Re-filter-lists/main/community.lst"])- Ссылка на текстовые файл(ы) со списками доменов сообщества. Можно указать одну или несколько ссылок, ядро будет скачивать файлы и сливать их в один с удалением дубликатов строк.
Important
Списки должны представлять собой файлы с текстовым содержанием и разделителем элементов в виде новой строки (\n) (1 домен/адрес - 1 строка)
- Для списков
domain_sourceиcommunity_domain_sourcesподдерживаются записи домена (example.com) и ссылки (http://example.com). Домен будет автоматически извлечён если в списке оказалась ссылка. - Для списков
ip_sourceподдерживаются записи IP адреса (1.1.1.1) и CIDR (1.1.1.0/24). CIDR будут автоматически распакованы в полный список адресов этой подсети. - Работа с IPv6 возможна, но не проверена и изначально не была предусмотрена.
Все параметры плагинов выделяются в отдельное поле [[extension]] конфигурация из которого будет полностью передана плагину в событии во время запуска. Подробнее ниже в структуре конфигурации.
name(Обязательное) (УНИКАЛЬНОЕ)- Поле для имени плагина заполняется как
name = "my plugin". Это имя будет использовано при инициализации и при трансляции логов из плагина через ядро. Вы можете устанавлиать любое имя, но оно не должно использоваться другим плагином, иначе ядро завершит работу на стадии инициализации плагинов.
- Поле для имени плагина заполняется как
desc(Необязательное)- Нужно для более простой навигации пользователя по конфигурации при поиске вашего плагина. Этот параметр будет передан плагину, но не учитывается ядром. Заполняется как
desc = "A plugin created just for being here"
- Нужно для более простой навигации пользователя по конфигурации при поиске вашего плагина. Этот параметр будет передан плагину, но не учитывается ядром. Заполняется как
source(Необязательное)- Нужно для более простой навигации пользователя по конфигурации при поиске места загрузки вашего плагина. Этот параметр будет передан плагину, но не учитывается ядром. Можно оставить в нём ссылку или краткое описание
source = "https://example.com"/source = "OnlyFans @shulkerplay"
- Нужно для более простой навигации пользователя по конфигурации при поиске места загрузки вашего плагина. Этот параметр будет передан плагину, но не учитывается ядром. Можно оставить в нём ссылку или краткое описание
path(Обязательное)- Относительный или полный к исполняемому файлу вашего плагина. Ядро парсит этот путь и пытается запустить плагин на шаге валидации. Для кросплатформенности конфигурации рекомендуется использовать относительные пути.
.в пути означает текущую директорию ядра,..означает что нужно поднятся на уровень выше. Так, стандартный путь к плагину должен выглядеть как./extensions/plugin- Для Windows, если в пути
pathне указано ни одно из поддерживаемых расширений (Подробнее), к пути автоматически будет подставлено.exe. Это обеспечивает портативность конфигурации. Так при использовании конфига на Windows запись./extensions/pluginбудет вести на файлplugin.exe, а на Linux конкретно наplugin.
- Для Windows, если в пути
- Относительный или полный к исполняемому файлу вашего плагина. Ядро парсит этот путь и пытается запустить плагин на шаге валидации. Для кросплатформенности конфигурации рекомендуется использовать относительные пути.
Tip
Если на Windows или Linux вы не можете исполнить плагин напрямую или вам нужно обязательно указать для него аргументы (Например если это сетевой запрос через curl или нужен строннний интерпретатор (Python для .py, Node для .js и т.д.) вы можете использовать .sh или .bat скрипт как посредника в зависимости от системы).
enabled(Обязательное)- Определяет включён
trueили выключенfalseконкретный плагин. Еслиenabled = false, ядро пропустит плагин на шаге валидации.
- Определяет включён
Остальные параметры могут быть абсолютно произвольными и будут переданы плагину в JSON при его запуске без изменений (Кроме трансляции TOML в JSON). Параметры должны быть описаны для каждого плагина отдельно. Список официальных плагинов и ссылки на их описание есть в спойлере над содержанием в этом документе.
Caution
Пользователям и разработчикам плагинов следует избегать типов данных TOML которых напрямую не существует в JSON! При конвертации в JSON они превратятся в строки стандарта RFC3339! Чтобы избежать проблем при парсинге значений на стороне плагина:
-
Не используйте никакие типы даты и времени:
2026-06-08T01:23:45+02:00,00:11:22,2026-06-08!- Изолируйте их как строку и распарсите строку самим плагином
"00:11:22"
- Изолируйте их как строку и распарсите строку самим плагином
-
Не используйте особые числовые выражения:
inf,+inf,-inf,nan,+nan,-nan!- Передавайте нестандартные значения как строку
"inf","nan".
- Передавайте нестандартные значения как строку
Это техническое ограничение существует, поскольку самый простой протокол данных для передачи массивов данных между процессами это JSON, а самый читаемый формат конфигурации для человека это TOML.
# Секция core содержит настройки ядра
[core]
# Параметры ядра
[core.data]
# Параметры ядра
# Для каждого плагина нужно отдельно создавать секцию extension
# Все данные этого [[extension]] будут переданы процессу path
[[extension]]
name = "Имя плагина"
desc = "Описание" # Необязательно
source = "Ссылка" # Необязательно
# Для Windows .exe к имени подставляется автоматически если не найдено ни одного поддерживаемого расширения.
# Слеши в относительных путях могут быть любыми "\" и "/"
# Для полных путей в Windows используйте два обратных слэша
path = "E:\\Zapretyan-Go\\extensions\\plugin1" # Полный путь Windows
enabled = true # Переключатель работы плагина
# Прочие параметры плагина 1
[[extension]]
name = "Имя плагина 2"
path = "./extensions/plugin2" # Относительный путь от ядра
enabled = false
# Прочие параметры плагина 2
[[extension]]
path = "/usr/bin/zapretyango/extensions/plugin3" # Полный путь Linux
# Параметры плагина 3Все файлы списков, загруженные из массива источников, которые указаны в конфигурации, сливаются в один список, сортируются по алфавиту, чистятся от дубликатов и после этого записываются в конечный файл.
- Файлы, загруженные из
domain_source = ['https://...','https://...']сохраняются вnew.tmp - Файлы, загруженные из
ip_source = ['https://...','https://...']сохраняются вnewip.tmp - Файлы, загруженные из
community_domain_sources = ['https://...','https://...']сохраняются вcommunity.tmp
Если в файле new.tmp есть изменения по сравнению с new.txt производится ротация:
old.txtудаляется из системыnew.txtпереименовывается вold.txtnew.tmpпереименовывается вnew.txt
Если в файле newip.tmp есть изменения по сравнению с newip.txt производится ротация:
oldip.txtудаляется из системыnewip.txtпереименовывается вoldip.txtnewip.tmpпереименовывается вnewip.txt
Если в файле community.tmp есть изменения по сравнению с community.txt производится ротация:
community.txtудаляется из системыcommunity.tmpпереименовывается вcommunity.txt
По окончанию процесса все временные файлы загрузок и сортировки автоматически удаляются
new.txt- Файл заблокированых доменов с самыми последними изменениямиold.txt- Файл заблокированых доменов предыдущей версииnewip.txt- Файл заблокированых IP адресов с самыми последними изменениямиoldip.txt- Файл заблокированых IP адресов предыдущей версииcommunity.txt- Файл заблокированых доменов по версии сообщества с самыми последними изменениями- Директория
debugс файлами внутри создаётся при установленом флаге--dumpevent
По умолчанию ядро поддерживает обработку файлов только по прямым ссылкам http(s). Если вы используете сторонние инструменты для скачивания и сохранения файлов на свой диск, вы можете настроить простой локальный веб-сервер. Это позволит транслировать локальные файлы в сеть по протоколу HTTPS, чтобы приложение могло беспрепятственно с ними работать.
Ниже приведены инструкции по быстрой настройке простого веб-сервера для Windows и Linux.
- Настройка веб-сервера для Windows (через Caddy)
- Настройка веб-сервера для Linux (Ubuntu/Debian)
- Альтернативный вариант (Если нужен только чистый Python без HTTPS)
Caddy — это современный, быстрый веб-сервер, который идеально подходит для этой задачи, так как он автоматически создает и доверяет локальные SSL-сертификаты (HTTPS) "из коробки" без сложной настройки.
Шаг 1. Подготовка
- Скачайте Caddy для Windows с официального сайта
- Создайте папку, где будут храниться ваши файлы (например, C:\shared_files).
Шаг 2. Создание конфигурации (Caddyfile)
В папке с программой Caddy (или в вашей рабочей папке) создайте текстовый файл с именем Caddyfile (без расширения .txt) и следующим содержимым:
localhost:443 {
# Укажите путь к папке с вашими файлами
root * "C:\shared_files"
# Включаем раздачу файлов
file_server
# Автоматический локальный HTTPS
tls internal
}
Шаг 3. Запуск сервера
Откройте командную строку (cmd) от имени Администратора (это необходимо для установки локального SSL-сертификата в систему) и выполните:
caddy run --config Caddyfile
При первом запуске Windows может спросить разрешение на установку корневого сертификата Caddy Local Authority — подтвердите установку, чтобы ссылки https://localhost/... стали доверенными.
Шаг 4. Использование в приложении
Теперь любой файл, скопированный в папку C:\shared_files\mydomains.txt, доступен вашему приложению по ссылке:
https://localhost/mydomains.txt
Для Linux мы также можем использовать Caddy из-за встроенной автоматизации локального HTTPS, либо связку Nginx + самоподписанный сертификат. Рассмотрим самый быстрый вариант с Caddy.
(Если у вас не установлен sudo - копируйте команды без sudo в начале)
Шаг 1. Установка Caddy
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddyШаг 2. Конфигурация
Создайте папку для файлов, например /var/www/shared_files, и выдайте на неё права:
sudo mkdir -p /var/www/shared_files
sudo chown -R caddy:caddy /var/www/shared_filesОтредактируйте конфигурационный файл /etc/caddy/Caddyfile:
localhost:443 {
root * /var/www/shared_files
file_server
tls internal
}
Шаг 3. Перезапуск службы
sudo systemctl restart caddyCaddy автоматически сгенерирует локальный HTTPS-сертификат и добавит его в системное хранилище доверенных сертификатов Linux.
Шаг 4. Использование в приложении
Поместите нужный файл в /var/www/shared_files/mydomains.lst. Теперь его можно передавать в приложение по адресу:
https://localhost/mydomains.lst
Warning
Этот способ подходит только в том случае, если вас устроит локальный веб-сервер без SSL, так как стандартный модуль Python не поддерживает HTTPS без ручной генерации ключей.
Если у вас установлен Python 3, вы можете мгновенно запустить HTTP-сервер в любой папке.
В Windows (PowerShell) или Linux:
Перейдите в папку с файлами: cd /path/to/files
Запустите сервер на порту 8080:
python -m http.server 8080Файлы будут доступны по протоколу HTTP: http://localhost:8080/mydomains.txt
Плагины играют ключевую роль в уникальности и гибкости Запретян-Go. Ядро само по себе работает как провайдер данных, сливая данные нескольких источников в единый список удаляя дубликаты, фильтруя ссылки, распаковывая подсети. Однако без плагинов всё что можно делать - это сохранять такие файлы на диск.
Плагинами могут быть скрипты или исполняемые файлы, с которыми ядро будет совершать рукопожатие (Проверка выполнения инструкций и получение данных о том что внутри плагина), после чего каждую итерацию сканирования будет отсылать плагинам широкий набор данных как индикацию о том, произошли ли изменения в списках и что конкретно было изменено. Ядро также служит транслятором конфигурации для плагина, передавая относящиеся к нему данные из своего конфига без каких-либо изменений. С таким набором данных можно выполнять абсолютно любые специфические задачи.
Всё что можно придумать получая данные от ядра. Выше были приведены примеры:
- При событии выгружать файл с новыми списками на свой сайт (Можно даже придумать свой фильтр результатов которые вы хотите испключить из этих списков)
- Отправлять список только что добавленных в список доменов или адресов в какой-либо мессенджер или соц.сеть постом с помощью ботов и подобного функционала (В Whatsapp, Telegram, Discord, и многие другие)
- Написать своего поискового бота или сервис по спискам, который всегда будет работать вместе с ядром, ядро будет поддерживать его жизнь.
- Обновлять счётчик заблокированых ресурсов (Доменов и адресов) находящийся где угодно
- Добавлять и удалять динамически адреса и домены из своего средства обхода блокировок
- Мониторить и собирать аналитику
Вы можете сделать плагин одноразовым обработчиком (Режим ONCE), например фильтровать результаты и выгружать данные на свой сайт.
Вы также можете сделать плагин сервисом при режиме stream, например сделать свой поисковой инструмент по спискам при этом принимая новые изменения, запустить соединение с любым API куда вы будете отправлять информацию, всё что угодно и при этом ядро будет поддерживать жизнь такого плагина, перезапуская его при краше.
Всё, на что хватит фантазии.
Плагин получает включительно но не ограничиваясь эти данные при каждом сканировании:
- Сам факт что сканирование случилось (Событие придёт в ядро даже если изменений нет при
send_empty_report = true) - Что именно изменилось:
- Ядро предоставляет 4 поля: Удалены/Добавлены домены/IP адреса
- Для каждого поля детальный массив со списком, количество элементов в массиве, и есть ли вообще изменения в массиве
- Конфигурацию вашего плагина в событии
- Абсолютный путь к директории с данными
Описание данных присылаемых плагину от ядра
Практически на любых. Серьёзно. В репозитории есть сборник примеров плагина на языках: C, C++, C#, Java, TypeScript (Deno), JavaScript (NodeJS), Rust, Ruby, PHP, Lua, Bash, Batch, Powershell.
Как и писалось выше, вы можете писать плагин на чём угодно, начиная от скриптов, заканчивая сложными программными средствами. Главное соблюдать правило кроссплатформенности, если вы хотите распространять плагин.
Так, например в Linux вам может понадобится передавать аргументы приложению или отправлять данные в другое место и вы можете использовать Bash скрипт .sh как "Прокси" между Запретян и другим программным средством. Вы также можете использовать Шебанги для прямого запуска скриптов.
А в Windows для запуска, например, скрипта на NodeJS, вам потребуется использовать скрипт командной строки .bat/.cmd как "Прокси" между запретян и Node для возможности запустить плагин, так как ядро Запретян на Windows может запускать только .exe и пакетные файлы командной строки.
Итак, вы решили стать пилотом. Хочется надеяться, что этот текст попался на глаза раньше, чем вы оказались в середине полёта (разработки).
В этом разделе мы разберём как именно ваш плагин получает конфигурацию, как выполнять рукопожатие с ядром, нюансы двух разных режимов работы и разберём какие именно данные получает плагин.
Для примеров я всё же не опредилился и буду использовать язык Go как язык на котором я могу написать пример чисто и аутентично к исходному коду ядра.
Все доступные примеры и подходы на разных языках программирования
Ваш плагин должен принимать поток данных, в котором будет принимать события, которые будут отправляться в JSON формате. В вашем языке программирования необходима возможность работать с тремя каналами ввода/вывода - stdout, stdin и stderr.
- При запуске ядра, первое что вы должны сделать как можно быстрее - вывести в
stdoutJSON рукопожатия с плагином. Подробнее в следующей части раздела
Warning
stdout Это стандартный консольный вывод, но ваш плагин должен использовать его только один раз при запуске и далее никогда - все данные попадающие в stdout после первого рукопожатия будут подавлены ядром!
- Вы можете подумать о том, что если стандартный консольный вывод заблокирован, как отслеживать логи плагина? Вам нужно будет сделать функцию для отправки логов приложения в канал
stderr.
Ваш плагин не должен выводить куда-либо логи сам по себе. Вы должны отправлять простые логи, без префиксов имени вашего плагина и времени, так как эти префиксы ядро подставит самостоятельно. Соответвенно и запись логов в файл ведёт ядро с флагом -logfile или в режиме системного сервиса.
Так, если отправить простой лог в stderr с использованием простой функции
logMsg("Event written successfuly: %s", fileName)В логе ядра будет аккуратная запись
00:58:35 INF PLUGIN: name="File Logger" msg="Event written successfuly: 2026-05-29_00-58-35.txt"В Go простая функция отправки логов реализуется так:
// Функция отправки логов в ядро Запретян форматируя их с помощью fmt.Fprintf
// Первый аргумент это сплошной текст
// Но для использования в нём переменных, например текста ошибок
// Можно перечислять их в дальнейших аргументах
func logMsg(format string, a ...interface{}) {
// os.Stderr - канал куда будет отправлен этот текст
fmt.Fprintf(os.Stderr, format+"\n", a...)
}
// Так вы можете отправлять лог
// В Go Fprintf подставит содержание targetDir на место %s и err на место %v
logMsg("Error creating directory %s: %v", targetDir, err)Tip
В C# для записи в stderr можно использовать Console.Error.WriteLine, в NodeJS process.stderr.write, в Python sys.stderr.write, в Bash и Batch echo или printf с перенаправлением >&2.
- В вашем плагине не будет смысла и он не пройдёт валидацию, если не будет корректно обрабатывать события, приходящие в формате JSON в
stdin.
Ядро отправляет вашему плагину события в формате JSON в одну строку с \n (Новой строкой) в окончании JSON объекта, чтобы самые простые JSON парсеры могли распознать когда данные закончились и можно приступать к их обработке.
Посмотрите пример события (Развёрнуто в несколько строк для читаемости) и описание данных присылаемых плагину от ядра
Caution
В JSON событии всегда есть поле kill. Если значение этого поля равняется true, ваш плагин обязательно должен завершить необходимые процессы и завершить работу за максимально короткий промежуток времени. Детали ситуации разбираются ниже...
Режим работы плагина означает то, как ядро будет его запускать и отправлять ему события, а также как будет следить за его жизненным циклом. Он должен быть описан в коде плагина, так как требует отправки ядру ещё до того как получит свою конфигурацию. Выберите самый удобный для вас.
Всего режимов предусмотрено два: ONCE и STREAM. Давайте разберём разницу их работы.
- Режим
ONCEиспользуется для одноразовых обработок.
Цикл работы выглядит так:
Ядро начинает сканирование -> Создаёт событие -> Запускает плагин -> Плагин выполняет действия -> Плагин завершает работу
Плагин с этим режимом проходит валидацию при запуске ядра и запускается каждый раз для каждого события. Это позволяет таким плагинам выполнять действие и не забивать ОЗУ своим присутствием, если это одноразовая обработка.
Для плагинов с режимом ONCE выделяется ограниченное время на обработку события установленное в параметре once_ctx_deadline, чтобы обработка первого события никак не могла наложиться на обработку второго. Если плагин не завершил работу по истечении once_ctx_deadline секунд, то ядро отправит ему команду на завершение работы. Если процесс не закроется и после этой команды - он будет принудительно завершён ядром Запретян.
- Режим
STREAMиспользуется для непрерывной работы с ядром. Удобно для сервисов и иных задач, в которых процесс плагина должен жить пока живо ядро Запретян
Плагин с этим режимом проходит валидацию при запуске ядра и запускается повторно сразу после неё. После этапа валидации все расширения с режимом STREAM запускаются параллельно. Все процессы ядра приостанавливаются на 5 секунд, чтобы плагины успели запуститься и распарсить свою конфигурацию, не получив при этом новое событие слишком рано.
Плагины в режиме STREAM должны всегда слушать stdin, так как в него от ядра будут приходить события всю жизнь процесса плагина.
Плагины в этом режиме поддерживаются ядром и не завершают свою работу пока ядро не закроется и не пришлёт им сигнал на закрытие. Если процесс плагина завершил работу сам по себе, ядро считает что он крашнулся и перезапускает его процесс после 5 секунд паузы. Ядро перезапустит расширение максимум 10 раз до перезапуска ядра. Если расширение типа STREAM самостоятельно завершит работу 10 раз, оно будет отключено до перезапуска.
Рукопожатием является двухэтапный тест обмена данными при запуске плагина.
Валидация происходит 1 раз при запуске ядра. Если плагин не пройдёт валидацию, ядро запустится без него.
- Этап 1: Ваше расширение обязательно должно прислать JSON со своими данными в канал
stdout. JSON должен содержать"mode"- Должен содержать режим работы вашего плагина. Может быть"ONCE"или"STREAM"."version"- Версия вашего плагина. Например"1.2.1"."jsonver"- Версия JSON протокола Запретян, для которого создано ваше ядро. Сейчас есть только версия -1, если эта версия изменится в ядре, это будет обозначать то что в JSON шаблоне события произошли изменения и плагины устаревшей версии могут неправильно обработать входящие события. Ядро выдаст предупреждение если эти версии не совпадают. Вы в своём плагине можете (необязательно) отбрасывать события которые не соответствуют версии, поддерживаемой плагином.
В Go вы можете гибко настроить структуру и отправлять её ядру при запуске:
// Структура для кодировки JSON
type Handshake struct {
Mode string `json:"mode"`
Version string `json:"version"`
JsonVer int `json:"jsonver"`
}
// Ваши параметры плагина
const pmode = "ONCE" // Режим работы
const pjsonver = 1 // Поддерживаемая версия JSON протокола Запретян
const pver = "1.0.1" // Версия вашего плагина
// Собираем данные в объект по структуре
handshake := Handshake{
Mode: pmode,
Version: pver,
JsonVer: pjsonver,
}
// Посылаем JSON рукопожатия с \n в конце
if err := json.NewEncoder(os.Stdout).Encode(handshake); err != nil {
logMsg("FATAL: Error sending Handshake (%v)", err)
os.Exit(1)
}Вы можете создать очень упрощённый вариант просто отправляя текстовую заготовку
// JSON рукопожатия с экранированием кавычек
const handshake string = `{"mode":"ONCE","version":"1.0.1","jsonver":1}` + "\n"
// Получится {"mode":"ONCE","version":"1.0.1","jsonver":1}
// Отправка рукопожатия
fmt.Fprintf(os.Stdout, handshake)- Этап 2: Проверка способности вашего плагина обрабатывать команды
- Во время запуска ядра, на этапе валидации, после ваших данных присланных плагином, плагину будет отправлена JSON команда. При валидации в команде будет параметр
"kill": true,, что будет означать что вашему ядру нужно завершить работу. Плагин пройдёт валидацию только в том случае, если после этой команды завершит свою работу за 5 секунд. Иначе плагин не будет загружен. - После этапа валидации, когда ваш плагин будет запускаться, он тоже получит команду после отправки ваших данных, но уже с параметром
"kill": false,. Эта команда будет прислана для того, чтобы прислать вашему плагину его конфигурацию из файлаconfig.toml. Это будет вам полезно, если вы хотите загрузить параметры плагина ДО ТОГО как придёт первое событие.
- Во время запуска ядра, на этапе валидации, после ваших данных присланных плагином, плагину будет отправлена JSON команда. При валидации в команде будет параметр
Если ваш плагин отправит свои данные корректно, а после по команде будет вовремя закрыт - поздравляем, плагин прошёл валидацию и будет запущен, раньше или позже, в зависимости от режима работы плагина.
Вы увидите это в логах
01:02:54 INF Handshake completed name="File Logger" mode=ONCE version=1.0.1
01:02:54 INF Extension successfuly validated name="File Logger"Important
При получении любой структуры от ядра ваш плагин ОБЯЗАН проверять параметр kill, так как он может получить его не только на этапе валидации, но и когда ядро завершает работу по запросу пользователя. Если при "kill": true, плагин не завершит работу сам, ядро убъёт его принудительно по таймауту
В Go для чистоты работы, мы запускаем сканнер и проверяем полученные условия. Подробности в следующем разделе с обработкой событий
// Структура данных которую мы можем достать из события
type BaseEvent struct {
// Версия протокола ядра Запретян
Ver int `json:"ver"`
// Тип "cmd" для команд и конфигурации, "rkn" для обработки событий
Type string `json:"type"`
// Если true процесс должен быть немедленно завершён
Kill bool `json:"kill"`
}
var base BaseEvent
// Ваш парсер событий...
// Смотрите примеры плагинов на разных языках программирования
// Завершаем процесс если "kill": true
if base.Kill {
logMsg("Получен сигнал KILL. Завершение работы.")
os.Exit(0)
}
...В этом разделе будет только пример того как именно мы можете обрабатывать данные от ядра. JSON события всегда имеет один конкретный формат, все его возможные поля вы можете узнать далее.
- Описание всех полей JSON события
- Развёрнутый пример JSON события которое будет получать ваш плагин
- Не забываем что на разных языках программирования подход отличается.
Tip
Весь код и решения описанные ниже не обязаны быть точно скопированы в ваш плагин или ваше решение.
Вы можете использовать информацию ниже с умом, чтобы увидеть пример реализации. Вы свободны в написании кода и можете как скопировать решения ниже, так и писать свои улучшеные версии. Если ваш плагин прошёл валидацию - вы вольны делать с данными что угодно и обрабатывать их как угодно.
Нам нужно как-то читать данные, которые нам пришлёт событие. В Go можно сделать это с помощью библиотеки bufio, собирая получаемые строки в цельный JSON объект.
Ядро отсылает событие одной строкой с окончанием \n (Новая строка). Это позволяет обнаружить конец JSON объекта примитивным парсерам, которые не умеют считать количество открытых { и закрытых } скобок для обнаружения конца JSON.
Пример сканирования строк на Go
// Назначаем новый сканер для чтения потока stdin
scanner := bufio.NewScanner(os.Stdin)Для того, чтобы не убивать память постоянными переаллокациями для буфера, в этом решении я настроил свой собственный буфер, но делать это необязательно
// Защита от слишком огромных объектов. Мы ограничиваем буфер размером в 100МБ
const maxCapacity = 100 * 1024 * 1024
// Выделяем стартовую память под буфер (64КБ)
buf := make([]byte, 64*1024)
// Применяем настройки буфера
scanner.Buffer(buf, maxCapacity)Теперь описываем цикл сканирования. Для каждого полученного сканнером события scanner.Scan() выполняем действия в цикле for.
for scanner.Scan() {
// Сканируем полученые данные побайтово
rawBytes := scanner.Bytes()
if len(rawBytes) == 0 {
// Если было получено 0 байт данных - пропускаем этот цикл
continue
}
// Все полученные данные из stdin записываем в переменную json парсером
rawEvent := json.RawMessage(rawBytes)
// Посылаем JSON в вашу обработку события
handleEvent(rawEvent)
}Не забываем что если вы делаете сервис с режимом STREAM который должен выполнять несколько функций одновременно, этот цикл повесит основной поток приложения. Ваше приложение будет занято только ожиданием нового события. В Go, чтобы этого избежать, нужно запустить цикл в отдельном потоке
func eventScanner() {
// Вся логика сканирования с буфером
}
go eventScanner()Мы разберём работу функции handleEvent() которую мы вызываем в прошлом примере, передавая сырые JSON данные из метода json.RawMessage()
Для начала мы должны понимать что мы уже знаем какую структуру имеет JSON. Секретов нет, поэтому мы заранее зададим вид структуры
type BaseEvent struct {
Ver int `json:"ver"` // Версия протокола ядра Запретян
Type string `json:"type"` // Тип "cmd" для команд и конфигурации, "rkn" для обработки событий
Kill bool `json:"kill"` // Если true процесс должен быть немедленно завершён
Path string `json:"path"` // Абсолютный путь к папке с данными ядра
// Конфигурацию плагина храним в как отдельную структуру
// Поле может быть быть пустым, поэтому оставляем указатель на неё
Cfg *PluginConfig `json:"cfg"` // Если конфиг не придёт, тут будет nil
}Теперь мы начинаем обрабатывать сырой JSON в нашей функции
func handleEvent(raw json.RawMessage) { // Начало функции handleEvent
// Объявляем локальную переменную в которой будет структура этого JSON
var base BaseEvent
// Распаковываем сырой JSON по указателю в переменную base
// Все поля существующие в структуре BaseEvent будут записаны в переменную
if err := json.Unmarshal(raw, &base); err != nil {
logMsg("Ошибка парсинга JSON события: %v", err)
return
}Итак, у нас есть готовая переменная base с зашитыми в неё данными.
Сходу проверяем поле kill. Вы должны завершить внутренние процессы вашего сервиса и завершить работу плагина. У нас никаких процессов важных нет, поэтому сразу выходим если получаем "kill":true
if base.Kill {
os.Exit(0)
}Можем проверить совместимость с текущей версией протокола ядра и сделать своё действие на случай несовместимости. Тут мы выведем предупреждение, но ядро выведет предупреждение при инициализации плагина если версии протокола отличаются.
if base.Ver != pjsonver && base.Ver != 0 {
logMsg("Warning: Event version (%d) does not match (%d)", base.Ver, pjsonver)
}Проверяем тип события. Типов есть два: "rkn" и "cmd".
У вас есть два пути для проверки типа:
- Чем глубже в лес...
if else if else - Использовать
switchв языках, в которых он есть
Используем switch для проверки типа и выполнений действий согласно типу события
switch base.Type {
case "cmd":
// Действия при команде
case "rkn":
// Действия при событии
default:
// Действия при неподдерживаемом типе
}Если мы получаем "cmd" есть два сценария, как было описано в валидации.
- Либо ядро должно завершить работу при
"kill":true, что мы в нашем примере сделали до обработкиswitch - Либо загрузить конфигурацию плагина при
"kill":false, так как перед получением первого события, вне зависимости от типа плагина, ядро вышлет вашему плагину отдельную JSON команду с конфигурацией плагина изconfig.toml.
Для начала посмотрим конфигурацию нашего плагина в config.toml. Наши параметры это save_last_entries и localfs_dir
[[extension]]
name = "File Logger"
path = "./extensions/localfs"
enabled = true
save_last_entries = 100
localfs_dir = "localfs_logger"Плагин пришлёт нам в структуре вот такую форму "cfg"
"cfg": {
"enabled": true,
"localfs_dir": "localfs_logger",
"name": "File Logger",
"path": "./extensions/localfs",
"save_last_entries": 100
},Ранее мы в структуре BaseEvent оставили указатель на структуру PluginConfig - в ней мы будем хранить конфигурацию
type PluginConfig struct {
SaveLastEntries int `json:"save_last_entries"` // Количество файлов для сохранения
Directory string `json:"localfs_dir"` // Папка внутри которой мы будем всё хранить
}До этого на верхнем уровне нашего модуля main.go оставили переменные в которых мы будем хранить конфигурацию
var config *PluginConfig // Структура со всей конфигураций
var targetDir string // Абсолютный путь к папке для файловТак как мы дошли до этого момента, это значит что мы получили "kill":false, обрабатываем полученную конфигурацию если нам прислали тип "cmd"
// Если переменная config всё ещё пустая и JSON имеет поле "cfg" - загружаем конфиг
if config == nil && base.Cfg != nil {
config = base.Cfg
logMsg("Конфигурация загружена. Лимит файлов: %d, директория: ./%v", config.SaveLastEntries, config.Directory)
}
// Загружаем директорию
// Делаем только если: У нас до сих пор нет пути куда сохранять (targetDir)
// У нас есть полный путь к папке с данными (base.Path)
// У нас есть параметр с названием нашей папки (config.Directory)
if targetDir == "" && base.Path != "" && config.Directory != "" {
// Объединяем полный путь к папке с данными с названием папки
// Так мы получим полный путь к папке куда нужно сохранять файлы
// filepath.Join автоматически запишет путь совместимый с текущей ОС
targetDir = filepath.Join(base.Path, config.Directory)
}Отлично! Теперь у нас есть записанные как нужно НАМ переменные config.SaveLastEntries с лимитом файлов и targetDir с полным путём к папке для сохранения
Теперь нам нужно уметь обрабатывать события, приходящие от ядра. Все события содержат данные о разнице данных с последней проверки. Тип таких событий всегда "rkn". В таких событиях поле "cfg" тоже присутствует, если оно вам очень нужно в обработке, чтобы не хранить параметры всегда в своём плагине.
В текущем примере обработка выведена в отдельную функцию, в switch только перенаправление и указание СТАНДАРТНЫХ параметров, на случай если мы почему-то так и не загрузили конфигурацию к этому моменту.
saveLimit := 100 // Стандартное значение если конфиг не загрузился
if config != nil && config.SaveLastEntries > 0 {
saveLimit = config.SaveLastEntries
}
// Отдаём сырой JSON в отдельную функцию
processRknEvent(raw, saveLimit)
// Отдаём лог если событие не "rkn" и не "cmd" (Наш код не знает что это)
default:
logMsg("Unknown event type: %s", base.Type)
}
} // Функция handleEvent закончиласьВ текущем примере мы передаём сырой JSON потому что плагин выполняет маршаллинг JSON в читаемый вид и сохрадяет в файл. Исходный код плагина тут. Но вероятно для ваших целей вам нужны данные самого события.
В любом из случаев в Go вам скорее всего понадобится структуры:
// Структура для каждого из типов списков
type DiffObjectData struct {
Empty bool `json:"empty"` // Если true - Data пустой
Length int `json:"length"` // Длинна массива Data
Data []string `json:"data"` // Массив с изменениями
Total int `json:"total"` // Общее количество записей типа
}Обратите внимание что все объекты поля "diff" имеют одинаковую форму, описаную в DiffObjectData
// Структура самого объекта "diff" из события
type DiffObject struct {
BannedDomains DiffObjectData `json:"banned"` // Заблокированые домены
UnbannedDomains DiffObjectData `json:"unbanned"` // Разблокированые домены
BannedIPs DiffObjectData `json:"banned_ip"` // Заблокированые IP
UnbannedIPs DiffObjectData `json:"unbanned_ip"` // Разблокированые IP
}Important
Вам всё ещё стоит взглянуть в описание JSON структуры ниже!
Поля "total", обозначают общее количество строк в файле с блокировками доменов и IP адресов. Однако это поле валидно только для объектов "banned" и "banned_ip"! Если вы спарсите данные в структуру, и попытаетесь прочитать
currentDiff.Diff.UnbannedDomains.Total("unbanned": {"total"})currentDiff.Diff.UnbannedIPs.Total("unbanned_ip": {"total"})
то в выводе получите не общее количество, а 0!
У вас есть два варианта:
- Вариант 1: вы будете парсить сырой JSON повторно в функции обработки события:
func processRknEvent(raw json.RawMessage) {
// Объявляем локальную переменную как структуру
// в которой будет структура текущего диффа
var currentDiff struct {
Diff DiffObject `json:"diff"` // В отдельном подходе нам нужно только поле diff
}
// Например чтобы вывести количество заблокированых в событии доменов
// Мы используем fmt.Println(currentDiff.Diff.BannedDomains.Length)
// Распаковываем сырой JSON по указателю в переменную currentDiff
// В этом случае в структуре есть только одно поле и запишем мы только его
if err := json.Unmarshal(raw, ¤tDiff); err != nil {
logMsg("Ошибка парсинга JSON события: %v", err)
return
}
// Дальше ваши действия с данными
}- Вариант 2: Вы пытаетесь парсить поле
"diff"в одном блоке кода в котором и принимаете конфигурацию.
Для этого нужно будет изменить структуру BaseEvent.
type BaseEvent struct {
Ver int `json:"ver"`
Type string `json:"type"`
Kill bool `json:"kill"`
Path string `json:"path"`
// Cfg и Diff это указатели на структуры
// Если спарсить их не удастся или их не будет - они будут равны nil
Diff *DiffObject `json:"diff"` // Добавляем поле "diff" в парсер
Cfg *PluginConfig `json:"cfg"`
}
// Объявляем локальную переменную в которой будет структура этого JSON
var base BaseEvent
// Распаковываем сырой JSON по указателю в переменную base
// Все поля существующие в структуре BaseEvent будут записаны в переменную
if err := json.Unmarshal(raw, &base); err != nil {
logMsg("Ошибка парсинга JSON события: %v", err)
return
}
switch base.Type {
case "cmd":
// Действия при команде
case "rkn":
// Проверяем что поле было и мы спарсили наш "diff" правильно
if base.Diff == nil {
logMsg("Ошибка: Объект 'diff' в событии оказался пустым или был обработан с ошибкой")
return
}
// Приступаем к обработке события
default:
// Действия при неподдерживаемом типе
}Tip
Весь код и решения описанные выше не обязаны быть точно скопированы в ваш плагин или ваше решение.
Вы можете использовать информацию выше с умом, чтобы увидеть пример реализации. Вы свободны в написании кода и можете как скопировать решения выше, так и писать свои улучшеные версии. Если ваш плагин прошёл валидацию - вы вольны делать с данными что угодно и обрабатывать их как угодно.
Эта секция это полный разбор развёрнутого примера JSON события которое будет получать ваш плагин.
Ниже представлена версия протокола Запретян 1, актуальная для v2.0.0.0+.
"Ver"- Версия JSON протокола Запретян. В рамках одной конкретной версии структура JSON не меняется. Можно использовать для проверки совместимости вашего плагина с ядром, на случай если этот протокол получит обновление. Текущая версия протокола:1"type"- Может содержать только два значения:"rkn"в случае если это событие сравнения с полем"diff","cmd"в случае если это команда для завершения работы плагина или для отправки конфигурации плагину"kill"- Приtrueваш плагин обязан завершить работу самостоятельно. Если не сделать этого вовремя, ядро завершит процесс плагина принудительно. В остальных случаях это поле будетfalse."path"- Полный путь к папке с данными, настроенной в конфиге ядра. Для Linux поле будет иметь такой формат:"/usr/bin/zapretyan-go/data", для Windows:"С:\\Zapretyan-Go\\data""cfg"- Содержит объект с конфигурацией вашего плагина изconfig.toml. Пример того, как данные переносится из конфига можно увидеть в графе "Как парсить события из полученного JSON""diff"- Содержит объекты со всеми данными о разнице с момента прошлого сканирования"banned"- Содержит объект с данными о заблокированых доменах с момента прошлого сканирования"empty"- Если изменений нет, поле будетtrue. Иначеfalse."length"- Количество заблокированых доменов (Фактически длинна массива"data"). Если массив с изменениями пустой, это поле будет содержать0."data"- Массив со всеми заблокироваными доменами с прошлого сканирования. Массив формата['domain1.com','domain2.com']. Если изменений не было, поле будет содержать[]"total"- Общее количество заблокированых доменов (Фактически количество строк файла с доменами (new.txt)). Если файла не существует, это поле будет содержать0.
"unbanned"- Содержит объект с данными о разблокированых доменах с момента прошлого сканирования"empty"- Если изменений нет, поле будетtrue. Иначеfalse."length"- Количество разблокированых доменов с прошлого сканирования (Фактически длинна массива"data"). Если массив с изменениями пустой, это поле будет содержать0."data"- Массив со всеми разблокироваными доменами с прошлого сканирования. Массив формата['domain1.com','domain2.com']. Если изменений не было, поле будет содержать[]
"banned_ip"- Содержит объект с данными о заблокированых IP адресах с момента прошлого сканирования"empty"- Если изменений нет, поле будетtrue. Иначеfalse."length"- Количество заблокированых IP адресов (Фактически длинна массива"data"). Если массив с изменениями пустой, это поле будет содержать0."data"- Массив со всеми заблокироваными IP адресами с прошлого сканирования. Массив формата['123.12.1.3','225.14.21.6']. Если изменений не было, поле будет содержать[]"total"- Общее количество заблокированых IP адресов (Фактически количество строк файла с IP адресами (newip.txt)). Если файла не существует, это поле будет содержать0.
"unbanned_ip"- Содержит объект с данными о разблокированых IP адресах с момента прошлого сканирования"empty"- Если изменений нет, поле будетtrue. Иначеfalse."length"- Количество разблокированых IP адресов с прошлого сканирования (Фактически длинна массива"data"). Если массив с изменениями пустой, это поле будет содержать0."data"- Массив со всеми разблокироваными IP адресами с прошлого сканирования. Массив формата['123.12.1.3','225.14.21.6']. Если изменений не было, поле будет содержать[]
- Страница Zapretyan-Go на нашем сайте
- Страница Discord приложения Запретян на нашем сайте
- Бот Запретян в магазине приложений Discord
Буду рад любой поддержке, связаться со мной можно на нашем сервере Discord
Если вы хотите сами скомпилировать ядро Zapretyan-Go и его расширения, ниже можете как это сделать для операционных систем Linux и Windows.
Перед началом сборки убедитесь, что в вашей системе установлен Go (Golang) версии 1.26.3 или новее.
- Проверить установленную версию можно командой:
go version - Если Go не установлен, скачайте его с официального сайта.
Вы можете выбрать один из двух способов получения исходного кода: сборку самой последней (разрабатываемой) версии или сборку стабильного релиза.
Этот вариант содержит самые последние изменения и исправления, но может быть оттестирован недостаточно тщательно.
- Скачайте zip архив напрямую
- Через консоль (Linux):
wget https://github.com/SHULKERPLAY/Zapretyan-Go/archive/refs/heads/main.zip
unzip main.zip
cd Zapretyan-Go-mainЕсли у вас установлен Git, вы можете клонировать репозиторий:
git clone https://github.com/SHULKERPLAY/Zapretyan-Go.git
cd Zapretyan-GoЕсли вам нужна проверенная и стабильная версия, вы можете скачать исходный код последнего релиза с помощью архивной ссылки GitHub:
- Ссылка на архив:
https://github.com/SHULKERPLAY/Zapretyan-Go/archive/refs/tags/LATEST_RELEASE.zip(замените LATEST_RELEASE на тег актуальной версии, например v2.1.1.0).
Основной исполняемый код приложения находится в каталоге /core. Чтобы получить оптимизированный бинарный файл без лишней отладочной информации, используется специальный набор флагов компиляции.
- Перейдите в каталог с точкой входа приложения:
cd core/cmd- Выполните команду сборки в зависимости от вашей операционной системы:
- Для Linux:
go build -v -trimpath -ldflags="-s -w -buildid=" -o zapretyanGo .- Для Windows (CMD / PowerShell):
go build -v -trimpath -ldflags="-s -w -buildid=" -o zapretyanGo.exe .- Важно: Для работы приложения рядом с полученным файлом
zapretyanGo(.exe) обязательно должен находиться файл конфигурации. Скопируйте его из корневой папки/core:
- Перенесите файл
config.tomlв ту же директорию, где теперь лежит ваш скомпилированный файл.
Все доступные плагины и расширения расположены в папке /extensions. Скомпилированные файлы расширений должны располагаться в подпапке extensions, находящейся **в корневом каталоге рядом с основным приложением zapretyanGo**.
Если вы только что завершили компиляцию ядра, вернитесь в корневую папку репозитория
cd ../.. # Возвращаемся в корень папки репозиторияСтруктура каталогов расширений может отличаться, поэтому процесс сборки делится на два типа:
Если внутри папки расширения (например, /extensions/extension1) сразу лежит файл main.go:
- Перейдите в папку расширения:
cd ./extensions/extension1 # Переходим к папке расширения- Скомпилируйте его прямо на месте:
- Linux:
go build -v -trimpath -ldflags="-s -w -buildid=" -o extension1 . - Windows:
go build -v -trimpath -ldflags="-s -w -buildid=" -o extension1.exe .
Если внутри папки расширения находится каталог cmd (путь вида /extensions/extension2/cmd):
- Перейдите в подпапку
cmdэтого расширения из корня папки Zapretyan-Go:
cd ./extensions/extension2/cmd # Переходим к папке расширения- Выполните компиляцию:
- Linux:
go build -v -trimpath -ldflags="-s -w -buildid=" -o extension2 . - Windows:
go build -v -trimpath -ldflags="-s -w -buildid=" -o extension2.exe .
После успешного завершения переместите полученный бинарный файл плагина в общую папку extensions, которая находится рядом с основным ядром zapretyanGo.
После окончания сборки ваша рабочая директория готового приложения должна выглядеть следующим образом:
📁 Zapretyan-Go/
├── 📄 config.toml # Файл конфигурации ядра
├── ⚙️ zapretyanGo (или .exe) # Основной исполняемый файл приложения
└── 📁 extensions/ # Папка с плагинами
├── ⚙️ extension1 (или .exe)
└── ⚙️ extension2 (или .exe)

