v/1.12.0

Платформа

  • Агрегирующие запросы к коллекциям (параметр aggr): добавлена функция count_distinct — количество различных значений в группе, например уникальных сущностей по дням.

  • Статические файлы веб-сервера (справка, админка, ресурсы ролевых приложений) поддерживают HTTP Range: работает перемотка аудио и видео.

  • Исправлены HEAD-запросы к REST: публичные ресурсы отвечали 401, /public/version — 405.

  • SIP по WebSocket (ws/wss): поддержан CRLF-keepalive; раньше соединение закрывалось.

  • SIP по WebSocket (ws/wss) и мобильные устройства:

    • закрытие прежнего соединения устройства, переподключившегося с тем же +sip.instance и reg-id, больше не снимает его новую регистрацию;

    • SG проверяет подключения WebSocket ping (параметр роли sg ws_ping_interval, по умолчанию 25 секунд): устройство, пропавшее без разрыва соединения, снимается за 50—​75 секунд вместо трех минут;

    • вызов на потерянное подключение сразу уходит на другое подключение устройства, а без него вызывающий получает 480 вместо 503 (для переадресации — условие dnd);

    • резервный вызов устройства с несколькими подключениями начинается через 2 секунды и при одинаковом Contact; раньше — 408 через 30 секунд;

    • устройство, переподключившееся во время входящего звонка, получает отмену вызова в новое подключение, а UPDATE без SDP отвечается 481, если вызов уже отменен;

    • мобильное приложение с push-уведомлениями, чье подключение живо, но не отвечает: через 2 секунды устройство будится push-уведомлением и получает вызов через новое подключение; раньше — 408 через 30 секунд;

    • отказ пользователя (486, 6xx) на одном подключении устройства сразу завершает вызов на этом устройстве; другие устройства пользователя продолжают звонить.

  • BYE вызывающего до ответа (после 180/183) отменяет вызов так же, как CANCEL; раньше — 481, и вызов продолжался.

  • ESG: запросы внутри диалога до ACK ставятся в очередь, как в B2B, и последовательно обрабатываются при завершении всех подготовительных состояний.

  • Подписки мастер-домена на класс событий callevents или confevents (либо отдельное событие класса) с objects any получают события всех доменов платформы: слушатель всех событий телефонии через websocket Token-API. Подписка мастер-домена на эти классы с объектами отклоняется.

  • SG, ESG, redirect и WS начинают принимать запросы на адресах из настроек sip_ifaces, http_ifaces, https_ifaces, появившихся на сервере после запуска роли, в течение 30 секунд; раньше требовался перезапуск узла.

  • Компоненты сценариев «Синтез речи (Yandex Cloud SpeechKit)» и «Распознавание речи (Yandex Cloud SpeechKit)» переведены на API v3 (gRPC). Распознавание выполняется потоково по мере записи, синтез воспроизводится, не дожидаясь окончания. Добавлены новые голоса и амплуа синтеза, громкость, высота голоса, кэширование; для распознавания — нормализация и литературное оформление текста, режим одной фразы, настройки определения конца фразы, текст без нормализации в отдельную переменную. Настройки существующих сценариев применяются без изменений: голос Alyss заменяется на Dasha, неподдерживаемые голосом эмоции не передаются, темы maps, dates, names, numbers заменяются на general. В настройке домена yandex_cloud адреса сервисов задаются полями grpc_tts, grpc_stt; поля uri_tts, uri_asr_short больше не используются.

  • Медиашлюз: доработан механизм переключения отправки на другой сокет при смене входящего потока.

  • Внешние хосты веб-сервера (ws/ExternalRoutedHosts): режим archive_referers записи или маршрута сохраняет переходы клиентов (IP, URL, utm-метки, Referer, User-Agent) в новую коллекцию ws/ArchiveReferers. По умолчанию выключен.

  • Проксирование внешних хостов веб-сервера (ws/ExternalRoutedHosts): исправлена передача cookie; cookie и токен сессии платформы на сервер назначения не передаются.

  • Бот администраторов заменяет Telegram-бот мониторинга:

    • работает в Telegram, MAX и VK через учетные записи мессенджеров мастер-домена; используются только мессенджеры с проверкой подлинности входящих сообщений;

    • администратор подключает чат одноразовым кодом, подтверждая его в приложении администрирования; пароль в мессенджер не передается;

    • каждый администратор может исключить разделы состояния системы из уведомлений и выбрать язык сообщений (команда /lang);

    • файл состояния отправляется при появлении и изменении проблем, при неизменных проблемах — напоминание; время ежедневного отчета настраивается;

    • команды с параметрами можно выбирать из меню мессенджера;

    • бот и подключенные администраторы прежнего Telegram-бота переносятся автоматически, в том числе с версий до 1.10; параметры system_telegram_bot и telegram_bot_token заменены на admin_imi_options.

  • Каналы мессенджеров (uc/imchannels) доступны и в мастер-домене.

  • Сообщения мессенджеров (im/Messages): опции отправки sendOptions (disable_notification, parse_mode) учитываются в Telegram.

  • Исправлено: классы служебных коллекций system/audit/RestrictedLogons, system/licensing/Indicators и telephony/ArchiveDialogs пересоздавались при изменении классов домена и при запуске серверов.

  • Коллекции с хранением transactionlog (Kafka + ClickHouse):

    • дата-время хранится в UTC с миллисекундами, как в PostgreSQL; чтение и фильтры по интервалу не зависят от часового пояса сервера ClickHouse. Таблицы, созданные ранее, преобразуются при загрузке класса: поле партиции сохраняет точность до секунды;

    • незаданные поля типов uuid и enum возвращаются отсутствующими, а не нулевым идентификатором и пустой строкой;

    • логин и пароль ClickHouse передаются в заголовках запроса: пароль может содержать любые символы.

  • Секреты в настройках домена шифруются при сохранении и не возвращаются в открытом виде: ключи и секреты yandex_cloud, sber_salute, azure_cloud (в том числе в accounts) и серверов record_asr_options, пароль в project_postgresql_connstr. Ранее сохраненные значения шифруются при следующем изменении настройки. Сценарии, читающие эти значения через системные переменные domain.settings, получают их в зашифрованном виде: параметры подключения сценарий задает самостоятельно.

  • Хранилища типа s3 (/rest/v1/domain/storages): секретный ключ secretKey шифруется при сохранении и не возвращается в открытом виде; ранее сохраненные ключи шифруются при следующем изменении хранилища.

  • Сборка trn-логов и диаграмма последовательности звонка (/api/monitor/v1/trace):

    • доступны и после очистки кэша связей (около 3 часов): связи звонка берутся из журналов callid микросервисов (глубина — параметр days), уже удаленные с нод журналы — из logstore при свободных ресурсах (параметр logstore);

    • порядок стрелок соответствует порядку событий: ответ не показывается раньше запроса, расхождение часов микросервисов учитывается;

    • сборка меньше нагружает микросервисы; параметр time (время звонка) сокращает ее еще.

  • Состояние системы: сравнение файлов платформы на серверах (version_files_diffs, version_all_files_diffs, уровни 1–3) выполняется за доли секунды вместо десятков секунд — сравниваются размер и время изменения файлов, каталоги резервных копий и сборки не учитываются; на односерверной системе сравнение не выполняется.

  • Кодеки в SDP инициируемых вызовов (параметр payloads_audio_offer ролей b2b, conf, esg, ivr, prompt, sg, а также payloads_video_offer) предлагаются в порядке списка; базовые PCMU, PCMA и telephone-event, не указанные в списке, добавляются после указанных. Префикс - исключает кодек из добавляемых (- — все неуказанные базовые), -- — также из SDP входящего вызова, передаваемого на другое плечо (с -- — в порядке списка). CN и telephone-event размещаются в конце. Подробнее — статья Кодеки и согласование медиа.

  • У провайдера (opts.payloads_audio) telephone-event можно исключить: -telephone-event/8000 или -*.

  • Список кодеков провайдера (opts.payloads_audio) применяется только на плече провайдера: внутренние плечи им не ограничиваются (при необходимости транскодинг), предложение внутрь платформы содержит кодеки провайдера из списка в порядке провайдера. Без списка при reinvite = 0 предложение провайдера передается внутрь с его кодеками, без дополнения по payloads_audio_offer esg. Если в SDP провайдера (в том числе в re-INVITE и INVITE с Replaces) нет кодека из списка или нет ни одного известного платформе кодека, esg отвечает 488 Not Acceptable Here вместо 415.

  • Исправлено: esg при reinvite = 0 отвечал на re-INVITE и INVITE с Replaces кодеками, которых не было в предложении. Теперь ответ содержит только кодеки предложения, при отсутствии общих — 488 Not Acceptable Here (re-INVITE отклоняется без разрыва вызова).

  • Исправлено: при пересылке re-INVITE через esg без транскодинга в предложении и ответе оставались кодеки, убранные новым предложением.

  • Имена кодеков в параметрах и у провайдера указываются без учета регистра.

  • Ответ SDP содержит динамические форматы (например, telephone-event) под номерами из предложения (RFC 3264). Если стороны вызова объявили для одного кодека разные номера, медиашлюз сопоставляет их по имени кодека.

  • Провайдер: G723/8000 в opts.payloads_audio не поддерживается — при добавлении ошибка, ранее сохраненное значение отбрасывается.

  • Серверы записи: при заданном audio_formats предлагаются ровно указанные кодеки в порядке списка.

  • BREAKING CHANGE. Если payloads_audio_offer не задан (у любой роли, в том числе esg и sg), G729 больше не предлагается: добавьте G729/8000 в параметр, если он нужен. Порядок кодеков в SDP может измениться: теперь он определяется порядком в конфигурации, а не прежним постоянным порядком платформы (например, [PCMA, PCMU, G722, CN] дает PCMA первым вместо PCMU).

  • Служебные задачи (service/svctasks): поля dtstart и dtstop необязательны — незаданное значение не ограничивает период активности. Регулярная задача без них выполняется по расписанию, однократная — сразу после включения. Раньше подставлялось текущее время, и задача, созданная без этих полей, не запускалась. Даты существующих задач не меняются.

  • Исправлено: подстановка {A} в модификаторе отображаемого имени SIP-пользователя (displayname контакта адресной книги по номеру) всегда давала пустую строку.

  • Исправлено: синхронизация данных между системами (ETL, режим выживания) не переносила контакты адресной книги.

  • Сервис телефонных оповещений (alertcall) снова включён. Изменения оповещений применяются сразу по уведомлениям, без постоянного опроса; исправлено сохранение статуса и статистики оповещения (запись отклонялась).

