Драйвер SMS-шлюза#

Драйвер SMS-шлюза позволяет реализовать пользовательскую логику перед делегированием работы SMS-шлюзу. Например, это может быть полезно, если возникнет потребность маршрутизировать отправки SMS по разным шлюзам в зависимости от кода страны номера телефона.

Примечание

Для отправки уведомлений доступны готовые драйверы, поддерживаемые системой и подробно описанные в разделе Уведомления и отправка сообщений:

  • HTTP — передача сообщений через HTTP-запросы к внешним сервисам;

  • SMPP — отправка SMS-сообщений через SMPP-шлюзы операторов связи;

  • CUSTOM — использование кастомного драйвера.

В данной инструкции описан порядок подключения собственного драйвера для маршрутизации и отправки SMS-сообщений в Blitz Identity Provider.

Шаг 1. Установка драйвера#

  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);
       }
    }
    
  2. Подготовленный класс (или jar-библиотеку) поместите в директорию загрузки расширений extensionsDir (параметр System.getProperty("extensionsDir")). Как правило, это путь:

    ${blitz-root}/jars/<любая-директория>/
    

Шаг 2. Подготовка конфигурации SMS-шлюза#

  1. Для передачи учетных данных и настроек своему драйверу создайте 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
       }
    }
    
  2. Файл конфигурации (например, customGatewayDriver.json) поместите в выделенную директорию SMS-уведомлений. Путь:

    ${blitz-root}/messaging/sms/
    

Шаг 3. Включение драйвера#

Перейдите в консоль управления во вкладку Сообщения, далее в блок Настройка сервиса отправки SMS-сообщений и выберите протокол доставки CUSTOM (см. Уведомления и отправка сообщений).