Драйвер SMS-шлюза#
Драйвер SMS-шлюза позволяет реализовать пользовательскую логику перед делегированием работы SMS-шлюзу. Например, это может быть полезно, если возникнет потребность маршрутизировать отправки SMS по разным шлюзам в зависимости от кода страны номера телефона.
Примечание
Для отправки уведомлений доступны готовые драйверы, поддерживаемые системой и подробно описанные в разделе Уведомления и отправка сообщений:
HTTP— передача сообщений через HTTP-запросы к внешним сервисам;SMPP— отправка SMS-сообщений через SMPP-шлюзы операторов связи;CUSTOM— использование кастомного драйвера.
В данной инструкции описан порядок подключения собственного драйвера для маршрутизации и отправки SMS-сообщений в Blitz Identity Provider.
Шаг 1. Установка драйвера#
Подготовьте Java-процедуру (класс-реализацию интерфейса
SmsGatewayDriver).Пример реализации CustomGatewayDriver.java
package com.identityblitz.idp.extensions.messaging.sms; import com.identityblitz.core.extensions.FutureStage; import com.identityblitz.idp.extensions.types.JsObject; import com.identityblitz.idp.extensions.messaging.sms.SmsGatewayDriver; import com.identityblitz.idp.extensions.messaging.sms.SmsGatewayStatus; import com.identityblitz.idp.extensions.messaging.sms.SmsGatewayContext; import com.identityblitz.idp.extensions.messaging.sms.SmsGatewaySendContext; import com.identityblitz.idp.extensions.messaging.sms.SmsProtocolDriver; import com.identityblitz.idp.extensions.messaging.sms.SmsSendingResult; import com.identityblitz.idp.extensions.messaging.sms.SmsMessageData; import com.identityblitz.idp.extensions.messaging.sms.SmsGatewayProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; @SmsGatewayProvider("customGatewayDriver") public class CustomGatewayDriver implements SmsGatewayDriver { private final AtomicReference<SmsProtocolDriver> europeSenderRef = new AtomicReference<>(); private final AtomicReference<SmsProtocolDriver> eastSenderRef = new AtomicReference<>(); private static final Logger logger = LoggerFactory .getLogger("com.identityblitz.idp.extensions.messaging.sms"); // Список кодов европейских стран private static final Set<String> EUROPEAN_COUNTRY_CODES = Set.of( "+43", "+352", "+32", "+356", "+359", "+31", "+36", "+48", "+49", "+351", "+30", "+40", "+45", "+421", "+353", "+386", "+34", "+358", "+39", "+33", "+357", "+385", "+371", "+420", "+370", "+372", "+46" ); @Override public FutureStage<SmsGatewayStatus> onInit(SmsGatewayContext context, JsObject config) { logger.info("[CustomGatewayDriver] Инициализация драйвера маршрутизации SMS"); if (!config.contains("europeGateway")) { return context.launchStage(() -> SmsGatewayStatus.failed("Not found 'europeGateway' in config")); } if (!config.contains("eastGateway")) { return context.launchStage(() -> SmsGatewayStatus.failed("Not found 'eastGateway' in config")); } try { SmsProtocolDriver europeSender = context.builtinHttpGetDriver(config.asObject("europeGateway")); SmsProtocolDriver eastSender = context.builtinHttpGetDriver(config.asObject("eastGateway")); // Атомарно устанавливаем новые инстансы через set() europeSenderRef.set(europeSender); eastSenderRef.set(eastSender); logger.info("[CustomGatewayDriver] Успешно инициализированы оба шлюза: Europe и East"); } catch (Exception e) { logger.error("[CustomGatewayDriver] Ошибка инициализации драйвера шлюза", e); return context.launchStage(() -> SmsGatewayStatus.failed(e.getMessage())); } return context.launchStage(() -> SmsGatewayStatus.active()); } @Override public FutureStage<SmsGatewayStatus> onConfigChanged(SmsGatewayContext context, JsObject config) { logger.info("[CustomGatewayDriver] Обновление конфигурации — пересоздаём шлюзы"); // Сохраняем старые ссылки для корректного shutdown SmsProtocolDriver oldEurope = europeSenderRef.get(); SmsProtocolDriver oldEast = eastSenderRef.get(); return onInit(context, config).thenCompose(gatewayStatus -> { if (gatewayStatus instanceof SmsGatewayStatus.Failed) { logger.warn("[CustomGatewayDriver] Сбой новой конфигурации, оставляем старые шлюзы"); return context.launchStage(() -> gatewayStatus); } // Безопасно завершаем старые драйверы FutureStage<Void> europeShutdown = (oldEurope != null) ? oldEurope.shutdown() : context.launchStage(() -> null); FutureStage<Void> eastShutdown = (oldEast != null) ? oldEast.shutdown() : context.launchStage(() -> null); return europeShutdown .thenCompose(europeUnit -> eastShutdown.thenApply(eastUnit -> gatewayStatus)); }); } @Override public FutureStage<SmsGatewayStatus> onShutdown(SmsGatewayContext context) { logger.info("[CustomGatewayDriver] Выключение драйвера"); SmsProtocolDriver europe = europeSenderRef.getAndSet(null); SmsProtocolDriver east = eastSenderRef.getAndSet(null); FutureStage<Void> europeShutdown = (europe != null) ? europe.shutdown() : context.launchStage(() -> null); FutureStage<Void> eastShutdown = (east != null) ? east.shutdown() : context.launchStage(() -> null); return europeShutdown .thenCompose(europeUnit -> eastShutdown.thenApply(eastUnit -> SmsGatewayStatus.active())); } @Override public FutureStage<SmsSendingResult> send(SmsGatewaySendContext context, SmsMessageData message) { String mobile = message.getPhoneNumber(); //Предполагаем, что номера телефонов сохранены в хранилище в международном формате (+{country_code}) //Иначе необходимо добавить логику нормализации номера телефона boolean isEuropean = EUROPEAN_COUNTRY_CODES.stream().anyMatch(mobile::startsWith); SmsProtocolDriver targetDriver = isEuropean ? europeSenderRef.get() : eastSenderRef.get(); String driverName = isEuropean ? "europeGateway" : "eastGateway"; if (targetDriver == null) { logger.error("[CustomGatewayDriver] Ошибка маршрутизации: {} не инициализирован (null)", driverName); return context.launchStage(() -> { throw new IllegalStateException("Protocol driver failed: " + driverName + " is null"); }); } logger.debug("[CustomGatewayDriver] Отправка SMS для номера {} через {}", mobile, driverName); return targetDriver.send(message); } }
Подготовленный класс (или jar-библиотеку) поместите в директорию загрузки расширений
extensionsDir(параметрSystem.getProperty("extensionsDir")). Как правило, это путь:${blitz-root}/jars/<любая-директория>/
Шаг 2. Подготовка конфигурации SMS-шлюза#
Для передачи учетных данных и настроек своему драйверу создайте JSON-файл конфигурации.
Внимание
Название файла должно точно совпадать с именем драйвера, объявленным в коде через аннотацию
@SmsGatewayProvider("...").Пример конфигурации customGatewayDriver.json
{ "europeGateway" : { "errRegExp" : "^ERROR.+$", "headers" : [], "login" : "admin_multigateway", "okIdRegExp" : "\"send_id\"\\s*:\\s*[\"]([^\"]+)[\"]", "okRegExp" : "OK.*$", "password" : "{$}G13bBQyO6ClliPqGaiysFtKNfCEIqtiRalzdHl5AeNnmojyflP8oGw==", "type" : "http-get", "url" : "http://127.0.0.1:5000/sms?login=${login}&psw=${password}&phones=${mobile}&mes=${message}&processid=${processId}&sessionid=${sessionId}", "useBasicAuth" : false }, "eastGateway" : { "errRegExp" : "^ERROR.+$", "headers" : [], "login" : "admin_multigateway", "okIdRegExp" : "\"send_id\"\\s*:\\s*[\"]([^\"]+)[\"]", "okRegExp" : "OK.*$", "password" : "my_password", "type" : "http-get", "url" : "http://127.0.0.1:5000/sms?login=${login}&psw=${password}&phones=${mobile}&mes=${message}&processid=${processId}&sessionid=${sessionId}", "useBasicAuth" : false } }
Файл конфигурации (например,
customGatewayDriver.json) поместите в выделенную директорию SMS-уведомлений. Путь:${blitz-root}/messaging/sms/
Шаг 3. Включение драйвера#
Перейдите в консоль управления во вкладку Сообщения, далее в блок Настройка сервиса отправки SMS-сообщений и
выберите протокол доставки CUSTOM (см. Уведомления и отправка сообщений).