Рефакторинг

  • Подключен статический анализатор кода, позволивший обнаружить и устранить ряд замечаний:

    • BREAKING CHANGE. Агрегирующая функция join (параметр aggr) теперь принимает разделитель первым аргументом, как функция общего назначения join и как указано в справке: ["join",", ",["property","name"]]. Запросы с прежним порядком аргументов нужно исправить. В PostgreSQL-коллекциях join соединяет и нестроковые значения.

    • BREAKING CHANGE. Имя класса динамической модели данных при создании и переименовании должно содержать раздел (section/name); имена без раздела зарезервированы за статической моделью. Существующие классы не затрагиваются.

    • BREAKING CHANGE. REST домена (/rest/v1/domain/domains): поле solution больше не возвращается и не принимается; удалён /rest/v1/domain/solutions.

    • BREAKING CHANGE. Правила IAM с режимом authenticated снова требуют аутентификации: REST-запрос без сессии к таким маршрутам получает 401.

    • BREAKING CHANGE. Событие приложения веб-конструктора по websocket (send_app_event) проверяет роли пользователя так же, как HTTP-доступ к приложению; без подходящей роли — ошибка «Invalid app name. Role mismatch».

    • BREAKING CHANGE. Функции даты в сценариях (year, month, day, hour, minute, second, millisecond, dayofyear, dayofweek, weekofyear, tick, datetimeutc, datetimelocal, localtoutc, utctolocal) при невалидной дате завершают выполнение ошибкой «Invalid datetime» вместо подстановки 2000-01-01; valid_date для невалидной даты возвращает false. Явно записанная дата 1970-01-01 с нулевым временем валидна.

    • BREAKING CHANGE. Вложенность eval в сценариях ограничена 16 уровнями (ошибка «eval: nesting is too deep»).

    • BREAKING CHANGE. Копирование сценария («Сохранить как» и ext.copied_from): принимается только идентификатор существующего сценария того же типа.

    • BREAKING CHANGE. SIP-пользователь без регистрации (reg=false): число устройств (devices) при создании и изменении не может превышать установленное для него значение lic.devices (проверка раньше не срабатывала). Сохранённые объекты загружаются как прежде.

    • BREAKING CHANGE. Неявный вызов из конференции в конференцию блокируется (проверка раньше не срабатывала).

    • BREAKING CHANGE. Получение почты по IMAP: параметр ssl учитывается (по умолчанию true; порт 993 — всегда TLS); раньше соединение всегда устанавливалось через TLS.

    • B2B: INFO без DTMF пересылается на другую сторону как SIP INFO (было 408).

    • ESG: исправлена передача X-Era-Extaccount с urlencode для значений, позволяющей избегать спецсимволов в коде провайдеров.

    • Добавлены операции info и message в /rest/v1/uc/sipusers/<id>/device; в справке описаны resync, event, headers, content.

    • Подписка (BLF) на внешние номера из настройки blf_external_numbers и chief_mobile комплекта руководителя работает; раньше отклонялась.

    • Обнаружены и исправлены несколько уязвимостей при работе с файлами через API авторизованных пользователей: временные файлы websocket-сессии (имена файла и подкаталога ограничены папкой сессии); файловые API (выход за пределы каталога через .. и символические ссылки); системный API приложений ролей (обход url_mask дважды закодированными сегментами).

    • Исправлено удаление папки в файловом хранилище (REST fs): без заданного корня могли удаляться пустые каталоги выше корня.

    • Исправлены ответы API, которые давали 500 или обрыв: список сессий при неответившем домене; запрос коллекции DC по полю для пустой коллекции; остановка сценария при недоступном узле сценариев; rest по websocket с classpath не коллекции; на неизвестную команду привязок и переключение конференции в недопустимом состоянии — ошибка сразу, а не таймаут.

    • Вход через служебный сценарий аутентификации (по паролю или токену) работает при любой форме результата сценария; раньше в части случаев вход завершался внутренней ошибкой.

    • Вызов серверной части приложения полки (служебного сценария приложения) через HTTP /api/roleapp/v1/<appkey> работает; раньше запрос всегда завершался ошибкой.

    • Исправлена доставка части событий по websocket-подпискам и подписка на события модели (modelevents) с коротким путём класса.

    • Функции сценариев dc_read и dc_find по полю id находят объекты и тех классов, где ключ записи не id (пользователи, группы, роли и т.п.); раньше возвращался пустой результат.

    • Установка и обновление продукта не прерываются ошибкой, если какой-либо объект домена обновился с предупреждениями.

    • Проксирование websocket учитывает порт из адреса назначения host:port.

    • SIP: исправлены уведомления о присутствии (PIDF), в том числе для BLF телефонов Cisco (cpim-pidf+xml); REGISTER без Contact через SG получает 200; SUBSCRIBE с Expires 1..29 — 423 Interval Too Brief; на внешнее направление — ошибка маршрута вместо 500.

    • B2B: исправлены reinvite и завершение диалога при ошибке миграции медиа; недоступный доменный центр не обрывает звонок при проверке переадресаций; REFER продолжает маршрутизацию при недоступном удалённом B2BUA; INVITE+Replaces на внешнее направление при ошибке маршрута возвращает 403.

    • ESG: сценарий нормализации без переменных или прерванный не задерживает вызов на 10 с; исправлен биллинг RADIUS при сервере без порта.

    • SG, взаимная супервизия экземпляров (режим reregister): при падении экземпляра SG зарегистрированным через него устройствам снова отправляется команда на внеплановую перерегистрацию; раньше после сбоя служебного процесса режим мог перестать работать до перезапуска узла.

    • IVR: исправлены Replaces в состоянии ringing и до ответа (заменённый INVITE отвечается 487); несовпадение режима медиа при REFER возвращается в сценарий как operation_failed.

    • Музыка на удержании: при отсутствующем или неверном music_on_hold играет мелодия по умолчанию.

    • Ошибки создания каталогов, копирования и удаления файлов (хранилище NFS, микшер, временные файлы) больше не выдаются за успех: например, при сбое копирования записи разговора её скачивание возвращает ошибку, а не пустой файл.

    • Сценарии: исправлены компоненты сценариев в части толерантности к некорректным значениям, влекущим прерывание работы компонента и завершение сценария.

    • Сценарии: компонент LDAP теперь поддерживает многострочные фильтры и not(…​), компонент получения почты декодирует заголовки =?charset?…​?=.

    • Исправлено скачивание файла из свойств типа filelink в multi=true в коллекциях динамической модели данных.

    • Запросы к коллекции динамической модели данных, пришедшие во время загрузки ее класса, выполняются после загрузки; раньше при нескольких таких запросах часть завершалась по таймауту.

    • Диаграмма звонка по логам версий до 1.9.7: сообщение без адреса не делает диаграмму ошибочной.

    • Журнал диалогов (СОРМ3/ArchiveDialogs): событиям ставится реальная дата вместо 1970-01-01.

    • Kafka для generic-событий: работают режимы разбиения по партициям random и random_by_key.

    • ACME для автоматической генерации сертификатов: неудачная подготовка повторяется через 10 с; исправлено восстановление сертификатов из резервной копии.

    • Сервис распределения учетных записей провайдеров телефонии по экземплярам ESG теперь учитывает конфигурационную опцию excludedomains ESG.

    • Резервный режим (survival): исправлена проверка токена при нескольких адресах.

    • Событие CCS connection_failure содержит sipcode и reason.

    • Голосовая почта: исправлена отметка сообщения прослушанным через REST.

    • Голосовая почта: ночная очистка больше не падает на пустом каталоге, ранее писала в лог.

    • Получение почты по IMAP: закрытие соединения почтовым сервером не роняет компонент сценария, ранее была способна обрушить сценарий.

    • Исправлен выбор ведущего сайта в межсайтовом кворуме при разделении сети.

    • Исправлена уязвимость редактора сценариев: операции с вложенными файлами сценария принимают только имя файла, без пути.

    • Событие statesevents.user_state_changed доставляется в подписки (веб-хуки, websocket, Kafka) корректным JSON с полем presence; раньше приходило как invalid_data.

    • Веб-хуки: подписка с объектами вида {"type": "sipuser", "sipuser": "sip1"} снова фильтрует события (с 1.11.0 события по таким подпискам не приходили), поддержаны также типы other, conf, provider, user; подписка на modelevents через веб-хуки отклоняется — для них используется websocket; в ответе GET поле expires — оставшееся время подписки в секундах.

    • Websocket: ответы с ошибкой, содержащей детали (например, неверный пароль при login), снова приходят с кодом и error_details (с 1.11.0 возвращалась внутренняя ошибка 1501).

    • Websocket: login по ненайденной или истёкшей сессии (sessionid, rsessionid) без логина и пароля возвращает ошибку «Session not found or expired.» (msg_code 10025) вместо требования домена.

    • Подписки веб-хуков (/rest/v1/service/webhooks): expires больше 86400 уменьшается до 86400; применённое значение возвращается в ответе в поле expires и определяет срок продления.

    • Подписки на события модели: строковая маска (exargs.mask) совместно с политикой безопасности класса не приводит к ошибке подписки; формат веб-хуков ext.http_notify_format применяется и для /api/token/v1/<token>/subscribe, неизвестное значение формата — JSON-тело.

    • Коллекции динамической модели с хранением ets: новые классы снова запускаются (с 1.10.5 класс не загружался, запросы получали «DataModel server is not loaded»); постраничное snapshot-чтение возвращает страницы в порядке сортировки и не смешивает выборки с разными фильтрами.